diff options
author | Feng Qian <fqian@google.com> | 2009-06-18 18:20:56 -0700 |
---|---|---|
committer | Feng Qian <fqian@google.com> | 2009-06-18 18:20:56 -0700 |
commit | 1edef79f87f9c52c21d69c87c19f8e2b140a9119 (patch) | |
tree | cad337ef493b0d9710bf3ae478cb87cb534f598d /WebCore/platform | |
parent | b83fc086000e27bc227580bd0e35b9d7bee1179a (diff) | |
parent | c9c4d65c1547996ed3748026904d6e7f09aec2b4 (diff) | |
download | external_webkit-1edef79f87f9c52c21d69c87c19f8e2b140a9119.zip external_webkit-1edef79f87f9c52c21d69c87c19f8e2b140a9119.tar.gz external_webkit-1edef79f87f9c52c21d69c87c19f8e2b140a9119.tar.bz2 |
Merge commit 'goog/master-webkit-merge' into webkit-merge-44544
Diffstat (limited to 'WebCore/platform')
373 files changed, 7903 insertions, 3915 deletions
diff --git a/WebCore/platform/ContextMenu.cpp b/WebCore/platform/ContextMenu.cpp index f66a891..362e334 100644 --- a/WebCore/platform/ContextMenu.cpp +++ b/WebCore/platform/ContextMenu.cpp @@ -112,11 +112,21 @@ static void createAndAppendSpellingAndGrammarSubMenu(const HitTestResult& result contextMenuItemTagCheckSpellingWhileTyping()); ContextMenuItem grammarWithSpelling(CheckableActionType, ContextMenuItemTagCheckGrammarWithSpelling, contextMenuItemTagCheckGrammarWithSpelling()); +#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + ContextMenuItem correctSpelling(CheckableActionType, ContextMenuItemTagCorrectSpellingAutomatically, + contextMenuItemTagCorrectSpellingAutomatically()); +#endif spellingAndGrammarMenu.appendItem(showSpellingPanel); spellingAndGrammarMenu.appendItem(checkSpelling); +#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + spellingAndGrammarMenu.appendItem(*separatorItem()); +#endif spellingAndGrammarMenu.appendItem(checkAsYouType); spellingAndGrammarMenu.appendItem(grammarWithSpelling); +#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + spellingAndGrammarMenu.appendItem(correctSpelling); +#endif spellingAndGrammarMenuItem.setSubMenu(&spellingAndGrammarMenu); } @@ -189,6 +199,45 @@ static void createAndAppendTextDirectionSubMenu(const HitTestResult& result, Con } #endif +#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +static void createAndAppendSubstitutionsSubMenu(const HitTestResult& result, ContextMenuItem& substitutionsMenuItem) +{ + ContextMenu substitutionsMenu(result); + + ContextMenuItem showSubstitutions(ActionType, ContextMenuItemTagShowSubstitutions, contextMenuItemTagShowSubstitutions(true)); + ContextMenuItem smartCopyPaste(CheckableActionType, ContextMenuItemTagSmartCopyPaste, contextMenuItemTagSmartCopyPaste()); + ContextMenuItem smartQuotes(CheckableActionType, ContextMenuItemTagSmartQuotes, contextMenuItemTagSmartQuotes()); + ContextMenuItem smartDashes(CheckableActionType, ContextMenuItemTagSmartDashes, contextMenuItemTagSmartDashes()); + ContextMenuItem smartLinks(CheckableActionType, ContextMenuItemTagSmartLinks, contextMenuItemTagSmartLinks()); + ContextMenuItem textReplacement(CheckableActionType, ContextMenuItemTagTextReplacement, contextMenuItemTagTextReplacement()); + + substitutionsMenu.appendItem(showSubstitutions); + substitutionsMenu.appendItem(*separatorItem()); + substitutionsMenu.appendItem(smartCopyPaste); + substitutionsMenu.appendItem(smartQuotes); + substitutionsMenu.appendItem(smartDashes); + substitutionsMenu.appendItem(smartLinks); + substitutionsMenu.appendItem(textReplacement); + + substitutionsMenuItem.setSubMenu(&substitutionsMenu); +} + +static void createAndAppendTransformationsSubMenu(const HitTestResult& result, ContextMenuItem& transformationsMenuItem) +{ + ContextMenu transformationsMenu(result); + + ContextMenuItem makeUpperCase(ActionType, ContextMenuItemTagMakeUpperCase, contextMenuItemTagMakeUpperCase()); + ContextMenuItem makeLowerCase(ActionType, ContextMenuItemTagMakeLowerCase, contextMenuItemTagMakeLowerCase()); + ContextMenuItem capitalize(ActionType, ContextMenuItemTagCapitalize, contextMenuItemTagCapitalize()); + + transformationsMenu.appendItem(makeUpperCase); + transformationsMenu.appendItem(makeLowerCase); + transformationsMenu.appendItem(capitalize); + + transformationsMenuItem.setSubMenu(&transformationsMenu); +} +#endif + static bool selectionContainsPossibleWord(Frame* frame) { // Current algorithm: look for a character that's not just a separator. @@ -357,6 +406,16 @@ void ContextMenu::populate() } else appendItem(IgnoreGrammarItem); appendItem(*separatorItem()); +#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + } else { + // If the string was autocorrected, generate a contextual menu item allowing it to be changed back. + String replacedString = result.replacedString(); + if (!replacedString.isEmpty()) { + ContextMenuItem item(ActionType, ContextMenuItemTagChangeBack, contextMenuItemTagChangeBack(replacedString)); + appendItem(item); + appendItem(*separatorItem()); + } +#endif } } @@ -407,6 +466,16 @@ void ContextMenu::populate() createAndAppendSpellingSubMenu(m_hitTestResult, SpellingMenuItem); appendItem(SpellingMenuItem); #endif +#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + ContextMenuItem substitutionsMenuItem(SubmenuType, ContextMenuItemTagSubstitutionsMenu, + contextMenuItemTagSubstitutionsMenu()); + createAndAppendSubstitutionsSubMenu(m_hitTestResult, substitutionsMenuItem); + appendItem(substitutionsMenuItem); + ContextMenuItem transformationsMenuItem(SubmenuType, ContextMenuItemTagTransformationsMenu, + contextMenuItemTagTransformationsMenu()); + createAndAppendTransformationsSubMenu(m_hitTestResult, transformationsMenuItem); + appendItem(transformationsMenuItem); +#endif ContextMenuItem FontMenuItem(SubmenuType, ContextMenuItemTagFontMenu, contextMenuItemTagFontMenu()); createAndAppendFontSubMenu(m_hitTestResult, FontMenuItem); @@ -584,6 +653,56 @@ void ContextMenu::checkOrEnableIfNeeded(ContextMenuItem& item) const case ContextMenuItemTagCheckSpellingWhileTyping: shouldCheck = frame->editor()->isContinuousSpellCheckingEnabled(); break; +#if PLATFORM(MAC) + case ContextMenuItemTagSubstitutionsMenu: + case ContextMenuItemTagTransformationsMenu: + break; + case ContextMenuItemTagShowSubstitutions: +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + if (frame->editor()->substitutionsPanelIsShowing()) + item.setTitle(contextMenuItemTagShowSubstitutions(false)); + else + item.setTitle(contextMenuItemTagShowSubstitutions(true)); + shouldEnable = frame->editor()->canEdit(); +#endif + break; + case ContextMenuItemTagMakeUpperCase: + case ContextMenuItemTagMakeLowerCase: + case ContextMenuItemTagCapitalize: + case ContextMenuItemTagChangeBack: + shouldEnable = frame->editor()->canEdit(); + break; + case ContextMenuItemTagCorrectSpellingAutomatically: +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + shouldCheck = frame->editor()->isAutomaticSpellingCorrectionEnabled(); +#endif + break; + case ContextMenuItemTagSmartCopyPaste: +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + shouldCheck = frame->editor()->smartInsertDeleteEnabled(); +#endif + break; + case ContextMenuItemTagSmartQuotes: +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + shouldCheck = frame->editor()->isAutomaticQuoteSubstitutionEnabled(); +#endif + break; + case ContextMenuItemTagSmartDashes: +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + shouldCheck = frame->editor()->isAutomaticDashSubstitutionEnabled(); +#endif + break; + case ContextMenuItemTagSmartLinks: +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + shouldCheck = frame->editor()->isAutomaticLinkDetectionEnabled(); +#endif + break; + case ContextMenuItemTagTextReplacement: +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + shouldCheck = frame->editor()->isAutomaticTextReplacementEnabled(); +#endif + break; +#endif #if PLATFORM(GTK) case ContextMenuItemTagGoBack: shouldEnable = frame->loader()->canGoBackOrForward(-1); diff --git a/WebCore/platform/ContextMenu.h b/WebCore/platform/ContextMenu.h index 9418ff5..75899ba 100644 --- a/WebCore/platform/ContextMenu.h +++ b/WebCore/platform/ContextMenu.h @@ -39,7 +39,6 @@ #endif namespace WebCore { -class MenuEventProxy; class ContextMenuController; diff --git a/WebCore/platform/ContextMenuItem.h b/WebCore/platform/ContextMenuItem.h index 52c4d1b..3a4cdfa 100644 --- a/WebCore/platform/ContextMenuItem.h +++ b/WebCore/platform/ContextMenuItem.h @@ -124,6 +124,21 @@ namespace WebCore { ContextMenuItemTagTextDirectionDefault, ContextMenuItemTagTextDirectionLeftToRight, ContextMenuItemTagTextDirectionRightToLeft, +#if PLATFORM(MAC) + ContextMenuItemTagCorrectSpellingAutomatically, + ContextMenuItemTagSubstitutionsMenu, + ContextMenuItemTagShowSubstitutions, + ContextMenuItemTagSmartCopyPaste, + ContextMenuItemTagSmartQuotes, + ContextMenuItemTagSmartDashes, + ContextMenuItemTagSmartLinks, + ContextMenuItemTagTextReplacement, + ContextMenuItemTagTransformationsMenu, + ContextMenuItemTagMakeUpperCase, + ContextMenuItemTagMakeLowerCase, + ContextMenuItemTagCapitalize, + ContextMenuItemTagChangeBack, +#endif ContextMenuItemBaseApplicationTag = 10000 }; diff --git a/WebCore/platform/CookieJar.h b/WebCore/platform/CookieJar.h index 178ee79..6159386 100644 --- a/WebCore/platform/CookieJar.h +++ b/WebCore/platform/CookieJar.h @@ -33,7 +33,7 @@ namespace WebCore { class Document; String cookies(const Document*, const KURL&); - void setCookies(Document*, const KURL&, const KURL& policyBaseURL, const String&); + void setCookies(Document*, const KURL&, const String&); bool cookiesEnabled(const Document*); } diff --git a/WebCore/platform/Cursor.h b/WebCore/platform/Cursor.h index 3ab694c..ea75191 100644 --- a/WebCore/platform/Cursor.h +++ b/WebCore/platform/Cursor.h @@ -70,18 +70,25 @@ namespace WebCore { HCURSOR m_nativeCursor; }; typedef RefPtr<SharedCursor> PlatformCursor; + typedef HCURSOR PlatformCursorHandle; #elif PLATFORM(MAC) typedef NSCursor* PlatformCursor; + typedef NSCursor* PlatformCursorHandle; #elif PLATFORM(GTK) typedef GdkCursor* PlatformCursor; + typedef GdkCursor* PlatformCursorHandle; #elif PLATFORM(QT) && !defined(QT_NO_CURSOR) typedef QCursor PlatformCursor; + typedef QCursor* PlatformCursorHandle; #elif PLATFORM(WX) typedef wxCursor* PlatformCursor; + typedef wxCursor* PlatformCursorHandle; #elif PLATFORM(CHROMIUM) // See PlatformCursor.h + typedef void* PlatformCursorHandle; #else typedef void* PlatformCursor; + typedef void* PlatformCursorHandle; #endif class Cursor { diff --git a/WebCore/platform/FileSystem.h b/WebCore/platform/FileSystem.h index 8ccefab..16afe8f 100644 --- a/WebCore/platform/FileSystem.h +++ b/WebCore/platform/FileSystem.h @@ -39,11 +39,10 @@ #if defined(Q_OS_WIN32) #include <windows.h> #endif -#endif - -#if PLATFORM(DARWIN) +#if defined(Q_WS_MAC) #include <CoreFoundation/CFBundle.h> #endif +#endif #include <time.h> diff --git a/WebCore/platform/HostWindow.h b/WebCore/platform/HostWindow.h index 7007ac5..3e982e1 100644 --- a/WebCore/platform/HostWindow.h +++ b/WebCore/platform/HostWindow.h @@ -27,18 +27,13 @@ #define HostWindow_h #include <wtf/Noncopyable.h> -#include "IntRect.h" #include "Widget.h" namespace WebCore { -class IntPoint; -class IntRect; - class HostWindow : Noncopyable { public: - HostWindow() {} - virtual ~HostWindow() {} + virtual ~HostWindow() { } // The repaint method asks the host window to repaint a rect in the window's coordinate space. The // contentChanged boolean indicates whether or not the Web page content actually changed (or if a repaint diff --git a/WebCore/platform/KURL.cpp b/WebCore/platform/KURL.cpp index 6901782..4b75046 100644 --- a/WebCore/platform/KURL.cpp +++ b/WebCore/platform/KURL.cpp @@ -310,8 +310,6 @@ KURL::KURL(const char* url) KURL::KURL(const String& url) { - checkEncodedString(url); - parse(url); ASSERT(url == m_string); } @@ -343,7 +341,7 @@ void KURL::init(const KURL& base, const String& relative, const TextEncoding& en // For compatibility with Win IE, treat backslashes as if they were slashes, // as long as we're not dealing with javascript: or data: URLs. String rel = relative; - if (rel.contains('\\') && !(protocolIs(rel, "javascript") || protocolIs(rel, "data"))) + if (rel.contains('\\') && !(protocolIsJavaScript(rel) || protocolIs(rel, "data"))) rel = substituteBackslashes(rel); String* originalString = &rel; @@ -631,10 +629,16 @@ static void assertProtocolIsGood(const char* protocol) bool KURL::protocolIs(const char* protocol) const { - // Do the comparison without making a new string object. assertProtocolIsGood(protocol); + + // 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); + if (!m_isValid) return false; + + // Do the comparison without making a new string object. for (int i = 0; i < m_schemeEnd; ++i) { if (!protocol[i] || toASCIILower(m_string[i]) != protocol[i]) return false; @@ -1549,7 +1553,7 @@ static void encodeRelativeString(const String& rel, const TextEncoding& encoding TextEncoding pathEncoding(UTF8Encoding()); // Path is always encoded as UTF-8; other parts may depend on the scheme. int pathEnd = -1; - if (encoding != pathEncoding && encoding.isValid() && !protocolIs(rel, "mailto") && !protocolIs(rel, "data") && !protocolIs(rel, "javascript")) { + if (encoding != pathEncoding && encoding.isValid() && !protocolIs(rel, "mailto") && !protocolIs(rel, "data") && !protocolIsJavaScript(rel)) { // Find the first instance of either # or ?, keep pathEnd at -1 otherwise. pathEnd = findFirstOf(s.data(), s.size(), 0, "#?"); } @@ -1615,6 +1619,11 @@ bool protocolIs(const String& url, const char* protocol) } } +bool protocolIsJavaScript(const String& url) +{ + return protocolIs(url, "javascript"); +} + String mimeTypeFromDataURL(const String& url) { ASSERT(protocolIs(url, "data")); diff --git a/WebCore/platform/KURL.h b/WebCore/platform/KURL.h index 46b72c7..e419d16 100644 --- a/WebCore/platform/KURL.h +++ b/WebCore/platform/KURL.h @@ -251,8 +251,11 @@ const KURL& blankURL(); // Functions to do URL operations on strings. // These are operations that aren't faster on a parsed URL. +// These are also different from the KURL functions in that they don't require the string to be a valid and parsable URL. +// This is especially important because valid javascript URLs are not necessarily considered valid by KURL. bool protocolIs(const String& url, const char* protocol); +bool protocolIsJavaScript(const String& url); String mimeTypeFromDataURL(const String& url); diff --git a/WebCore/platform/KURLGoogle.cpp b/WebCore/platform/KURLGoogle.cpp index c2e8272..d8b87e5 100644 --- a/WebCore/platform/KURLGoogle.cpp +++ b/WebCore/platform/KURLGoogle.cpp @@ -1,4 +1,5 @@ /* + * Copyright (C) 2004, 2007, 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2008, 2009 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -235,6 +236,7 @@ void KURLGooglePrivate::init(const KURL& base, const UChar* rel, int relLength, charsetConverter, &output, &m_parsed); + if (m_isValid || output.length()) { if (m_parsed.ref.is_nonempty()) setUtf8(CString(output.data(), output.length())); @@ -521,6 +523,12 @@ bool KURL::hasRef() const return m_url.m_parsed.ref.len >= 0; } +String KURL::baseAsString() const +{ + // FIXME: There is probably a more efficient way to do this? + return string().left(pathAfterLastSlash()); +} + String KURL::query() const { if (m_url.m_parsed.query.len >= 0) @@ -685,6 +693,11 @@ String KURL::prettyURL() const return m_url.string(); } +bool protocolIsJavaScript(const String& url) +{ + return protocolIs(url, "javascript"); +} + // We copied the KURL version here on Sept 12, 2008 while doing a WebKit // merge. // @@ -800,6 +813,11 @@ String decodeURLEscapeSequences(const String& str, const TextEncoding& encoding) bool KURL::protocolIs(const char* protocol) const { assertProtocolIsGood(protocol); + + // JavaScript URLs are "valid" and should be executed even if KURL decides they are invalid. + // The free function protocolIsJavaScript() should be used instead. + // FIXME: Chromium code needs to be fixed for this assert to be enabled. ASSERT(strcmp(protocol, "javascript")); + if (m_url.m_parsed.scheme.len <= 0) return !protocol; return lowerCaseEqualsASCII( diff --git a/WebCore/platform/qt/KeyboardCodes.h b/WebCore/platform/KeyboardCodes.h index 61bc9fe..c2c3b54 100644 --- a/WebCore/platform/qt/KeyboardCodes.h +++ b/WebCore/platform/KeyboardCodes.h @@ -30,6 +30,17 @@ #include <wtf/Platform.h> +// FIXME: We should get rid of these Chromium-related ifdefs. +#if PLATFORM(CHROMIUM) + +#if PLATFORM(WIN_OS) +#include "KeyboardCodesWin.h" +#else +#include "KeyboardCodesPosix.h" +#endif + +#else + namespace WebCore { #if !PLATFORM(WIN_OS) @@ -558,4 +569,6 @@ const int VK_UNKNOWN = 0; } +#endif // PLATFORM(CHROMIUM) + #endif diff --git a/WebCore/platform/LinkHash.cpp b/WebCore/platform/LinkHash.cpp index 793a65d..878933a 100644 --- a/WebCore/platform/LinkHash.cpp +++ b/WebCore/platform/LinkHash.cpp @@ -152,12 +152,12 @@ LinkHash visitedLinkHash(const UChar* url, unsigned length) return AlreadyHashed::avoidDeletedValue(StringImpl::computeHash(url, length)); } -LinkHash visitedLinkHash(const KURL& base, const AtomicString& attributeURL) +void visitedURL(const KURL& base, const AtomicString& attributeURL, Vector<UChar, 512>& buffer) { const UChar* characters = attributeURL.characters(); unsigned length = attributeURL.length(); if (!length) - return 0; + return; // This is a poor man's completeURL. Faster with less memory allocation. // FIXME: It's missing a lot of what completeURL does and a lot of what KURL does. @@ -172,17 +172,18 @@ LinkHash visitedLinkHash(const KURL& base, const AtomicString& attributeURL) bool hasColonSlashSlash = containsColonSlashSlash(characters, length); - if (hasColonSlashSlash && !needsTrailingSlash(characters, length)) - return visitedLinkHash(attributeURL.characters(), attributeURL.length()); + if (hasColonSlashSlash && !needsTrailingSlash(characters, length)) { + buffer.append(attributeURL.characters(), attributeURL.length()); + return; + } - Vector<UChar, 512> buffer; if (hasColonSlashSlash) { // FIXME: This is incorrect for URLs that have a query or anchor; the "/" needs to go at the // end of the path, *before* the query or anchor. buffer.append(characters, length); buffer.append('/'); - return visitedLinkHash(buffer.data(), buffer.size()); + return; } switch (characters[0]) { @@ -204,7 +205,17 @@ LinkHash visitedLinkHash(const KURL& base, const AtomicString& attributeURL) buffer.append('/'); } - return visitedLinkHash(buffer.data(), buffer.size()); + return; +} + +LinkHash visitedLinkHash(const KURL& base, const AtomicString& attributeURL) +{ + Vector<UChar, 512> url; + visitedURL(base, attributeURL, url); + if (url.isEmpty()) + return 0; + + return visitedLinkHash(url.data(), url.size()); } } // namespace WebCore diff --git a/WebCore/platform/LinkHash.h b/WebCore/platform/LinkHash.h index 1ec1e16..2756654 100644 --- a/WebCore/platform/LinkHash.h +++ b/WebCore/platform/LinkHash.h @@ -62,6 +62,12 @@ LinkHash visitedLinkHash(const UChar* url, unsigned length); // look like a relative URL. LinkHash visitedLinkHash(const KURL& base, const AtomicString& attributeURL); +// Resolves the potentially relative URL "attributeURL" relative to the given +// base URL, and returns the hash of the string that will be used for visited. +// It will return an empty Vector in case of errors. +void visitedURL(const KURL& base, const AtomicString& attributeURL, Vector<UChar, 512>&); + + } // namespace WebCore #endif // LinkHash_h diff --git a/WebCore/platform/LocalizedStrings.h b/WebCore/platform/LocalizedStrings.h index 085c6e1..b6ec878 100644 --- a/WebCore/platform/LocalizedStrings.h +++ b/WebCore/platform/LocalizedStrings.h @@ -88,6 +88,19 @@ namespace WebCore { String contextMenuItemTagSpeechMenu(); String contextMenuItemTagStartSpeaking(); String contextMenuItemTagStopSpeaking(); + String contextMenuItemTagCorrectSpellingAutomatically(); + String contextMenuItemTagSubstitutionsMenu(); + String contextMenuItemTagShowSubstitutions(bool show); + String contextMenuItemTagSmartCopyPaste(); + String contextMenuItemTagSmartQuotes(); + String contextMenuItemTagSmartDashes(); + String contextMenuItemTagSmartLinks(); + String contextMenuItemTagTextReplacement(); + String contextMenuItemTagTransformationsMenu(); + String contextMenuItemTagMakeUpperCase(); + String contextMenuItemTagMakeLowerCase(); + String contextMenuItemTagCapitalize(); + String contextMenuItemTagChangeBack(const String& replacedString); #endif String contextMenuItemTagInspectElement(); diff --git a/WebCore/platform/Logging.cpp b/WebCore/platform/Logging.cpp index a1aa3d6..9c3f324 100644 --- a/WebCore/platform/Logging.cpp +++ b/WebCore/platform/Logging.cpp @@ -25,6 +25,7 @@ #include "config.h" #include "Logging.h" +#include "PlatformString.h" namespace WebCore { @@ -59,4 +60,33 @@ WTFLogChannel LogMedia = { 0x01000000, "WebCoreLogLevel", WTFLogChan WTFLogChannel LogPlugin = { 0x02000000, "WebCoreLogLevel", WTFLogChannelOff }; WTFLogChannel LogArchives = { 0x04000000, "WebCoreLogLevel", WTFLogChannelOff }; +WTFLogChannel* getChannelFromName(const String& channelName) +{ + if (!(channelName.length() >= 2)) + return 0; + + if (channelName == String("BackForward")) return &LogBackForward; + if (channelName == String("Editing")) return &LogEditing; + if (channelName == String("Events")) return &LogEvents; + if (channelName == String("Frames")) return &LogFrames; + if (channelName == String("FTP")) return &LogFTP; + if (channelName == String("History")) return &LogHistory; + if (channelName == String("IconDatabase")) return &LogIconDatabase; + if (channelName == String("Loading")) return &LogLoading; + if (channelName == String("Media")) return &LogMedia; + if (channelName == String("Network")) return &LogNetwork; + if (channelName == String("NotYetImplemented")) return &LogNotYetImplemented; + if (channelName == String("PageCache")) return &LogPageCache; + if (channelName == String("PlatformLeaks")) return &LogPlatformLeaks; + if (channelName == String("Plugin")) return &LogPlugin; + if (channelName == String("PopupBlocking")) return &LogPopupBlocking; + if (channelName == String("SpellingAndGrammar")) return &LogSpellingAndGrammar; + if (channelName == String("SQLDatabase")) return &LogSQLDatabase; + if (channelName == String("StorageAPI")) return &LogStorageAPI; + if (channelName == String("TextConversion")) return &LogTextConversion; + if (channelName == String("Threading")) return &LogThreading; + + return 0; +} + } diff --git a/WebCore/platform/Logging.h b/WebCore/platform/Logging.h index 844ac3a..c1461e7 100644 --- a/WebCore/platform/Logging.h +++ b/WebCore/platform/Logging.h @@ -34,6 +34,8 @@ namespace WebCore { + class String; + extern WTFLogChannel LogNotYetImplemented; extern WTFLogChannel LogFrames; extern WTFLogChannel LogLoading; @@ -57,6 +59,7 @@ namespace WebCore { extern WTFLogChannel LogArchives; void InitializeLoggingChannelsIfNecessary(); + WTFLogChannel* getChannelFromName(const String& channelName); } #endif // Logging_h diff --git a/WebCore/platform/MIMETypeRegistry.cpp b/WebCore/platform/MIMETypeRegistry.cpp index 14becb5..1819e1d 100644 --- a/WebCore/platform/MIMETypeRegistry.cpp +++ b/WebCore/platform/MIMETypeRegistry.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * Copyright (C) 2006, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,6 +34,7 @@ #include "StringHash.h" #include <wtf/HashMap.h> #include <wtf/HashSet.h> +#include <wtf/StdLibExtras.h> #if PLATFORM(CG) #include "ImageSourceCG.h" @@ -53,6 +54,7 @@ static HashSet<String>* supportedImageMIMETypesForEncoding; static HashSet<String>* supportedJavaScriptMIMETypes; static HashSet<String>* supportedNonImageMIMETypes; static HashSet<String>* supportedMediaMIMETypes; +static HashMap<String, String, CaseFoldingHash>* mediaMIMETypeForExtensionMap; static void initializeSupportedImageMIMETypes() { @@ -73,7 +75,9 @@ static void initializeSupportedImageMIMETypes() supportedImageResourceMIMETypes->add("image/bmp"); // Favicons don't have a MIME type in the registry either. + supportedImageMIMETypes->add("image/vnd.microsoft.icon"); supportedImageMIMETypes->add("image/x-icon"); + supportedImageResourceMIMETypes->add("image/vnd.microsoft.icon"); supportedImageResourceMIMETypes->add("image/x-icon"); // We only get one MIME type per UTI, hence our need to add these manually @@ -102,6 +106,9 @@ static void initializeSupportedImageMIMETypes() supportedImageMIMETypes->add(mimeType); supportedImageResourceMIMETypes->add(mimeType); } + + supportedImageMIMETypes->remove("application/octet-stream"); + supportedImageResourceMIMETypes->remove("application/octet-stream"); #elif PLATFORM(ANDROID) static const char* types[] = { "image/jpeg", @@ -132,6 +139,7 @@ static void initializeSupportedImageMIMETypes() "image/png", "image/gif", "image/bmp", + "image/vnd.microsoft.icon", // ico "image/x-icon", // ico "image/x-xbitmap" // xbm }; @@ -169,6 +177,8 @@ static void initializeSupportedImageMIMETypesForEncoding() String mimeType = MIMETypeRegistry::getMIMETypeForExtension(formats.at(i).constData()); supportedImageMIMETypesForEncoding->add(mimeType); } + + supportedImageMIMETypesForEncoding->remove("application/octet-stream"); #elif PLATFORM(CAIRO) supportedImageMIMETypesForEncoding->add("image/png"); #endif @@ -214,6 +224,9 @@ static void initializeSupportedNonImageMimeTypes() "text/", "application/xml", "application/xhtml+xml", +#if ENABLE(XHTMLMP) + "application/vnd.wap.xhtml+xml", +#endif "application/rss+xml", "application/atom+xml", #if ENABLE(SVG) @@ -232,6 +245,103 @@ static void initializeSupportedNonImageMimeTypes() #endif } +static void initializeMediaTypeMaps() +{ + struct TypeExtensionPair { + const char* type; + const char* extension; + }; + + // A table of common media MIME types and file extenstions used when a platform's + // specific MIME type lookup doens't have a match for a media file extension. While some + // file extensions are claimed by multiple MIME types, this table only includes one + // for each because it is currently only used by getMediaMIMETypeForExtension. If we + // ever add a MIME type -> file extension mapping, the alternate MIME types will need + // to be added. + static const TypeExtensionPair pairs[] = { + + // Ogg + { "application/ogg", "ogg" }, + { "application/ogg", "ogx" }, + { "audio/ogg", "oga" }, + { "video/ogg", "ogv" }, + + // Annodex + { "application/annodex", "anx" }, + { "audio/annodex", "axa" }, + { "video/annodex", "axv" }, + { "audio/speex", "spx" }, + + // MPEG + { "audio/mpeg", "m1a" }, + { "audio/mpeg", "m2a" }, + { "audio/mpeg", "m1s" }, + { "audio/mpeg", "mpa" }, + { "video/mpeg", "mpg" }, + { "video/mpeg", "m15" }, + { "video/mpeg", "m1s" }, + { "video/mpeg", "m1v" }, + { "video/mpeg", "m75" }, + { "video/mpeg", "mpa" }, + { "video/mpeg", "mpeg" }, + { "video/mpeg", "mpm" }, + { "video/mpeg", "mpv" }, + + // MPEG playlist + { "audio/x-mpegurl", "m3url" }, + { "application/x-mpegurl", "m3u8" }, + + // MPEG-4 + { "video/x-m4v", "m4v" }, + { "audio/x-m4a", "m4a" }, + { "audio/x-m4b", "m4b" }, + { "audio/x-m4p", "m4p" }, + + // MP3 + { "audio/mp3", "mp3" }, + + // MPEG-2 + { "video/x-mpeg2", "mp2" }, + { "video/mpeg2", "vob" }, + { "video/mpeg2", "mod" }, + { "video/m2ts", "m2ts" }, + { "video/x-m2ts", "m2t" }, + { "video/x-m2ts", "ts" }, + + // 3GP/3GP2 + { "audio/3gpp", "3gpp" }, + { "audio/3gpp2", "3g2" }, + { "application/x-mpeg", "amc" }, + + // AAC + { "audio/aac", "aac" }, + { "audio/aac", "adts" }, + { "audio/x-aac", "m4r" }, + + // CoreAudio File + { "audio/x-caf", "caf" }, + { "audio/x-gsm", "gsm" } + }; + + mediaMIMETypeForExtensionMap = new HashMap<String, String, CaseFoldingHash>; + const unsigned numPairs = sizeof(pairs) / sizeof(pairs[0]); + for (unsigned ndx = 0; ndx < numPairs; ++ndx) + mediaMIMETypeForExtensionMap->set(pairs[ndx].extension, pairs[ndx].type); +} + +String MIMETypeRegistry::getMediaMIMETypeForExtension(const String& ext) +{ + // Check with system specific implementation first. + String mimeType = getMIMETypeForExtension(ext); + if (!mimeType.isEmpty()) + return mimeType; + + // No match, look in the static mapping. + if (!mediaMIMETypeForExtensionMap) + initializeMediaTypeMaps(); + return mediaMIMETypeForExtensionMap->get(ext); +} + static void initializeSupportedMediaMIMETypes() { supportedMediaMIMETypes = new HashSet<String>; @@ -365,4 +475,10 @@ HashSet<String>& MIMETypeRegistry::getSupportedMediaMIMETypes() return *supportedMediaMIMETypes; } +const String& defaultMIMEType() +{ + DEFINE_STATIC_LOCAL(const String, defaultMIMEType, ("application/octet-stream")); + return defaultMIMEType; +} + } // namespace WebCore diff --git a/WebCore/platform/MIMETypeRegistry.h b/WebCore/platform/MIMETypeRegistry.h index fca467f..8801ac1 100644 --- a/WebCore/platform/MIMETypeRegistry.h +++ b/WebCore/platform/MIMETypeRegistry.h @@ -38,6 +38,7 @@ public: static String getMIMETypeForExtension(const String& ext); static Vector<String> getExtensionsForMIMEType(const String& type); static String getPreferredExtensionForMIMEType(const String& type); + static String getMediaMIMETypeForExtension(const String& ext); static String getMIMETypeForPath(const String& path); @@ -73,6 +74,8 @@ public: static HashSet<String>& getSupportedMediaMIMETypes(); }; +const String& defaultMIMEType(); + } // namespace WebCore #endif // MIMETypeRegistry_h diff --git a/WebCore/platform/PlatformMouseEvent.h b/WebCore/platform/PlatformMouseEvent.h index 9f6bea9..2543d40 100644 --- a/WebCore/platform/PlatformMouseEvent.h +++ b/WebCore/platform/PlatformMouseEvent.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 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 @@ -27,26 +27,6 @@ #define PlatformMouseEvent_h #include "IntPoint.h" -#include <wtf/Platform.h> - -#if PLATFORM(MAC) -#ifdef __OBJC__ -@class NSEvent; -@class NSScreen; -@class NSWindow; -#else -class NSEvent; -class NSScreen; -class NSWindow; -#endif -#endif - -#if PLATFORM(WIN) -typedef struct HWND__* HWND; -typedef unsigned UINT; -typedef unsigned WPARAM; -typedef long LPARAM; -#endif #if PLATFORM(GTK) typedef struct _GdkEventButton GdkEventButton; @@ -59,6 +39,13 @@ class QInputEvent; QT_END_NAMESPACE #endif +#if PLATFORM(WIN) +typedef struct HWND__* HWND; +typedef unsigned UINT; +typedef unsigned WPARAM; +typedef long LPARAM; +#endif + #if PLATFORM(WX) class wxMouseEvent; #endif @@ -84,9 +71,11 @@ namespace WebCore { { } - PlatformMouseEvent(const IntPoint& pos, const IntPoint& globalPos, MouseButton button, MouseEventType eventType, + PlatformMouseEvent(const IntPoint& position, const IntPoint& globalPosition, MouseButton button, MouseEventType eventType, int clickCount, bool shift, bool ctrl, bool alt, bool meta, double timestamp) - : m_position(pos), m_globalPosition(globalPos), m_button(button) + : m_position(position) + , m_globalPosition(globalPosition) + , m_button(button) , m_eventType(eventType) , m_clickCount(clickCount) , m_shiftKey(shift) @@ -112,29 +101,32 @@ namespace WebCore { bool metaKey() const { return m_metaKey; } unsigned modifierFlags() const { return m_modifierFlags; } - //time in seconds + // Time in seconds. double timestamp() const { return m_timestamp; } -#if PLATFORM(MAC) - PlatformMouseEvent(NSEvent*); - int eventNumber() const { return m_eventNumber; } -#endif -#if PLATFORM(WIN) - PlatformMouseEvent(HWND, UINT, WPARAM, LPARAM, bool activatedWebView = false); - void setClickCount(int count) { m_clickCount = count; } - bool activatedWebView() const { return m_activatedWebView; } -#endif #if PLATFORM(GTK) PlatformMouseEvent(GdkEventButton*); PlatformMouseEvent(GdkEventMotion*); #endif + +#if PLATFORM(MAC) && defined(__OBJC__) + PlatformMouseEvent(NSEvent *, NSView *windowView); + int eventNumber() const { return m_eventNumber; } +#endif + #if PLATFORM(QT) PlatformMouseEvent(QInputEvent*, int clickCount); #endif -#if PLATFORM(WX) - PlatformMouseEvent(const wxMouseEvent&, const wxPoint& globalPoint); + +#if PLATFORM(WIN) + PlatformMouseEvent(HWND, UINT, WPARAM, LPARAM, bool activatedWebView = false); + void setClickCount(int count) { m_clickCount = count; } + bool activatedWebView() const { return m_activatedWebView; } #endif +#if PLATFORM(WX) + PlatformMouseEvent(const wxMouseEvent&, const wxPoint& globalPoint, int clickCount); +#endif protected: IntPoint m_position; @@ -148,18 +140,20 @@ namespace WebCore { bool m_metaKey; double m_timestamp; // unit: seconds unsigned m_modifierFlags; + #if PLATFORM(MAC) int m_eventNumber; #endif + #if PLATFORM(WIN) bool m_activatedWebView; #endif }; -#if PLATFORM(MAC) - IntPoint globalPoint(const NSPoint& windowPoint, NSWindow *window); - IntPoint pointForEvent(NSEvent *event); - IntPoint globalPointForEvent(NSEvent *event); +#if PLATFORM(MAC) && defined(__OBJC__) + IntPoint globalPoint(const NSPoint& windowPoint, NSWindow *); + IntPoint pointForEvent(NSEvent *, NSView *windowView); + IntPoint globalPointForEvent(NSEvent *); #endif } // namespace WebCore diff --git a/WebCore/platform/PlatformWheelEvent.h b/WebCore/platform/PlatformWheelEvent.h index 9395e93..037c4b7 100644 --- a/WebCore/platform/PlatformWheelEvent.h +++ b/WebCore/platform/PlatformWheelEvent.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 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 @@ -28,20 +28,6 @@ #include "IntPoint.h" -#if PLATFORM(MAC) -#ifdef __OBJC__ -@class NSEvent; -#else -class NSEvent; -#endif -#endif - -#if PLATFORM(WIN) -typedef struct HWND__* HWND; -typedef unsigned WPARAM; -typedef long LPARAM; -#endif - #if PLATFORM(GTK) typedef struct _GdkEventScroll GdkEventScroll; #endif @@ -52,6 +38,12 @@ class QWheelEvent; QT_END_NAMESPACE #endif +#if PLATFORM(WIN) +typedef struct HWND__* HWND; +typedef unsigned WPARAM; +typedef long LPARAM; +#endif + #if PLATFORM(WX) class wxMouseEvent; class wxPoint; @@ -93,18 +85,22 @@ namespace WebCore { void accept() { m_isAccepted = true; } void ignore() { m_isAccepted = false; } -#if PLATFORM(MAC) - PlatformWheelEvent(NSEvent*); -#endif -#if PLATFORM(WIN) - PlatformWheelEvent(HWND, WPARAM, LPARAM, bool isMouseHWheel); -#endif #if PLATFORM(GTK) PlatformWheelEvent(GdkEventScroll*); #endif + +#if PLATFORM(MAC) && defined(__OBJC__) + PlatformWheelEvent(NSEvent *, NSView *windowView); +#endif + #if PLATFORM(QT) PlatformWheelEvent(QWheelEvent*); #endif + +#if PLATFORM(WIN) + PlatformWheelEvent(HWND, WPARAM, LPARAM, bool isMouseHWheel); +#endif + #if PLATFORM(WX) PlatformWheelEvent(const wxMouseEvent&, const wxPoint&); #endif diff --git a/WebCore/platform/ScrollView.cpp b/WebCore/platform/ScrollView.cpp index 5a12304..f0db95a 100644 --- a/WebCore/platform/ScrollView.cpp +++ b/WebCore/platform/ScrollView.cpp @@ -47,6 +47,7 @@ ScrollView::ScrollView() , m_scrollbarsAvoidingResizer(0) , m_scrollbarsSuppressed(false) , m_inUpdateScrollbars(false) + , m_updateScrollbarsPass(0) , m_drawPanScrollIcon(false) , m_useFixedLayout(false) { @@ -78,7 +79,7 @@ void ScrollView::removeChild(Widget* child) void ScrollView::setHasHorizontalScrollbar(bool hasBar) { - if (hasBar && !m_horizontalScrollbar && !platformHasHorizontalAdjustment()) { + if (hasBar && !m_horizontalScrollbar) { m_horizontalScrollbar = createScrollbar(HorizontalScrollbar); addChild(m_horizontalScrollbar.get()); } else if (!hasBar && m_horizontalScrollbar) { @@ -89,7 +90,7 @@ void ScrollView::setHasHorizontalScrollbar(bool hasBar) void ScrollView::setHasVerticalScrollbar(bool hasBar) { - if (hasBar && !m_verticalScrollbar && !platformHasVerticalAdjustment()) { + if (hasBar && !m_verticalScrollbar) { m_verticalScrollbar = createScrollbar(VerticalScrollbar); addChild(m_verticalScrollbar.get()); } else if (!hasBar && m_verticalScrollbar) { @@ -98,10 +99,12 @@ void ScrollView::setHasVerticalScrollbar(bool hasBar) } } +#if !PLATFORM(GTK) PassRefPtr<Scrollbar> ScrollView::createScrollbar(ScrollbarOrientation orientation) { return Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar); } +#endif void ScrollView::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode) { @@ -238,9 +241,9 @@ void ScrollView::valueChanged(Scrollbar* scrollbar) // Figure out if we really moved. IntSize newOffset = m_scrollOffset; if (scrollbar) { - if (scrollbar == m_horizontalScrollbar) + if (scrollbar->orientation() == HorizontalScrollbar) newOffset.setWidth(scrollbar->value()); - else if (scrollbar == m_verticalScrollbar) + else if (scrollbar->orientation() == VerticalScrollbar) newOffset.setHeight(scrollbar->value()); } @@ -318,62 +321,99 @@ bool ScrollView::scroll(ScrollDirection direction, ScrollGranularity granularity return false; } +static const unsigned cMaxUpdateScrollbarsPass = 2; + void ScrollView::updateScrollbars(const IntSize& desiredOffset) { - // Don't allow re-entrancy into this function. if (m_inUpdateScrollbars || prohibitsScrolling() || platformWidget()) return; - m_inUpdateScrollbars = true; - - bool hasVerticalScrollbar = m_verticalScrollbar; bool hasHorizontalScrollbar = m_horizontalScrollbar; - bool oldHasVertical = hasVerticalScrollbar; - bool oldHasHorizontal = hasHorizontalScrollbar; + bool hasVerticalScrollbar = m_verticalScrollbar; + + bool newHasHorizontalScrollbar = hasHorizontalScrollbar; + bool newHasVerticalScrollbar = hasVerticalScrollbar; + ScrollbarMode hScroll = m_horizontalScrollbarMode; ScrollbarMode vScroll = m_verticalScrollbarMode; - const int scrollbarThickness = ScrollbarTheme::nativeTheme()->scrollbarThickness(); + if (hScroll != ScrollbarAuto) + newHasHorizontalScrollbar = (hScroll == ScrollbarAlwaysOn); + if (vScroll != ScrollbarAuto) + newHasVerticalScrollbar = (vScroll == ScrollbarAlwaysOn); - for (int pass = 0; pass < 2; pass++) { - bool scrollsVertically; - bool scrollsHorizontally; + if (m_scrollbarsSuppressed || (hScroll != ScrollbarAuto && vScroll != ScrollbarAuto)) { + if (hasHorizontalScrollbar != newHasHorizontalScrollbar) + setHasHorizontalScrollbar(newHasHorizontalScrollbar); + if (hasVerticalScrollbar != newHasVerticalScrollbar) + setHasVerticalScrollbar(newHasVerticalScrollbar); + } else { + // If we came in here with the view already needing a layout, then go ahead and do that + // first. (This will be the common case, e.g., when the page changes due to window resizing for example). + // This layout will not re-enter updateScrollers and does not count towards our max layout pass total. + m_inUpdateScrollbars = true; + visibleContentsResized(); + m_inUpdateScrollbars = false; + + bool sendContentResizedNotification = false; + + IntSize docSize = contentsSize(); + IntSize frameSize = frameRect().size(); - if (!m_scrollbarsSuppressed && (hScroll == ScrollbarAuto || vScroll == ScrollbarAuto)) { - // Do a layout if pending before checking if scrollbars are needed. - if (hasVerticalScrollbar != oldHasVertical || hasHorizontalScrollbar != oldHasHorizontal) - visibleContentsResized(); + if (hScroll == ScrollbarAuto) { + newHasHorizontalScrollbar = docSize.width() > visibleWidth(); + if (newHasHorizontalScrollbar && !m_updateScrollbarsPass && docSize.width() <= frameSize.width() && docSize.height() <= frameSize.height()) + newHasHorizontalScrollbar = false; + } + if (vScroll == ScrollbarAuto) { + newHasVerticalScrollbar = docSize.height() > visibleHeight(); + if (newHasVerticalScrollbar && !m_updateScrollbarsPass && docSize.width() <= frameSize.width() && docSize.height() <= frameSize.height()) + newHasVerticalScrollbar = false; + } - scrollsVertically = (vScroll == ScrollbarAlwaysOn) || (vScroll == ScrollbarAuto && contentsHeight() > height()); - if (scrollsVertically) - scrollsHorizontally = (hScroll == ScrollbarAlwaysOn) || (hScroll == ScrollbarAuto && contentsWidth() + scrollbarThickness > width()); - else { - scrollsHorizontally = (hScroll == ScrollbarAlwaysOn) || (hScroll == ScrollbarAuto && contentsWidth() > width()); - if (scrollsHorizontally) - scrollsVertically = (vScroll == ScrollbarAlwaysOn) || (vScroll == ScrollbarAuto && contentsHeight() + scrollbarThickness > height()); - } - } else { - scrollsHorizontally = (hScroll == ScrollbarAuto) ? hasHorizontalScrollbar : (hScroll == ScrollbarAlwaysOn); - scrollsVertically = (vScroll == ScrollbarAuto) ? hasVerticalScrollbar : (vScroll == ScrollbarAlwaysOn); + // If we ever turn one scrollbar off, always turn the other one off too. Never ever + // try to both gain/lose a scrollbar in the same pass. + if (!newHasHorizontalScrollbar && hasHorizontalScrollbar && vScroll != ScrollbarAlwaysOn) + newHasVerticalScrollbar = false; + if (!newHasVerticalScrollbar && hasVerticalScrollbar && hScroll != ScrollbarAlwaysOn) + newHasHorizontalScrollbar = false; + + if (hasHorizontalScrollbar != newHasHorizontalScrollbar) { + setHasHorizontalScrollbar(newHasHorizontalScrollbar); + sendContentResizedNotification = true; } - - if (hasVerticalScrollbar != scrollsVertically) { - setHasVerticalScrollbar(scrollsVertically); - hasVerticalScrollbar = scrollsVertically; + + if (hasVerticalScrollbar != newHasVerticalScrollbar) { + setHasVerticalScrollbar(newHasVerticalScrollbar); + sendContentResizedNotification = true; } - if (hasHorizontalScrollbar != scrollsHorizontally) { - setHasHorizontalScrollbar(scrollsHorizontally); - hasHorizontalScrollbar = scrollsHorizontally; + if (sendContentResizedNotification && m_updateScrollbarsPass < cMaxUpdateScrollbarsPass) { + m_updateScrollbarsPass++; + contentsResized(); + visibleContentsResized(); + IntSize newDocSize = contentsSize(); + if (newDocSize == docSize) { + // The layout with the new scroll state had no impact on + // the document's overall size, so updateScrollbars didn't get called. + // Recur manually. + updateScrollbars(desiredOffset); + } + m_updateScrollbarsPass--; } } - // Set up the range (and page step/line step). + // Set up the range (and page step/line step), but only do this if we're not in a nested call (to avoid + // doing it multiple times). + if (m_updateScrollbarsPass) + return; + + m_inUpdateScrollbars = true; IntSize maxScrollPosition(contentsWidth() - visibleWidth(), contentsHeight() - visibleHeight()); IntSize scroll = desiredOffset.shrunkTo(maxScrollPosition); scroll.clampNegativeToZero(); - if (!platformHandleHorizontalAdjustment(scroll) && m_horizontalScrollbar) { + if (m_horizontalScrollbar) { int clientWidth = visibleWidth(); m_horizontalScrollbar->setEnabled(contentsWidth() > clientWidth); int pageStep = (clientWidth - cAmountToKeepWhenPaging); @@ -397,7 +437,7 @@ void ScrollView::updateScrollbars(const IntSize& desiredOffset) m_horizontalScrollbar->setSuppressInvalidation(false); } - if (!platformHandleVerticalAdjustment(scroll) && m_verticalScrollbar) { + if (m_verticalScrollbar) { int clientHeight = visibleHeight(); m_verticalScrollbar->setEnabled(contentsHeight() > clientHeight); int pageStep = (clientHeight - cAmountToKeepWhenPaging); @@ -421,7 +461,7 @@ void ScrollView::updateScrollbars(const IntSize& desiredOffset) m_verticalScrollbar->setSuppressInvalidation(false); } - if (oldHasVertical != (m_verticalScrollbar != 0) || oldHasHorizontal != (m_horizontalScrollbar != 0)) + if (hasHorizontalScrollbar != (m_horizontalScrollbar != 0) || hasVerticalScrollbar != (m_verticalScrollbar != 0)) frameRectsChanged(); // See if our offset has changed in a situation where we might not have scrollbars. @@ -467,7 +507,7 @@ void ScrollView::scrollContents(const IntSize& scrollDelta) hostWindow()->scroll(-scrollDelta, scrollViewRect, clipRect); } else { // We need to go ahead and repaint the entire backing store. Do it now before moving the - // plugins. + // windowed plugins. hostWindow()->repaint(updateRect, true, false, true); // Invalidate the backing store and repaint it synchronously } @@ -548,8 +588,16 @@ void ScrollView::setParent(ScrollView* parentView) if (m_scrollbarsAvoidingResizer && parent()) parent()->adjustScrollbarsAvoidingResizerCount(-m_scrollbarsAvoidingResizer); +#if PLATFORM(QT) + if (m_widgetsPreventingBlitting && parent()) + parent()->adjustWidgetsPreventingBlittingCount(-m_widgetsPreventingBlitting); + + if (m_widgetsPreventingBlitting && parentView) + parentView->adjustWidgetsPreventingBlittingCount(m_widgetsPreventingBlitting); +#endif + Widget::setParent(parentView); - + if (m_scrollbarsAvoidingResizer && parent()) parent()->adjustScrollbarsAvoidingResizerCount(m_scrollbarsAvoidingResizer); } @@ -606,8 +654,13 @@ Scrollbar* ScrollView::scrollbarUnderMouse(const PlatformMouseEvent& mouseEvent) void ScrollView::wheelEvent(PlatformWheelEvent& e) { // We don't allow mouse wheeling to happen in a ScrollView that has had its scrollbars explicitly disabled. - if (!canHaveScrollbars() || platformWidget()) +#if PLATFORM(WX) + if (!canHaveScrollbars()) { +#else + if (!canHaveScrollbars() || platformWidget()) { +#endif return; + } // Determine how much we want to scroll. If we can move at all, we will accept the event. IntSize maxScrollDelta = maximumScrollPosition() - scrollPosition(); @@ -817,6 +870,7 @@ void ScrollView::removePanScrollIcon() } #if !PLATFORM(WX) && !PLATFORM(GTK) && !PLATFORM(QT) + void ScrollView::platformInit() { } @@ -824,9 +878,11 @@ void ScrollView::platformInit() void ScrollView::platformDestroy() { } + #endif #if !PLATFORM(WX) && !PLATFORM(GTK) && !PLATFORM(QT) && !PLATFORM(MAC) + void ScrollView::platformAddChild(Widget*) { } @@ -834,15 +890,19 @@ void ScrollView::platformAddChild(Widget*) void ScrollView::platformRemoveChild(Widget*) { } + #endif #if !PLATFORM(MAC) + void ScrollView::platformSetScrollbarsSuppressed(bool repaintOnUnsuppress) { } + #endif #if !PLATFORM(MAC) && !PLATFORM(WX) + void ScrollView::platformSetScrollbarModes() { } @@ -850,6 +910,8 @@ void ScrollView::platformSetScrollbarModes() #if !PLATFORM(ANDROID) void ScrollView::platformScrollbarModes(ScrollbarMode& horizontal, ScrollbarMode& vertical) const { + horizontal = ScrollbarAuto; + vertical = ScrollbarAuto; } #endif @@ -917,28 +979,6 @@ bool ScrollView::platformIsOffscreen() const { return false; } -#endif - -#if !PLATFORM(GTK) -bool ScrollView::platformHandleHorizontalAdjustment(const IntSize&) -{ - return false; -} - -bool ScrollView::platformHandleVerticalAdjustment(const IntSize&) -{ - return false; -} - -bool ScrollView::platformHasHorizontalAdjustment() const -{ - return false; -} - -bool ScrollView::platformHasVerticalAdjustment() const -{ - return false; -} #endif diff --git a/WebCore/platform/ScrollView.h b/WebCore/platform/ScrollView.h index f7bfbe8..9847350 100644 --- a/WebCore/platform/ScrollView.h +++ b/WebCore/platform/ScrollView.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2004, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Holger Hans Peter Freyther * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -46,9 +47,6 @@ typedef struct _GtkAdjustment GtkAdjustment; class wxScrollWinEvent; #endif -// DANGER WILL ROBINSON! THIS FILE IS UNDERGOING HEAVY REFACTORING. -// Everything is changing! -// Port authors should wait until this refactoring is complete before attempting to implement this interface. namespace WebCore { class HostWindow; @@ -125,7 +123,7 @@ public: // Methods for getting/setting the size of the document contained inside the ScrollView (as an IntSize or as individual width and height // values). - IntSize contentsSize() const; + IntSize contentsSize() const; // Always at least as big as the visibleWidth()/visibleHeight(). int contentsWidth() const { return contentsSize().width(); } int contentsHeight() const { return contentsSize().height(); } virtual void setContentsSize(const IntSize&); @@ -254,6 +252,7 @@ private: bool m_scrollbarsSuppressed; bool m_inUpdateScrollbars; + unsigned m_updateScrollbarsPass; IntPoint m_panScrollIconPoint; bool m_drawPanScrollIcon; @@ -283,10 +282,6 @@ private: void platformSetScrollbarsSuppressed(bool repaintOnUnsuppress); void platformRepaintContentRectangle(const IntRect&, bool now); bool platformIsOffscreen() const; - bool platformHandleHorizontalAdjustment(const IntSize&); - bool platformHandleVerticalAdjustment(const IntSize&); - bool platformHasHorizontalAdjustment() const; - bool platformHasVerticalAdjustment() const; #if PLATFORM(MAC) && defined __OBJC__ public: @@ -297,9 +292,11 @@ private: #endif #if PLATFORM(QT) +public: + void adjustWidgetsPreventingBlittingCount(int delta); private: - bool rootPreventsBlitting() const { return root()->m_widgetsThatPreventBlitting > 0; } - unsigned m_widgetsThatPreventBlitting; + bool rootPreventsBlitting() const { return root()->m_widgetsPreventingBlitting > 0; } + unsigned m_widgetsPreventingBlitting; #else bool rootPreventsBlitting() const { return false; } #endif diff --git a/WebCore/platform/Scrollbar.cpp b/WebCore/platform/Scrollbar.cpp index 13bb0c9..babf3d4 100644 --- a/WebCore/platform/Scrollbar.cpp +++ b/WebCore/platform/Scrollbar.cpp @@ -57,6 +57,7 @@ Scrollbar::Scrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, , m_visibleSize(0) , m_totalSize(0) , m_currentPos(0) + , m_dragOrigin(0) , m_lineStep(0) , m_pageStep(0) , m_pixelStep(1) @@ -92,13 +93,7 @@ bool Scrollbar::setValue(int v) v = max(min(v, m_totalSize - m_visibleSize), 0); if (value() == v) return false; // Our value stayed the same. - m_currentPos = v; - - updateThumbPosition(); - - if (client()) - client()->valueChanged(this); - + setCurrentPos(v); return true; } @@ -139,20 +134,7 @@ bool Scrollbar::scroll(ScrollDirection direction, ScrollGranularity granularity, float newPos = m_currentPos + step * multiplier; float maxPos = m_totalSize - m_visibleSize; - newPos = max(min(newPos, maxPos), 0.0f); - - if (newPos == m_currentPos) - return false; - - int oldValue = value(); - m_currentPos = newPos; - updateThumbPosition(); - - if (value() != oldValue && client()) - client()->valueChanged(this); - - // return true even if the integer value did not change so that scroll event gets eaten - return true; + return setCurrentPos(max(min(newPos, maxPos), 0.0f)); } void Scrollbar::updateThumbPosition() @@ -269,15 +251,30 @@ void Scrollbar::moveThumb(int pos) int thumbLen = theme()->thumbLength(this); int trackLen = theme()->trackLength(this); int maxPos = trackLen - thumbLen; - int delta = pos - pressedPos(); + int delta = pos - m_pressedPos; if (delta > 0) delta = min(maxPos - thumbPos, delta); else if (delta < 0) delta = max(-thumbPos, delta); - if (delta) { - setValue(static_cast<int>(static_cast<float>(thumbPos + delta) * maximum() / (trackLen - thumbLen))); - setPressedPos(pressedPos() + theme()->thumbPosition(this) - thumbPos); - } + if (delta) + setCurrentPos(static_cast<float>(thumbPos + delta) * maximum() / (trackLen - thumbLen)); +} + +bool Scrollbar::setCurrentPos(float pos) +{ + if (pos == m_currentPos) + return false; + + int oldValue = value(); + int oldThumbPos = theme()->thumbPosition(this); + m_currentPos = pos; + updateThumbPosition(); + if (m_pressedPart == ThumbPart) + setPressedPos(m_pressedPos + theme()->thumbPosition(this) - oldThumbPos); + + if (value() != oldValue && client()) + client()->valueChanged(this); + return true; } void Scrollbar::setHoveredPart(ScrollbarPart part) @@ -287,7 +284,7 @@ void Scrollbar::setHoveredPart(ScrollbarPart part) if ((m_hoveredPart == NoPart || part == NoPart) && theme()->invalidateOnMouseEnterExit()) invalidate(); // Just invalidate the whole scrollbar, since the buttons at either end change anyway. - else if (m_pressedPart == NoPart) { + else if (m_pressedPart == NoPart) { // When there's a pressed part, we don't draw a hovered state, so there's no reason to invalidate. theme()->invalidatePart(this, part); theme()->invalidatePart(this, m_hoveredPart); } @@ -301,14 +298,20 @@ void Scrollbar::setPressedPart(ScrollbarPart part) m_pressedPart = part; if (m_pressedPart != NoPart) theme()->invalidatePart(this, m_pressedPart); + else if (m_hoveredPart != NoPart) // When we no longer have a pressed part, we can start drawing a hovered state on the hovered part. + theme()->invalidatePart(this, m_hoveredPart); } bool Scrollbar::mouseMoved(const PlatformMouseEvent& evt) { if (m_pressedPart == ThumbPart) { - moveThumb(m_orientation == HorizontalScrollbar ? - convertFromContainingWindow(evt.pos()).x() : - convertFromContainingWindow(evt.pos()).y()); + if (theme()->shouldSnapBackToDragOrigin(this, evt)) + setCurrentPos(m_dragOrigin); + else { + moveThumb(m_orientation == HorizontalScrollbar ? + convertFromContainingWindow(evt.pos()).x() : + convertFromContainingWindow(evt.pos()).y()); + } return true; } @@ -364,9 +367,10 @@ bool Scrollbar::mouseDown(const PlatformMouseEvent& evt) setPressedPart(theme()->hitTest(this, evt)); int pressedPos = (orientation() == HorizontalScrollbar ? convertFromContainingWindow(evt.pos()).x() : convertFromContainingWindow(evt.pos()).y()); - if ((pressedPart() == BackTrackPart || pressedPart() == ForwardTrackPart) && theme()->shouldCenterOnThumb(this, evt)) { + if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && theme()->shouldCenterOnThumb(this, evt)) { setHoveredPart(ThumbPart); setPressedPart(ThumbPart); + m_dragOrigin = m_currentPos; int thumbLen = theme()->thumbLength(this); int desiredPos = pressedPos; // Set the pressed position to the middle of the thumb so that when we do the move, the delta @@ -374,7 +378,8 @@ bool Scrollbar::mouseDown(const PlatformMouseEvent& evt) m_pressedPos = theme()->trackPosition(this) + theme()->thumbPosition(this) + thumbLen / 2; moveThumb(desiredPos); return true; - } + } else if (m_pressedPart == ThumbPart) + m_dragOrigin = m_currentPos; m_pressedPos = pressedPos; diff --git a/WebCore/platform/Scrollbar.h b/WebCore/platform/Scrollbar.h index 2c5b274..19d95d7 100644 --- a/WebCore/platform/Scrollbar.h +++ b/WebCore/platform/Scrollbar.h @@ -125,6 +125,9 @@ public: virtual void styleChanged() { } +private: + virtual bool isScrollbar() const { return true; } + protected: virtual void updateThumbPosition(); virtual void updateThumbProportion(); @@ -137,6 +140,7 @@ protected: ScrollGranularity pressedPartScrollGranularity(); void moveThumb(int pos); + bool setCurrentPos(float pos); ScrollbarClient* m_client; ScrollbarOrientation m_orientation; @@ -146,6 +150,7 @@ protected: int m_visibleSize; int m_totalSize; float m_currentPos; + float m_dragOrigin; int m_lineStep; int m_pageStep; float m_pixelStep; diff --git a/WebCore/platform/ScrollbarTheme.h b/WebCore/platform/ScrollbarTheme.h index e2aebc6..9327dc6 100644 --- a/WebCore/platform/ScrollbarTheme.h +++ b/WebCore/platform/ScrollbarTheme.h @@ -76,6 +76,7 @@ public: virtual void paintScrollCorner(ScrollView*, GraphicsContext* context, const IntRect& cornerRect) { context->fillRect(cornerRect, Color::white); } virtual bool shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent&) { return false; } + virtual bool shouldSnapBackToDragOrigin(Scrollbar*, const PlatformMouseEvent&) { return false; } virtual int thumbPosition(Scrollbar*) { return 0; } // The position of the thumb relative to the track. virtual int thumbLength(Scrollbar*) { return 0; } // The length of the thumb along the axis of the scrollbar. virtual int trackPosition(Scrollbar*) { return 0; } // The position of the track relative to the scrollbar. diff --git a/WebCore/platform/SharedBuffer.h b/WebCore/platform/SharedBuffer.h index 3675a3b..3404a0c 100644 --- a/WebCore/platform/SharedBuffer.h +++ b/WebCore/platform/SharedBuffer.h @@ -70,6 +70,7 @@ public: #endif #if PLATFORM(CF) CFDataRef createCFData(); + static PassRefPtr<SharedBuffer> wrapCFData(CFDataRef); #endif const char* data() const; diff --git a/WebCore/platform/SuddenTermination.h b/WebCore/platform/SuddenTermination.h new file mode 100644 index 0000000..7171102 --- /dev/null +++ b/WebCore/platform/SuddenTermination.h @@ -0,0 +1,43 @@ +/* + * 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 SuddenTermination_h +#define SuddenTermination_h + +#include <wtf/Platform.h> + +namespace WebCore { + + void disableSuddenTermination(); + void enableSuddenTermination(); + +#if (!PLATFORM(MAC) || defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)) && !PLATFORM(CHROMIUM) + inline void disableSuddenTermination() { } + inline void enableSuddenTermination() { } +#endif + +} // namespace WebCore + +#endif // SuddenTermination_h diff --git a/WebCore/platform/ThreadGlobalData.cpp b/WebCore/platform/ThreadGlobalData.cpp index 903af66..a43e9bd 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) +#if USE(ICU_UNICODE) || USE(GLIB_ICU_UNICODE_HYBRID) #include "TextCodecICU.h" #endif @@ -72,7 +72,10 @@ ThreadGlobalData::ThreadGlobalData() , m_atomicStringTable(new HashSet<StringImpl*>) , m_eventNames(new EventNames) , m_threadTimers(new ThreadTimers) -#if USE(ICU_UNICODE) +#ifndef NDEBUG + , m_isMainThread(isMainThread()) +#endif +#if USE(ICU_UNICODE) || USE(GLIB_ICU_UNICODE_HYBRID) , m_cachedConverterICU(new ICUConverterWrapper) #endif #if PLATFORM(MAC) @@ -86,7 +89,7 @@ ThreadGlobalData::~ThreadGlobalData() #if PLATFORM(MAC) delete m_cachedConverterTEC; #endif -#if USE(ICU_UNICODE) +#if USE(ICU_UNICODE) || USE(GLIB_ICU_UNICODE_HYBRID) delete m_cachedConverterICU; #endif @@ -94,7 +97,12 @@ ThreadGlobalData::~ThreadGlobalData() delete m_atomicStringTable; delete m_threadTimers; - ASSERT(isMainThread() || m_emptyString->hasOneRef()); // We intentionally don't clean up static data on application quit, so there will be many strings remaining on the main thread. + // Using member variable m_isMainThread instead of calling WTF::isMainThread() directly + // to avoid issues described in https://bugs.webkit.org/show_bug.cgi?id=25973. + // In short, some pthread-based platforms and ports can not use WTF::CurrentThread() and WTF::isMainThread() + // in destructors of thread-specific data. + ASSERT(m_isMainThread || m_emptyString->hasOneRef()); // We intentionally don't clean up static data on application quit, so there will be many strings remaining on the main thread. + delete m_emptyString; } diff --git a/WebCore/platform/ThreadGlobalData.h b/WebCore/platform/ThreadGlobalData.h index 7faca36..e0aa092 100644 --- a/WebCore/platform/ThreadGlobalData.h +++ b/WebCore/platform/ThreadGlobalData.h @@ -48,7 +48,7 @@ namespace WebCore { HashSet<StringImpl*>& atomicStringTable() { return *m_atomicStringTable; } ThreadTimers& threadTimers() { return *m_threadTimers; } -#if USE(ICU_UNICODE) +#if USE(ICU_UNICODE) || USE(GLIB_ICU_UNICODE_HYBRID) ICUConverterWrapper& cachedConverterICU() { return *m_cachedConverterICU; } #endif @@ -62,7 +62,11 @@ namespace WebCore { EventNames* m_eventNames; ThreadTimers* m_threadTimers; -#if USE(ICU_UNICODE) +#ifndef NDEBUG + bool m_isMainThread; +#endif + +#if USE(ICU_UNICODE) || USE(GLIB_ICU_UNICODE_HYBRID) ICUConverterWrapper* m_cachedConverterICU; #endif diff --git a/WebCore/platform/Timer.cpp b/WebCore/platform/Timer.cpp index 353a2a7..d4235d9 100644 --- a/WebCore/platform/Timer.cpp +++ b/WebCore/platform/Timer.cpp @@ -169,6 +169,9 @@ TimerBase::TimerBase() : m_nextFireTime(0) , m_repeatInterval(0) , m_heapIndex(-1) +#ifndef NDEBUG + , m_thread(currentThread()) +#endif { } @@ -180,12 +183,16 @@ TimerBase::~TimerBase() void TimerBase::start(double nextFireInterval, double repeatInterval) { + ASSERT(m_thread == currentThread()); + m_repeatInterval = repeatInterval; setNextFireTime(currentTime() + nextFireInterval); } void TimerBase::stop() { + ASSERT(m_thread == currentThread()); + m_repeatInterval = 0; setNextFireTime(0); @@ -196,6 +203,8 @@ void TimerBase::stop() bool TimerBase::isActive() const { + ASSERT(m_thread == currentThread()); + return m_nextFireTime || timersReadyToFire().contains(this); } @@ -284,6 +293,8 @@ void TimerBase::heapPopMin() void TimerBase::setNextFireTime(double newTime) { + ASSERT(m_thread == currentThread()); + // Keep heap valid while changing the next-fire time. timersReadyToFire().remove(this); diff --git a/WebCore/platform/Timer.h b/WebCore/platform/Timer.h index aab52c2..8723515 100644 --- a/WebCore/platform/Timer.h +++ b/WebCore/platform/Timer.h @@ -27,6 +27,7 @@ #define Timer_h #include <wtf/Noncopyable.h> +#include <wtf/Threading.h> namespace WebCore { @@ -77,6 +78,10 @@ private: int m_heapIndex; // -1 if not in heap unsigned m_heapInsertionOrder; // Used to keep order among equal-fire-time timers +#ifndef NDEBUG + ThreadIdentifier m_thread; +#endif + friend class TimerHeapElement; friend class ThreadTimers; friend bool operator<(const TimerHeapElement&, const TimerHeapElement&); diff --git a/WebCore/platform/Widget.h b/WebCore/platform/Widget.h index 459d615..50d17b2 100644 --- a/WebCore/platform/Widget.h +++ b/WebCore/platform/Widget.h @@ -155,6 +155,7 @@ public: virtual bool isFrameView() const { return false; } virtual bool isPluginView() const { return false; } + virtual bool isScrollbar() const { return false; } void removeFromParent(); virtual void setParent(ScrollView* view); diff --git a/WebCore/platform/android/RenderThemeAndroid.cpp b/WebCore/platform/android/RenderThemeAndroid.cpp index a1e8bf6..3910b7a 100644 --- a/WebCore/platform/android/RenderThemeAndroid.cpp +++ b/WebCore/platform/android/RenderThemeAndroid.cpp @@ -27,7 +27,6 @@ #include "RenderThemeAndroid.h" #include "Color.h" -#include "FormControlElement.h" #include "GraphicsContext.h" #include "PlatformGraphicsContext.h" #include "RenderSkinAndroid.h" @@ -181,8 +180,8 @@ bool RenderThemeAndroid::paintButton(RenderObject* obj, const RenderObject::Pain { // If it is a disabled button, simply paint it to the master picture. Node* node = obj->node(); - FormControlElement* formControlElement = toFormControlElement(static_cast<Element*>(node)); - if (formControlElement && !formControlElement->isEnabled()) + if (node && node->isElementNode() && + static_cast<Element*>(node)->isEnabledFormControl()) RenderSkinButton::Draw(getCanvasFromInfo(info), rect, RenderSkinAndroid::kDisabled); else // Store all the important information in the platform context. @@ -255,10 +254,7 @@ static void adjustMenuListStyleCommon(RenderStyle* style, Element* e) style->setPaddingRight(Length(RenderSkinCombo::extraWidth(), Fixed)); // Code copied from RenderThemeMac.mm // Makes sure that the text shows up on our treatment - bool isEnabled = true; - if (FormControlElement* formControlElement = toFormControlElement(e)) - isEnabled = formControlElement->isEnabled(); - style->setColor(isEnabled ? Color::black : Color::darkGray); + style->setColor(e->isEnabledFormControl() ? Color::black : Color::darkGray); } void RenderThemeAndroid::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element* e) const diff --git a/WebCore/platform/android/TemporaryLinkStubs.cpp b/WebCore/platform/android/TemporaryLinkStubs.cpp index b00f321..b48f006 100644 --- a/WebCore/platform/android/TemporaryLinkStubs.cpp +++ b/WebCore/platform/android/TemporaryLinkStubs.cpp @@ -59,6 +59,7 @@ #include "Icon.h" #include "IconDatabase.h" #include "IconLoader.h" +#include "InspectorFrontend.h" #include "IntPoint.h" #if USE(JSC) @@ -459,7 +460,7 @@ PassRefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String&) #if USE(JSC) namespace JSC { namespace Bindings { bool dispatchJNICall(ExecState*, const void* targetAppletView, jobject obj, bool isStatic, JNIType returnType, - jmethodID methodID, jvalue* args, jvalue& result, const char* callingURL, JSValuePtr& exceptionDescription) + jmethodID methodID, jvalue* args, jvalue& result, const char* callingURL, JSValue& exceptionDescription) { notImplemented(); return false; @@ -539,6 +540,11 @@ void AXObjectCache::remove(RenderObject*) notImplemented(); } +InspectorFrontend::~InspectorFrontend() +{ + notImplemented(); +} + #if USE(JSC) using namespace JSC; @@ -555,15 +561,9 @@ OpaqueJSClassContextData::~OpaqueJSClassContextData() // as we don't use inspector/*.cpp, add stub here. +/* namespace WebCore { - -JSValuePtr toJS(ExecState*, Profile*) -{ - notImplemented(); - return jsNull(); -} - -JSValuePtr JavaScriptCallFrame::evaluate(const UString& script, JSValuePtr& exception) const +JSValue JavaScriptCallFrame::evaluate(const UString& script, JSValue& exception) const { notImplemented(); return jsNull(); @@ -663,4 +663,5 @@ void JavaScriptDebugServer::willExecuteProgram(const DebuggerCallFrame&, int, in { notImplemented(); } +*/ #endif diff --git a/WebCore/platform/cf/BinaryPropertyList.cpp b/WebCore/platform/cf/BinaryPropertyList.cpp new file mode 100644 index 0000000..c0fda3d --- /dev/null +++ b/WebCore/platform/cf/BinaryPropertyList.cpp @@ -0,0 +1,831 @@ +/* + * 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. + */ + +#include "config.h" +#include "BinaryPropertyList.h" + +#include "StringHash.h" +#include <wtf/HashSet.h> +#include <limits> + +using namespace std; + +namespace WebCore { + +static const size_t headerSize = 8; +static const size_t trailerSize = 32; + +static const UInt8 booleanTrueMarkerByte = 0x09; +static const UInt8 oneByteIntegerMarkerByte = 0x10; +static const UInt8 twoByteIntegerMarkerByte = 0x11; +static const UInt8 fourByteIntegerMarkerByte = 0x12; +static const UInt8 eightByteIntegerMarkerByte = 0x13; +static const UInt8 asciiStringMarkerByte = 0x50; +static const UInt8 asciiStringWithSeparateLengthMarkerByte = 0x5F; +static const UInt8 unicodeStringMarkerByte = 0x60; +static const UInt8 unicodeStringWithSeparateLengthMarkerByte = 0x6F; +static const UInt8 arrayMarkerByte = 0xA0; +static const UInt8 arrayWithSeparateLengthMarkerByte = 0xAF; +static const UInt8 dictionaryMarkerByte = 0xD0; +static const UInt8 dictionaryWithSeparateLengthMarkerByte = 0xDF; +static const size_t maxLengthInMarkerByte = 0xE; + +class IntegerArray { +public: + IntegerArray() : m_integers(0), m_size(0) { } + IntegerArray(const int* integers, size_t size) : m_integers(integers), m_size(size) { ASSERT(integers); ASSERT(size); } + + void markDeleted() { m_integers = 0; m_size = deletedValueSize(); } + bool isDeletedValue() const { return m_size == deletedValueSize(); } + + const int* integers() const { ASSERT(!isDeletedValue()); return m_integers; } + size_t size() const { ASSERT(!isDeletedValue()); return m_size; } + +private: + static size_t deletedValueSize() { return numeric_limits<size_t>::max(); } + + friend bool operator==(const IntegerArray&, const IntegerArray&); + + const int* m_integers; + size_t m_size; +}; + +inline bool operator==(const IntegerArray& a, const IntegerArray& b) +{ + return a.m_integers == b.m_integers && a.m_size == b.m_size; +} + +struct IntegerArrayHashTraits : WTF::GenericHashTraits<IntegerArray> { + static const bool needsDestruction = false; + static void constructDeletedValue(IntegerArray& slot) { slot.markDeleted(); } + static bool isDeletedValue(const IntegerArray& array) { return array.isDeletedValue(); } +}; + +struct IntegerArrayHash { + static unsigned hash(const IntegerArray&); + static bool equal(const IntegerArray&, const IntegerArray&); + static const bool safeToCompareToEmptyOrDeleted = true; +}; + +unsigned IntegerArrayHash::hash(const IntegerArray& array) +{ + return StringImpl::computeHash(reinterpret_cast<const UChar*>(array.integers()), array.size() / (sizeof(int) / sizeof(UChar))); +} + +bool IntegerArrayHash::equal(const IntegerArray& a, const IntegerArray& b) +{ + if (a.isDeletedValue() || b.isDeletedValue()) + return a.isDeletedValue() == b.isDeletedValue(); + if (a.size() != b.size()) + return false; + for (size_t i = 0; i < a.size(); ++i) { + if (a.integers()[i] != b.integers()[i]) + return false; + } + return true; +} + +typedef size_t ObjectReference; + +class BinaryPropertyListPlan : private BinaryPropertyListObjectStream { +public: + BinaryPropertyListPlan(BinaryPropertyListWriter&); + + ObjectReference booleanTrueObjectReference() const; + ObjectReference integerObjectReference(int) const; + ObjectReference stringObjectReference(const String&) const; + ObjectReference integerArrayObjectReference(const int*, size_t) const; + + ObjectReference objectCount() const { return m_currentObjectReference; } + + ObjectReference byteCount() const { return m_byteCount; } + ObjectReference objectReferenceCount() const { return m_objectReferenceCount; } + +private: + virtual void writeBooleanTrue(); + virtual void writeInteger(int); + virtual void writeString(const String&); + virtual void writeIntegerArray(const int*, size_t); + virtual void writeUniqueString(const String&); + virtual void writeUniqueString(const char*); + virtual size_t writeArrayStart(); + virtual void writeArrayEnd(size_t); + virtual size_t writeDictionaryStart(); + virtual void writeDictionaryEnd(size_t); + + void writeArrayObject(size_t); + void writeDictionaryObject(size_t); + void writeStringObject(const String&); + void writeStringObject(const char*); + + static ObjectReference invalidObjectReference() { return numeric_limits<ObjectReference>::max(); } + + typedef HashMap<IntegerArray, ObjectReference, IntegerArrayHash, IntegerArrayHashTraits> IntegerArrayMap; + + ObjectReference m_booleanTrueObjectReference; + ObjectReference m_integerZeroObjectReference; + HashMap<int, ObjectReference> m_integers; + HashMap<String, ObjectReference> m_strings; + IntegerArrayMap m_integerArrays; + + ObjectReference m_currentObjectReference; + + size_t m_currentAggregateSize; + + size_t m_byteCount; + size_t m_objectReferenceCount; +}; + +BinaryPropertyListPlan::BinaryPropertyListPlan(BinaryPropertyListWriter& client) + : m_booleanTrueObjectReference(invalidObjectReference()) + , m_integerZeroObjectReference(invalidObjectReference()) + , m_currentObjectReference(0) + , m_currentAggregateSize(0) + , m_byteCount(0) + , m_objectReferenceCount(0) +{ + client.writeObjects(*this); + ASSERT(m_currentAggregateSize == 1); +} + +void BinaryPropertyListPlan::writeBooleanTrue() +{ + ++m_currentAggregateSize; + if (m_booleanTrueObjectReference != invalidObjectReference()) + return; + m_booleanTrueObjectReference = m_currentObjectReference++; + ++m_byteCount; +} + +static inline int integerByteCount(size_t integer) +{ + if (integer <= 0xFF) + return 2; + if (integer <= 0xFFFF) + return 3; +#ifdef __LP64__ + if (integer <= 0xFFFFFFFFULL) + return 5; + return 9; +#else + return 5; +#endif +} + +void BinaryPropertyListPlan::writeInteger(int integer) +{ + ASSERT(integer >= 0); + ++m_currentAggregateSize; + if (!integer) { + if (m_integerZeroObjectReference != invalidObjectReference()) + return; + m_integerZeroObjectReference = m_currentObjectReference; + } else { + if (!m_integers.add(integer, m_currentObjectReference).second) + return; + } + ++m_currentObjectReference; + m_byteCount += integerByteCount(integer); +} + +void BinaryPropertyListPlan::writeString(const String& string) +{ + ++m_currentAggregateSize; + if (!m_strings.add(string, m_currentObjectReference).second) + return; + ++m_currentObjectReference; + writeStringObject(string); +} + +void BinaryPropertyListPlan::writeIntegerArray(const int* integers, size_t size) +{ + size_t savedAggregateSize = ++m_currentAggregateSize; + ASSERT(size); + pair<IntegerArrayMap::iterator, bool> addResult = m_integerArrays.add(IntegerArray(integers, size), 0); + if (!addResult.second) + return; + for (size_t i = 0; i < size; ++i) + writeInteger(integers[i]); + addResult.first->second = m_currentObjectReference++; + writeArrayObject(size); + m_currentAggregateSize = savedAggregateSize; +} + +void BinaryPropertyListPlan::writeUniqueString(const String& string) +{ + ++m_currentAggregateSize; + ++m_currentObjectReference; + writeStringObject(string); +} + +void BinaryPropertyListPlan::writeUniqueString(const char* string) +{ + ++m_currentAggregateSize; + ++m_currentObjectReference; + writeStringObject(string); +} + +size_t BinaryPropertyListPlan::writeArrayStart() +{ + size_t savedAggregateSize = m_currentAggregateSize; + m_currentAggregateSize = 0; + return savedAggregateSize; +} + +void BinaryPropertyListPlan::writeArrayEnd(size_t savedAggregateSize) +{ + ++m_currentObjectReference; + writeArrayObject(m_currentAggregateSize); + m_currentAggregateSize = savedAggregateSize + 1; +} + +size_t BinaryPropertyListPlan::writeDictionaryStart() +{ + size_t savedAggregateSize = m_currentAggregateSize; + m_currentAggregateSize = 0; + return savedAggregateSize; +} + +void BinaryPropertyListPlan::writeDictionaryEnd(size_t savedAggregateSize) +{ + ++m_currentObjectReference; + writeDictionaryObject(m_currentAggregateSize); + m_currentAggregateSize = savedAggregateSize + 1; +} + +static size_t markerPlusLengthByteCount(size_t length) +{ + if (length <= maxLengthInMarkerByte) + return 1; + return 1 + integerByteCount(length); +} + +void BinaryPropertyListPlan::writeStringObject(const String& string) +{ + const UChar* characters = string.characters(); + unsigned length = string.length(); + m_byteCount += markerPlusLengthByteCount(length) + length; + if (!charactersAreAllASCII(characters, length)) + m_byteCount += length; +} + +void BinaryPropertyListPlan::writeStringObject(const char* string) +{ + unsigned length = strlen(string); + m_byteCount += markerPlusLengthByteCount(length) + length; +} + +void BinaryPropertyListPlan::writeArrayObject(size_t size) +{ + ASSERT(size); + m_byteCount += markerPlusLengthByteCount(size); + m_objectReferenceCount += size; +} + +void BinaryPropertyListPlan::writeDictionaryObject(size_t size) +{ + ASSERT(size); + ASSERT(!(size & 1)); + m_byteCount += markerPlusLengthByteCount(size / 2); + m_objectReferenceCount += size; +} + +ObjectReference BinaryPropertyListPlan::booleanTrueObjectReference() const +{ + ASSERT(m_booleanTrueObjectReference != invalidObjectReference()); + return m_booleanTrueObjectReference; +} + +ObjectReference BinaryPropertyListPlan::integerObjectReference(int integer) const +{ + ASSERT(integer >= 0); + if (!integer) { + ASSERT(m_integerZeroObjectReference != invalidObjectReference()); + return m_integerZeroObjectReference; + } + ASSERT(m_integers.contains(integer)); + return m_integers.get(integer); +} + +ObjectReference BinaryPropertyListPlan::stringObjectReference(const String& string) const +{ + ASSERT(m_strings.contains(string)); + return m_strings.get(string); +} + +ObjectReference BinaryPropertyListPlan::integerArrayObjectReference(const int* integers, size_t size) const +{ + ASSERT(m_integerArrays.contains(IntegerArray(integers, size))); + return m_integerArrays.get(IntegerArray(integers, size)); +} + +class BinaryPropertyListSerializer : private BinaryPropertyListObjectStream { +public: + BinaryPropertyListSerializer(BinaryPropertyListWriter&); + +private: + virtual void writeBooleanTrue(); + virtual void writeInteger(int); + virtual void writeString(const String&); + virtual void writeIntegerArray(const int*, size_t); + virtual void writeUniqueString(const String&); + virtual void writeUniqueString(const char*); + virtual size_t writeArrayStart(); + virtual void writeArrayEnd(size_t); + virtual size_t writeDictionaryStart(); + virtual void writeDictionaryEnd(size_t); + + ObjectReference writeIntegerWithoutAddingAggregateObjectReference(int); + + void appendIntegerObject(int); + void appendStringObject(const String&); + void appendStringObject(const char*); + void appendIntegerArrayObject(const int*, size_t); + + void appendByte(unsigned char); + void appendByte(unsigned); + void appendByte(unsigned long); + void appendByte(int); + + void appendInteger(size_t); + + void appendObjectReference(ObjectReference); + + void addAggregateObjectReference(ObjectReference); + + void startObject(); + + const BinaryPropertyListPlan m_plan; + const int m_objectReferenceSize; + const size_t m_offsetTableStart; + const int m_offsetSize; + const size_t m_bufferSize; + UInt8* const m_buffer; + + UInt8* m_currentByte; + ObjectReference m_currentObjectReference; + UInt8* m_currentAggregateBufferByte; +}; + +inline void BinaryPropertyListSerializer::appendByte(unsigned char byte) +{ + *m_currentByte++ = byte; + ASSERT(m_currentByte <= m_currentAggregateBufferByte); +} + +inline void BinaryPropertyListSerializer::appendByte(unsigned byte) +{ + *m_currentByte++ = byte; + ASSERT(m_currentByte <= m_currentAggregateBufferByte); +} + +inline void BinaryPropertyListSerializer::appendByte(unsigned long byte) +{ + *m_currentByte++ = byte; + ASSERT(m_currentByte <= m_currentAggregateBufferByte); +} + +inline void BinaryPropertyListSerializer::appendByte(int byte) +{ + *m_currentByte++ = byte; + ASSERT(m_currentByte <= m_currentAggregateBufferByte); +} + +static int bytesNeeded(size_t count) +{ + ASSERT(count); + int bytesNeeded = 1; + for (size_t mask = numeric_limits<size_t>::max() << 8; count & mask; mask <<= 8) + ++bytesNeeded; + return bytesNeeded; +} + +static inline void storeLength(UInt8* destination, size_t length) +{ +#ifdef __LP64__ + destination[0] = length >> 56; + destination[1] = length >> 48; + destination[2] = length >> 40; + destination[3] = length >> 32; +#else + destination[0] = 0; + destination[1] = 0; + destination[2] = 0; + destination[3] = 0; +#endif + destination[4] = length >> 24; + destination[5] = length >> 16; + destination[6] = length >> 8; + destination[7] = length; +} + +// Like memmove, but reverses the bytes. +static void moveAndReverseBytes(UInt8* destination, const UInt8* source, size_t length) +{ + ASSERT(length); + memmove(destination, source, length); + UInt8* start = destination; + UInt8* end = destination + length; + while (end - start > 1) + std::swap(*start++, *--end); +} + +// The serializer uses a single buffer for the property list. +// The buffer contains: +// +// 8-byte header +// object data +// offset table +// 32-byte trailer +// +// While serializing object, the offset table entry for each object is written just before +// the object data for that object is written. Aggregates, arrays and dictionaries, are a +// special case. The objects that go into an aggregate are written before the aggregate is. +// As each object is written, the object reference is put in the aggregate buffer. Then, +// when the aggregate is written, the aggregate buffer is copied into place in the object +// data. Finally, the header and trailer are written. +// +// The aggregate buffer shares space with the object data, like this: +// +// 8-byte header +// object data +// >>> aggregate buffer <<< +// offset table +// 32-byte trailer +// +// To make it easy to build it incrementally, the buffer starts at the end of the object +// data space, and grows backwards. We're guaranteed the aggregate buffer will never collide +// with the object data pointer because we know that the object data is correctly sized +// based on our plan, and all the data in the aggregate buffer will be used to create the +// actual aggregate objects; in the worst case the aggregate buffer will already be in +// exactly the right place, but backwards. + +BinaryPropertyListSerializer::BinaryPropertyListSerializer(BinaryPropertyListWriter& client) + : m_plan(client) + , m_objectReferenceSize(bytesNeeded(m_plan.objectCount())) + , m_offsetTableStart(headerSize + m_plan.byteCount() + m_plan.objectReferenceCount() * m_objectReferenceSize) + , m_offsetSize(bytesNeeded(m_offsetTableStart)) + , m_bufferSize(m_offsetTableStart + m_plan.objectCount() * m_offsetSize + trailerSize) + , m_buffer(client.buffer(m_bufferSize)) + , m_currentObjectReference(0) +{ + ASSERT(m_objectReferenceSize > 0); + ASSERT(m_offsetSize > 0); + +#ifdef __LP64__ + ASSERT(m_objectReferenceSize <= 8); + ASSERT(m_offsetSize <= 8); +#else + ASSERT(m_objectReferenceSize <= 4); + ASSERT(m_offsetSize <= 4); +#endif + + if (!m_buffer) + return; + + // Write objects and offset table. + m_currentByte = m_buffer + headerSize; + m_currentAggregateBufferByte = m_buffer + m_offsetTableStart; + client.writeObjects(*this); + ASSERT(m_currentObjectReference == m_plan.objectCount()); + ASSERT(m_currentAggregateBufferByte == m_buffer + m_offsetTableStart); + ASSERT(m_currentByte == m_buffer + m_offsetTableStart); + + // Write header. + memcpy(m_buffer, "bplist00", headerSize); + + // Write trailer. + UInt8* trailer = m_buffer + m_bufferSize - trailerSize; + memset(trailer, 0, 6); + trailer[6] = m_offsetSize; + trailer[7] = m_objectReferenceSize; + storeLength(trailer + 8, m_plan.objectCount()); + storeLength(trailer + 16, m_plan.objectCount() - 1); + storeLength(trailer + 24, m_offsetTableStart); +} + +void BinaryPropertyListSerializer::writeBooleanTrue() +{ + ObjectReference reference = m_plan.booleanTrueObjectReference(); + if (m_currentObjectReference != reference) + ASSERT(reference < m_currentObjectReference); + else { + startObject(); + appendByte(booleanTrueMarkerByte); + } + addAggregateObjectReference(reference); +} + +inline ObjectReference BinaryPropertyListSerializer::writeIntegerWithoutAddingAggregateObjectReference(int integer) +{ + ObjectReference reference = m_plan.integerObjectReference(integer); + if (m_currentObjectReference != reference) + ASSERT(reference < m_currentObjectReference); + else + appendIntegerObject(integer); + return reference; +} + +void BinaryPropertyListSerializer::writeInteger(int integer) +{ + addAggregateObjectReference(writeIntegerWithoutAddingAggregateObjectReference(integer)); +} + +void BinaryPropertyListSerializer::writeString(const String& string) +{ + ObjectReference reference = m_plan.stringObjectReference(string); + if (m_currentObjectReference != reference) + ASSERT(reference < m_currentObjectReference); + else + appendStringObject(string); + addAggregateObjectReference(reference); +} + +void BinaryPropertyListSerializer::writeIntegerArray(const int* integers, size_t size) +{ + ObjectReference reference = m_plan.integerArrayObjectReference(integers, size); + for (size_t i = 0; i < size; ++i) + writeIntegerWithoutAddingAggregateObjectReference(integers[i]); + if (m_currentObjectReference != reference) + ASSERT(reference < m_currentObjectReference); + else + appendIntegerArrayObject(integers, size); + addAggregateObjectReference(reference); +} + +void BinaryPropertyListSerializer::writeUniqueString(const char* string) +{ + addAggregateObjectReference(m_currentObjectReference); + appendStringObject(string); +} + +void BinaryPropertyListSerializer::writeUniqueString(const String& string) +{ + addAggregateObjectReference(m_currentObjectReference); + appendStringObject(string); +} + +size_t BinaryPropertyListSerializer::writeArrayStart() +{ + return m_currentAggregateBufferByte - m_buffer; +} + +void BinaryPropertyListSerializer::writeArrayEnd(size_t savedAggregateBufferOffset) +{ + ObjectReference reference = m_currentObjectReference; + startObject(); + size_t aggregateBufferByteCount = savedAggregateBufferOffset - (m_currentAggregateBufferByte - m_buffer); + ASSERT(aggregateBufferByteCount); + ASSERT(!(aggregateBufferByteCount % m_objectReferenceSize)); + size_t size = aggregateBufferByteCount / m_objectReferenceSize; + if (size <= maxLengthInMarkerByte) + appendByte(arrayMarkerByte | size); + else { + appendByte(arrayWithSeparateLengthMarkerByte); + appendInteger(size); + } + m_currentAggregateBufferByte = m_buffer + savedAggregateBufferOffset; + ASSERT(m_currentByte <= m_currentAggregateBufferByte); + moveAndReverseBytes(m_currentByte, m_currentAggregateBufferByte - aggregateBufferByteCount, aggregateBufferByteCount); + m_currentByte += aggregateBufferByteCount; + ASSERT(m_currentByte <= m_currentAggregateBufferByte); + if (m_currentObjectReference < m_plan.objectCount()) + addAggregateObjectReference(reference); + else + ASSERT(m_currentObjectReference == m_plan.objectCount()); +} + +size_t BinaryPropertyListSerializer::writeDictionaryStart() +{ + return m_currentAggregateBufferByte - m_buffer; +} + +void BinaryPropertyListSerializer::writeDictionaryEnd(size_t savedAggregateBufferOffset) +{ + ObjectReference reference = m_currentObjectReference; + startObject(); + size_t aggregateBufferByteCount = savedAggregateBufferOffset - (m_currentAggregateBufferByte - m_buffer); + ASSERT(aggregateBufferByteCount); + ASSERT(!(aggregateBufferByteCount % (m_objectReferenceSize * 2))); + size_t size = aggregateBufferByteCount / (m_objectReferenceSize * 2); + if (size <= maxLengthInMarkerByte) + appendByte(dictionaryMarkerByte | size); + else { + appendByte(dictionaryWithSeparateLengthMarkerByte); + appendInteger(size); + } + m_currentAggregateBufferByte = m_buffer + savedAggregateBufferOffset; + ASSERT(m_currentByte <= m_currentAggregateBufferByte); + moveAndReverseBytes(m_currentByte, m_currentAggregateBufferByte - aggregateBufferByteCount, aggregateBufferByteCount); + m_currentByte += aggregateBufferByteCount; + ASSERT(m_currentByte <= m_currentAggregateBufferByte); + if (m_currentObjectReference != m_plan.objectCount()) + addAggregateObjectReference(reference); + else + ASSERT(m_currentObjectReference == m_plan.objectCount()); +} + +void BinaryPropertyListSerializer::appendIntegerObject(int integer) +{ + startObject(); + ASSERT(integer >= 0); + appendInteger(integer); +} + +void BinaryPropertyListSerializer::appendInteger(size_t integer) +{ + if (integer <= 0xFF) { + appendByte(oneByteIntegerMarkerByte); + appendByte(integer); + return; + } + if (integer <= 0xFFFF) { + appendByte(twoByteIntegerMarkerByte); + appendByte(integer >> 8); + appendByte(integer); + return; + } +#ifdef __LP64__ + if (integer <= 0xFFFFFFFFULL) { +#endif + appendByte(fourByteIntegerMarkerByte); + appendByte(integer >> 24); + appendByte(integer >> 16); + appendByte(integer >> 8); + appendByte(integer); +#ifdef __LP64__ + return; + } + appendByte(eightByteIntegerMarkerByte); + appendByte(integer >> 56); + appendByte(integer >> 48); + appendByte(integer >> 40); + appendByte(integer >> 32); + appendByte(integer >> 24); + appendByte(integer >> 16); + appendByte(integer >> 8); + appendByte(integer); +#endif +} + +void BinaryPropertyListSerializer::appendStringObject(const String& string) +{ + startObject(); + const UChar* characters = string.characters(); + unsigned length = string.length(); + if (charactersAreAllASCII(characters, length)) { + if (length <= maxLengthInMarkerByte) + appendByte(asciiStringMarkerByte | length); + else { + appendByte(asciiStringWithSeparateLengthMarkerByte); + appendInteger(length); + } + for (unsigned i = 0; i < length; ++i) + appendByte(characters[i]); + } else { + if (length <= maxLengthInMarkerByte) + appendByte(unicodeStringMarkerByte | length); + else { + appendByte(unicodeStringWithSeparateLengthMarkerByte); + appendInteger(length); + } + for (unsigned i = 0; i < length; ++i) { + appendByte(characters[i] >> 8); + appendByte(characters[i]); + } + } +} + +void BinaryPropertyListSerializer::appendStringObject(const char* string) +{ + startObject(); + unsigned length = strlen(string); + if (length <= maxLengthInMarkerByte) + appendByte(asciiStringMarkerByte | length); + else { + appendByte(asciiStringWithSeparateLengthMarkerByte); + appendInteger(length); + } + for (unsigned i = 0; i < length; ++i) + appendByte(string[i]); +} + +void BinaryPropertyListSerializer::appendIntegerArrayObject(const int* integers, size_t size) +{ + startObject(); + if (size <= maxLengthInMarkerByte) + appendByte(arrayMarkerByte | size); + else { + appendByte(arrayWithSeparateLengthMarkerByte); + appendInteger(size); + } + for (unsigned i = 0; i < size; ++i) + appendObjectReference(m_plan.integerObjectReference(integers[i])); +} + +void BinaryPropertyListSerializer::appendObjectReference(ObjectReference reference) +{ + switch (m_objectReferenceSize) { +#ifdef __LP64__ + case 8: + appendByte(reference >> 56); + case 7: + appendByte(reference >> 48); + case 6: + appendByte(reference >> 40); + case 5: + appendByte(reference >> 32); +#endif + case 4: + appendByte(reference >> 24); + case 3: + appendByte(reference >> 16); + case 2: + appendByte(reference >> 8); + case 1: + appendByte(reference); + } +} + +void BinaryPropertyListSerializer::startObject() +{ + ObjectReference reference = m_currentObjectReference++; + + size_t offset = m_currentByte - m_buffer; + + UInt8* offsetTableEntry = m_buffer + m_offsetTableStart + reference * m_offsetSize + m_offsetSize; + switch (m_offsetSize) { +#ifdef __LP64__ + case 8: + offsetTableEntry[-8] = offset >> 56; + case 7: + offsetTableEntry[-7] = offset >> 48; + case 6: + offsetTableEntry[-6] = offset >> 40; + case 5: + offsetTableEntry[-5] = offset >> 32; +#endif + case 4: + offsetTableEntry[-4] = offset >> 24; + case 3: + offsetTableEntry[-3] = offset >> 16; + case 2: + offsetTableEntry[-2] = offset >> 8; + case 1: + offsetTableEntry[-1] = offset; + } +} + +void BinaryPropertyListSerializer::addAggregateObjectReference(ObjectReference reference) +{ + switch (m_objectReferenceSize) { +#ifdef __LP64__ + case 8: + *--m_currentAggregateBufferByte = reference >> 56; + case 7: + *--m_currentAggregateBufferByte = reference >> 48; + case 6: + *--m_currentAggregateBufferByte = reference >> 40; + case 5: + *--m_currentAggregateBufferByte = reference >> 32; +#endif + case 4: + *--m_currentAggregateBufferByte = reference >> 24; + case 3: + *--m_currentAggregateBufferByte = reference >> 16; + case 2: + *--m_currentAggregateBufferByte = reference >> 8; + case 1: + *--m_currentAggregateBufferByte = reference; + } + ASSERT(m_currentByte <= m_currentAggregateBufferByte); +} + +void BinaryPropertyListWriter::writePropertyList() +{ + BinaryPropertyListSerializer(*this); +} + +} diff --git a/WebCore/platform/cf/BinaryPropertyList.h b/WebCore/platform/cf/BinaryPropertyList.h new file mode 100644 index 0000000..598aaa7 --- /dev/null +++ b/WebCore/platform/cf/BinaryPropertyList.h @@ -0,0 +1,108 @@ +/* + * 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 BinaryPropertyList_h +#define BinaryPropertyList_h + +#include <wtf/Vector.h> + +namespace WebCore { + +class String; + +// Writes a limited subset of binary property lists. +// Covers only what's needed for writing browser history as of this writing. +class BinaryPropertyListObjectStream { +public: + // Call writeBooleanTrue to write the boolean true value. + // A single shared object will be used in the serialized list. + virtual void writeBooleanTrue() = 0; + + // Call writeInteger to write an integer value. + // A single shared object will be used for each integer in the serialized list. + virtual void writeInteger(int) = 0; + + // Call writeString to write a string value. + // A single shared object will be used for each string in the serialized list. + virtual void writeString(const String&) = 0; + + // Call writeUniqueString instead of writeString when it's unlikely the + // string will be written twice in the same property list; this saves hash + // table overhead for such strings. A separate object will be used for each + // of these strings in the serialized list. + virtual void writeUniqueString(const String&) = 0; + virtual void writeUniqueString(const char*) = 0; + + // Call writeIntegerArray instead of writeArrayStart/writeArrayEnd for + // arrays entirely composed of integers. A single shared object will be used + // for each identical array in the serialized list. Warning: The integer + // pointer must remain valid until the writeBinaryPropertyList function + // returns, because these lists are put into a hash table without copying + // them -- that's OK if the client already has a Vector<int>. + virtual void writeIntegerArray(const int*, size_t) = 0; + + // After calling writeArrayStart, write array elements. + // Then call writeArrayEnd, passing in the result from writeArrayStart. + // A separate object will be used for each of these arrays in the serialized list. + virtual size_t writeArrayStart() = 0; + virtual void writeArrayEnd(size_t resultFromWriteArrayStart) = 0; + + // After calling writeDictionaryStart, write all keys, then all values. + // Then call writeDictionaryEnd, passing in the result from writeDictionaryStart. + // A separate object will be used for each dictionary in the serialized list. + virtual size_t writeDictionaryStart() = 0; + virtual void writeDictionaryEnd(size_t resultFromWriteDictionaryStart) = 0; + +protected: + virtual ~BinaryPropertyListObjectStream() { } +}; + +class BinaryPropertyListWriter { +public: + // Calls writeObjects once to prepare for writing and determine how big a + // buffer is required. Then calls buffer to get the appropriately-sized + // buffer, then calls writeObjects a second time and writes the property list. + void writePropertyList(); + +protected: + virtual ~BinaryPropertyListWriter() { } + +private: + // Called by writePropertyList. + // Must call the object stream functions for the objects to be written + // into the property list. + virtual void writeObjects(BinaryPropertyListObjectStream&) = 0; + + // Called by writePropertyList. + // Returns the buffer that the writer should write into. + virtual UInt8* buffer(size_t) = 0; + + friend class BinaryPropertyListPlan; + friend class BinaryPropertyListSerializer; +}; + +} + +#endif diff --git a/WebCore/platform/cf/SharedBufferCF.cpp b/WebCore/platform/cf/SharedBufferCF.cpp index 7213c7e..26fc07f 100644 --- a/WebCore/platform/cf/SharedBufferCF.cpp +++ b/WebCore/platform/cf/SharedBufferCF.cpp @@ -51,6 +51,11 @@ CFDataRef SharedBuffer::createCFData() } #endif +PassRefPtr<SharedBuffer> SharedBuffer::wrapCFData(CFDataRef data) +{ + return adoptRef(new SharedBuffer(data)); +} + bool SharedBuffer::hasPlatformData() const { return m_cfData; diff --git a/WebCore/platform/chromium/ChromiumBridge.h b/WebCore/platform/chromium/ChromiumBridge.h index 3e5c404..75e9103 100644 --- a/WebCore/platform/chromium/ChromiumBridge.h +++ b/WebCore/platform/chromium/ChromiumBridge.h @@ -76,8 +76,8 @@ namespace WebCore { static void clipboardWriteImage(const NativeImageSkia*, const KURL&, const String&); // Cookies ------------------------------------------------------------ - static void setCookies(const KURL& url, const KURL& policyURL, const String& value); - static String cookies(const KURL& url, const KURL& policyURL); + static void setCookies(const KURL& url, const KURL& firstPartyForCookies, const String& value); + static String cookies(const KURL& url, const KURL& firstPartyForCookies); // DNS ---------------------------------------------------------------- static void prefetchDNS(const String& hostname); @@ -135,6 +135,9 @@ namespace WebCore { static void decrementStatsCounter(const char* name); static void incrementStatsCounter(const char* name); + // Sudden Termination + static void suddenTerminationChanged(bool enabled); + // SystemTime --------------------------------------------------------- static double currentTime(); diff --git a/WebCore/platform/chromium/ClipboardChromium.cpp b/WebCore/platform/chromium/ClipboardChromium.cpp index b28503d..8f9ac7f 100644 --- a/WebCore/platform/chromium/ClipboardChromium.cpp +++ b/WebCore/platform/chromium/ClipboardChromium.cpp @@ -35,8 +35,10 @@ #include "Element.h" #include "Frame.h" #include "HTMLNames.h" +#include "NamedAttrMap.h" #include "MIMETypeRegistry.h" #include "markup.h" +#include "NamedNodeMap.h" #include "PlatformString.h" #include "Range.h" #include "RenderImage.h" @@ -216,7 +218,7 @@ static String imageToMarkup(const String& url, Element* element) markup.append("\""); // Copy over attributes. If we are dragging an image, we expect things like // the id to be copied as well. - NamedAttrMap* attrs = element->attributes(); + NamedNodeMap* attrs = element->attributes(); unsigned length = attrs->length(); for (unsigned i = 0; i < length; ++i) { Attribute* attr = attrs->attributeItem(i); diff --git a/WebCore/platform/chromium/ClipboardChromium.h b/WebCore/platform/chromium/ClipboardChromium.h index 53699da..0a83fd4 100644 --- a/WebCore/platform/chromium/ClipboardChromium.h +++ b/WebCore/platform/chromium/ClipboardChromium.h @@ -82,7 +82,6 @@ namespace WebCore { void resetFromClipboard(); void setDragImage(CachedImage*, Node*, const IntPoint&); RefPtr<ChromiumDataObject> m_dataObject; - Frame* m_frame; }; } // namespace WebCore diff --git a/WebCore/platform/chromium/KeyCodeConversionGtk.cpp b/WebCore/platform/chromium/KeyCodeConversionGtk.cpp index a3efe44..4fc7f32 100644 --- a/WebCore/platform/chromium/KeyCodeConversionGtk.cpp +++ b/WebCore/platform/chromium/KeyCodeConversionGtk.cpp @@ -150,9 +150,10 @@ int windowsKeyCodeForKeyEvent(unsigned keycode) case GDK_Help: return VKEY_HELP; // (2F) HELP key case GDK_0: - case GDK_parenleft: + case GDK_parenright: return VKEY_0; // (30) 0) key case GDK_1: + case GDK_exclam: return VKEY_1; // (31) 1 ! key case GDK_2: case GDK_at: @@ -176,7 +177,7 @@ int windowsKeyCodeForKeyEvent(unsigned keycode) case GDK_asterisk: return VKEY_8; // (38) 8 key '*' case GDK_9: - case GDK_parenright: + case GDK_parenleft: return VKEY_9; // (39) 9 key '(' case GDK_a: case GDK_A: diff --git a/WebCore/platform/chromium/MimeTypeRegistryChromium.cpp b/WebCore/platform/chromium/MimeTypeRegistryChromium.cpp index 1aac5ec..0f371b1 100644 --- a/WebCore/platform/chromium/MimeTypeRegistryChromium.cpp +++ b/WebCore/platform/chromium/MimeTypeRegistryChromium.cpp @@ -127,6 +127,11 @@ bool MIMETypeRegistry::isJavaAppletMIMEType(const String& mimeType) || mimeType.startsWith("application/x-java-vm", false); } +String MIMETypeRegistry::getMediaMIMETypeForExtension(const String&) +{ + return String(); +} + static HashSet<String>& dummyHashSet() { ASSERT_NOT_REACHED(); diff --git a/WebCore/platform/chromium/PopupMenuChromium.cpp b/WebCore/platform/chromium/PopupMenuChromium.cpp index 53f565a..1be075d 100644 --- a/WebCore/platform/chromium/PopupMenuChromium.cpp +++ b/WebCore/platform/chromium/PopupMenuChromium.cpp @@ -136,32 +136,26 @@ public: // Returns whether the popup wants to process events for the passed key. bool isInterestedInEventForKey(int keyCode); + // Gets the height of a row. + int getRowHeight(int index); + + // Returns true if the selection can be changed to index. + // Disabled items, or labels cannot be selected. + bool isSelectableItem(int index); + + const Vector<PopupItem*>& items() const { return m_items; } + private: friend class PopupContainer; friend class RefCounted<PopupListBox>; - // A type of List Item - enum ListItemType { - TypeOption, - TypeGroup, - TypeSeparator - }; - - // A item (represented by <option> or <optgroup>) in the <select> widget. - struct ListItem { - ListItem(const String& label, ListItemType type) - : label(label.copy()), type(type), y(0) {} - String label; - ListItemType type; - int y; // y offset of this item, relative to the top of the popup. - }; - PopupListBox(PopupMenuClient* client, const PopupContainerSettings& settings) : m_settings(settings) , m_originalIndex(0) , m_selectedIndex(0) - , m_willAcceptOnAbandon(false) + , m_acceptedIndexOnAbandon(-1) , m_visibleRows(0) + , m_baseWidth(0) , m_popupClient(client) , m_repeatingChar(0) , m_lastCharTime(0) @@ -184,10 +178,6 @@ private: // the web page, and closes the popup. void acceptIndex(int index); - // Returns true if the selection can be changed to index. - // Disabled items, or labels cannot be selected. - bool isSelectableItem(int index); - // Clears the selection (so no row appears selected). void clearSelection(); @@ -198,8 +188,6 @@ private: // Invalidates the row at the given index. void invalidateRow(int index); - // Gets the height of a row. - int getRowHeight(int index); // Get the bounds of a row. IntRect getRowBounds(int index); @@ -235,11 +223,11 @@ private: // enter yet however. int m_selectedIndex; - // True if we should accept the selectedIndex as chosen, even if the popup - // is "abandoned". This is used for keyboard navigation, where we want the + // If >= 0, this is the index we should accept if the popup is "abandoned". + // This is used for keyboard navigation, where we want the // selection to change immediately, and is only used if the settings // acceptOnAbandon field is true. - bool m_willAcceptOnAbandon; + int m_acceptedIndexOnAbandon; // This is the number of rows visible in the popup. The maximum number visible at a time is // defined as being kMaxVisibleRows. For a scrolled popup, this can be thought of as the @@ -250,7 +238,7 @@ private: int m_baseWidth; // A list of the options contained within the <select> - Vector<ListItem*> m_items; + Vector<PopupItem*> m_items; // The <select> PopupMenuClient that opened us. PopupMenuClient* m_popupClient; @@ -310,7 +298,8 @@ PassRefPtr<PopupContainer> PopupContainer::create(PopupMenuClient* client, return adoptRef(new PopupContainer(client, settings)); } -PopupContainer::PopupContainer(PopupMenuClient* client, const PopupContainerSettings& settings) +PopupContainer::PopupContainer(PopupMenuClient* client, + const PopupContainerSettings& settings) : m_listBox(PopupListBox::create(client, settings)) , m_settings(settings) { @@ -319,7 +308,7 @@ PopupContainer::PopupContainer(PopupMenuClient* client, const PopupContainerSett PopupContainer::~PopupContainer() { - if (m_listBox) + if (m_listBox && m_listBox->parent()) removeChild(m_listBox.get()); } @@ -342,7 +331,7 @@ void PopupContainer::showPopup(FrameView* view) if (widgetRect.bottom() > static_cast<int>(screen.bottom())) widgetRect.move(0, -(widgetRect.height() + selectHeight)); - chromeClient->popupOpened(this, widgetRect, m_settings.focusOnShow); + chromeClient->popupOpened(this, widgetRect, m_settings.focusOnShow, false); } if (!m_listBox->parent()) @@ -357,6 +346,29 @@ void PopupContainer::showPopup(FrameView* view) invalidate(); } +void PopupContainer::showExternal(const IntRect& rect, FrameView* v, int index) +{ + if (!listBox()) + return; + + listBox()->setBaseWidth(rect.width()); + listBox()->updateFromElement(); + + if (listBox()->numItems() < 1) { + hidePopup(); + return; + } + + // Adjust the popup position to account for scrolling. + IntPoint location = v->contentsToWindow(rect.location()); + IntRect popupRect(location, rect.size()); + + // Get the ChromeClient and pass it the popup menu's listbox data. + ChromeClientChromium* client = static_cast<ChromeClientChromium*>( + v->frame()->page()->chrome()->client()); + client->popupOpened(this, popupRect, true, true); +} + void PopupContainer::hidePopup() { if (client()) @@ -485,6 +497,16 @@ int PopupContainer::selectedIndex() const return m_listBox->selectedIndex(); } +int PopupContainer::menuItemHeight() const +{ + return m_listBox->getRowHeight(0); +} + +const WTF::Vector<PopupItem*>& PopupContainer:: popupData() const +{ + return m_listBox->items(); +} + /////////////////////////////////////////////////////////////////////////////// // PopupListBox implementation @@ -628,7 +650,7 @@ bool PopupListBox::handleKeyEvent(const PlatformKeyboardEvent& event) // IE). We change the original index so we revert to that when the // popup is closed. if (m_settings.acceptOnAbandon) - m_willAcceptOnAbandon = true; + m_acceptedIndexOnAbandon = m_selectedIndex; setOriginalIndex(m_selectedIndex); if (m_settings.setTextOnIndexChange) @@ -797,7 +819,7 @@ void PopupListBox::paintRow(GraphicsContext* gc, const IntRect& rect, int rowInd Font PopupListBox::getRowFont(int rowIndex) { - Font itemFont = m_popupClient->itemStyle(rowIndex).font(); + Font itemFont = m_popupClient->menuStyle().font(); if (m_popupClient->itemIsLabel(rowIndex)) { // Bold-ify labels (ie, an <optgroup> heading). FontDescription d = itemFont.fontDescription(); @@ -818,8 +840,10 @@ void PopupListBox::abandon() m_popupClient->hidePopup(); - if (m_willAcceptOnAbandon) - m_popupClient->valueChanged(m_selectedIndex); + if (m_acceptedIndexOnAbandon >= 0) { + m_popupClient->valueChanged(m_acceptedIndexOnAbandon); + m_acceptedIndexOnAbandon = -1; + } } int PopupListBox::pointToRowIndex(const IntPoint& point) @@ -828,7 +852,7 @@ int PopupListBox::pointToRowIndex(const IntPoint& point) // FIXME: binary search if perf matters. for (int i = 0; i < numItems(); ++i) { - if (y < m_items[i]->y) + if (y < m_items[i]->yOffset) return i-1; } @@ -890,7 +914,7 @@ IntRect PopupListBox::getRowBounds(int index) if (index < 0) return IntRect(0, 0, visibleWidth(), getRowHeight(index)); - return IntRect(0, m_items[index]->y, visibleWidth(), getRowHeight(index)); + return IntRect(0, m_items[index]->yOffset, visibleWidth(), getRowHeight(index)); } void PopupListBox::invalidateRow(int index) @@ -921,7 +945,7 @@ void PopupListBox::scrollToRevealRow(int index) bool PopupListBox::isSelectableItem(int index) { - return m_items[index]->type == TypeOption && m_popupClient->itemIsEnabled(index); + return m_items[index]->type == PopupItem::TypeOption && m_popupClient->itemIsEnabled(index); } void PopupListBox::clearSelection() @@ -998,26 +1022,19 @@ void PopupListBox::adjustSelectedIndex(int delta) void PopupListBox::updateFromElement() { - // It happens when pressing a key to jump to an item, then use tab or - // mouse to get away from the select box. In that case, updateFromElement - // is called before abandon, which causes discarding of the select result. - if (m_willAcceptOnAbandon) { - m_popupClient->valueChanged(m_selectedIndex); - m_willAcceptOnAbandon = false; - } - clear(); int size = m_popupClient->listSize(); for (int i = 0; i < size; ++i) { - ListItemType type; + PopupItem::Type type; if (m_popupClient->itemIsSeparator(i)) - type = PopupListBox::TypeSeparator; + type = PopupItem::TypeSeparator; else if (m_popupClient->itemIsLabel(i)) - type = PopupListBox::TypeGroup; + type = PopupItem::TypeGroup; else - type = PopupListBox::TypeOption; - m_items.append(new ListItem(m_popupClient->itemText(i), type)); + type = PopupItem::TypeOption; + m_items.append(new PopupItem(m_popupClient->itemText(i), type)); + m_items[i]->enabled = isSelectableItem(i); } m_selectedIndex = m_popupClient->selectedIndex(); @@ -1036,7 +1053,7 @@ void PopupListBox::layout() Font itemFont = getRowFont(i); // Place the item vertically. - m_items[i]->y = y; + m_items[i]->yOffset = y; y += itemFont.height(); // Ensure the popup is wide enough to fit this item. @@ -1051,13 +1068,26 @@ void PopupListBox::layout() } int windowHeight = 0; + +#if PLATFORM(DARWIN) + // Set the popup's window to contain all available items on Mac only, which + // uses native controls that manage their own scrolling. This allows hit + // testing to work when selecting items in popups that have more menu entries + // than the maximum window size. + m_visibleRows = numItems(); +#else m_visibleRows = min(numItems(), kMaxVisibleRows); +#endif + for (int i = 0; i < m_visibleRows; ++i) { int rowHeight = getRowHeight(i); +#if !PLATFORM(DARWIN) + // Only clip the window height for non-Mac platforms. if (windowHeight + rowHeight > kMaxHeight) { m_visibleRows = i; break; } +#endif windowHeight += rowHeight; } @@ -1088,7 +1118,7 @@ void PopupListBox::layout() void PopupListBox::clear() { - for (Vector<ListItem*>::iterator it = m_items.begin(); it != m_items.end(); ++it) + for (Vector<PopupItem*>::iterator it = m_items.begin(); it != m_items.end(); ++it) delete *it; m_items.clear(); } @@ -1115,11 +1145,19 @@ PopupMenu::~PopupMenu() hide(); } -void PopupMenu::show(const IntRect& r, FrameView* v, int index) +// The Mac Chromium implementation relies on external control (a Cocoa control) +// to display, handle the input tracking and menu item selection for the popup. +// Windows and Linux Chromium let our WebKit port handle the display, while +// another process manages the popup window and input handling. +void PopupMenu::show(const IntRect& r, FrameView* v, int index) { if (!p.popup) p.popup = PopupContainer::create(client(), dropDownSettings); +#if PLATFORM(DARWIN) + p.popup->showExternal(r, v, index); +#else p.popup->show(r, v, index); +#endif } void PopupMenu::hide() diff --git a/WebCore/platform/chromium/PopupMenuChromium.h b/WebCore/platform/chromium/PopupMenuChromium.h index cd13c22..23003b1 100644 --- a/WebCore/platform/chromium/PopupMenuChromium.h +++ b/WebCore/platform/chromium/PopupMenuChromium.h @@ -42,6 +42,23 @@ namespace WebCore { class FrameView; class PopupListBox; + // A container for the data for each menu item (e.g. represented by <option> + // or <optgroup> in a <select> widget) and is used by PopupListBox. + struct PopupItem { + enum Type { + TypeOption, + TypeGroup, + TypeSeparator + }; + + PopupItem(const String& label, Type type) + : label(label), type(type), yOffset(0) { } + String label; + Type type; + int yOffset; // y offset of this item, relative to the top of the popup. + bool enabled; + }; + // FIXME: Our FramelessScrollView classes should probably implement HostWindow! // The PopupContainer class holds a PopupListBox (see cpp file). Its sole purpose is to be @@ -94,9 +111,14 @@ namespace WebCore { // Show the popup void showPopup(FrameView*); + // Used on Mac Chromium for HTML select popup menus. + void showExternal(const IntRect&, FrameView*, int index); + // Show the popup in the specified rect for the specified frame. // Note: this code was somehow arbitrarily factored-out of the Popup class - // so WebViewImpl can create a PopupContainer. + // so WebViewImpl can create a PopupContainer. This method is used for + // displaying auto complete popup menus on Mac Chromium, and for all + // popups on other platforms. void show(const IntRect&, FrameView*, int index); // Hide the popup. Do not call this directly: use client->hidePopup(). @@ -114,6 +136,12 @@ namespace WebCore { // Refresh the popup values from the PopupMenuClient. void refresh(); + // The menu per-item data. + const WTF::Vector<PopupItem*>& popupData() const; + + // The height of a row in the menu. + int menuItemHeight() const; + private: friend class WTF::RefCounted<PopupContainer>; diff --git a/WebCore/platform/chromium/ScrollbarThemeChromium.cpp b/WebCore/platform/chromium/ScrollbarThemeChromium.cpp index 426a078..78fc088 100644 --- a/WebCore/platform/chromium/ScrollbarThemeChromium.cpp +++ b/WebCore/platform/chromium/ScrollbarThemeChromium.cpp @@ -40,24 +40,6 @@ namespace WebCore { -ScrollbarTheme* ScrollbarTheme::nativeTheme() -{ - static ScrollbarThemeChromium theme; - return &theme; -} - -ScrollbarThemeChromium::ScrollbarThemeChromium() -{ -} - -ScrollbarThemeChromium::~ScrollbarThemeChromium() -{ -} - -void ScrollbarThemeChromium::themeChanged() -{ -} - bool ScrollbarThemeChromium::hasThumb(Scrollbar* scrollbar) { // This method is just called as a paint-time optimization to see if @@ -93,20 +75,6 @@ IntRect ScrollbarThemeChromium::forwardButtonRect(Scrollbar* scrollbar, Scrollba return IntRect(x, y, size.width(), size.height()); } -IntRect ScrollbarThemeChromium::trackRect(Scrollbar* scrollbar, bool) -{ - IntSize bs = buttonSize(scrollbar); - int thickness = scrollbarThickness(scrollbar->controlSize()); - if (scrollbar->orientation() == HorizontalScrollbar) { - if (scrollbar->width() < 2 * thickness) - return IntRect(); - return IntRect(scrollbar->x() + bs.width(), scrollbar->y(), scrollbar->width() - 2 * bs.width(), thickness); - } - if (scrollbar->height() < 2 * thickness) - return IntRect(); - return IntRect(scrollbar->x(), scrollbar->y() + bs.height(), thickness, scrollbar->height() - 2 * bs.height()); -} - void ScrollbarThemeChromium::paintTrackBackground(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect) { // Just assume a forward track part. We only paint the track as a single piece when there is no thumb. @@ -165,36 +133,4 @@ bool ScrollbarThemeChromium::shouldCenterOnThumb(Scrollbar*, const PlatformMouse return evt.shiftKey() && evt.button() == LeftButton; } -IntSize ScrollbarThemeChromium::buttonSize(Scrollbar* scrollbar) -{ -#if defined(__linux__) - // On Linux, we don't use buttons - return IntSize(0, 0); -#endif - - // Our desired rect is essentially thickness by thickness. - - // Our actual rect will shrink to half the available space when we have < 2 - // times thickness pixels left. This allows the scrollbar to scale down - // and function even at tiny sizes. - - int thickness = scrollbarThickness(scrollbar->controlSize()); - - // In layout test mode, we force the button "girth" (i.e., the length of - // the button along the axis of the scrollbar) to be a fixed size. - // FIXME: This is retarded! scrollbarThickness is already fixed in layout - // test mode so that should be enough to result in repeatable results, but - // preserving this hack avoids having to rebaseline pixel tests. - const int kLayoutTestModeGirth = 17; - int girth = ChromiumBridge::layoutTestMode() ? kLayoutTestModeGirth : thickness; - - if (scrollbar->orientation() == HorizontalScrollbar) { - int width = scrollbar->width() < 2 * girth ? scrollbar->width() / 2 : girth; - return IntSize(width, thickness); - } - - int height = scrollbar->height() < 2 * girth ? scrollbar->height() / 2 : girth; - return IntSize(thickness, height); -} - } // namespace WebCore diff --git a/WebCore/platform/chromium/ScrollbarThemeChromium.h b/WebCore/platform/chromium/ScrollbarThemeChromium.h index 87ffd44..71d4817 100644 --- a/WebCore/platform/chromium/ScrollbarThemeChromium.h +++ b/WebCore/platform/chromium/ScrollbarThemeChromium.h @@ -1,10 +1,10 @@ /* * Copyright (c) 2008, 2009, Google Inc. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above @@ -14,7 +14,7 @@ * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -37,22 +37,9 @@ namespace WebCore { class PlatformMouseEvent; - // This class contains the Chromium scrollbar implementations for Windows - // and Linux. All of the symbols here in must be defined somewhere in the - // code and we manage the platform specific parts by linking in different, - // platform specific, files. Methods that we shared across platforms are - // implemented in ScrollbarThemeChromium.cpp + // This class contains the scrollbar code which is shared between Chromium + // Windows and Linux. class ScrollbarThemeChromium : public ScrollbarThemeComposite { - public: - ScrollbarThemeChromium(); - virtual ~ScrollbarThemeChromium(); - - virtual int scrollbarThickness(ScrollbarControlSize = RegularScrollbar); - - virtual void themeChanged(); - - virtual bool invalidateOnMouseEnterExit(); - protected: virtual bool hasButtons(Scrollbar*) { return true; } virtual bool hasThumb(Scrollbar*); @@ -65,19 +52,10 @@ namespace WebCore { virtual bool shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent&); virtual void paintTrackBackground(GraphicsContext*, Scrollbar*, const IntRect&); - virtual void paintTrackPiece(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarPart); - virtual void paintButton(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarPart); - virtual void paintThumb(GraphicsContext*, Scrollbar*, const IntRect&); virtual void paintTickmarks(GraphicsContext*, Scrollbar*, const IntRect&); - private: - IntSize buttonSize(Scrollbar*); - - int getThemeState(Scrollbar*, ScrollbarPart) const; - int getThemeArrowState(Scrollbar*, ScrollbarPart) const; - int getClassicThemeState(Scrollbar*, ScrollbarPart) const; + virtual IntSize buttonSize(Scrollbar*) = 0; }; - } // namespace WebCore #endif diff --git a/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp b/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp index a99d778..6893dea 100644 --- a/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp +++ b/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp @@ -29,9 +29,8 @@ */ #include "config.h" -#include "ScrollbarThemeChromium.h" +#include "ScrollbarThemeChromiumLinux.h" -#include "NotImplemented.h" #include "PlatformContextSkia.h" #include "PlatformMouseEvent.h" #include "Scrollbar.h" @@ -39,14 +38,15 @@ namespace WebCore { -int ScrollbarThemeChromium::scrollbarThickness(ScrollbarControlSize controlSize) +ScrollbarTheme* ScrollbarTheme::nativeTheme() { - return 15; + static ScrollbarThemeChromiumLinux theme; + return &theme; } -bool ScrollbarThemeChromium::invalidateOnMouseEnterExit() +int ScrollbarThemeChromiumLinux::scrollbarThickness(ScrollbarControlSize controlSize) { - return false; + return 15; } static void drawVertLine(SkCanvas* canvas, int x, int y1, int y2, const SkPaint& paint) @@ -73,8 +73,16 @@ static void drawBox(SkCanvas* canvas, const IntRect& rect, const SkPaint& paint) drawVertLine(canvas, rect.x(), rect.y(), bottom, paint); } -void ScrollbarThemeChromium::paintTrackPiece(GraphicsContext* gc, Scrollbar* scrollbar, - const IntRect& rect, ScrollbarPart partType) +IntRect ScrollbarThemeChromium::trackRect(Scrollbar* scrollbar, bool) +{ + IntSize bs = buttonSize(scrollbar); + int thickness = scrollbarThickness(scrollbar->controlSize()); + if (scrollbar->orientation() == HorizontalScrollbar) + return IntRect(scrollbar->x() + bs.width(), scrollbar->y(), scrollbar->width(), thickness); + return IntRect(scrollbar->x(), scrollbar->y() + bs.height(), thickness, scrollbar->height()); +} + +void ScrollbarThemeChromiumLinux::paintTrackPiece(GraphicsContext* gc, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart partType) { SkCanvas* const canvas = gc->platformContext()->canvas(); SkPaint paint; @@ -88,13 +96,12 @@ void ScrollbarThemeChromium::paintTrackPiece(GraphicsContext* gc, Scrollbar* scr drawBox(canvas, rect, paint); } -void ScrollbarThemeChromium::paintButton(GraphicsContext* gc, Scrollbar* scrollbar, - const IntRect& rect, ScrollbarPart part) +void ScrollbarThemeChromiumLinux::paintButton(GraphicsContext* gc, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart part) { // We don't use buttons } -void ScrollbarThemeChromium::paintThumb(GraphicsContext* gc, Scrollbar* scrollbar, const IntRect& rect) +void ScrollbarThemeChromiumLinux::paintThumb(GraphicsContext* gc, Scrollbar* scrollbar, const IntRect& rect) { const bool hovered = scrollbar->hoveredPart() == ThumbPart; const int midx = rect.x() + rect.width() / 2; @@ -139,4 +146,16 @@ void ScrollbarThemeChromium::paintThumb(GraphicsContext* gc, Scrollbar* scrollba } } +IntSize ScrollbarThemeChromiumLinux::buttonSize(Scrollbar* scrollbar) +{ + // On Linux, we don't use buttons + return IntSize(0, 0); +} + +int ScrollbarThemeChromiumLinux::minimumThumbLength(Scrollbar* scrollbar) +{ + // This matches Firefox on Linux. + return 2 * scrollbarThickness(scrollbar->controlSize()); +} + } // namespace WebCore diff --git a/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.h b/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.h new file mode 100644 index 0000000..4e08b07 --- /dev/null +++ b/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.h @@ -0,0 +1,51 @@ +/* + * 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 ScrollbarThemeChromiumLinux_h +#define ScrollbarThemeChromiumLinux_h + +#include "ScrollbarThemeChromium.h" + +namespace WebCore { + class ScrollbarThemeChromiumLinux : public ScrollbarThemeChromium { + public: + virtual int scrollbarThickness(ScrollbarControlSize); + + protected: + virtual void paintTrackPiece(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarPart); + virtual void paintButton(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarPart); + virtual void paintThumb(GraphicsContext*, Scrollbar*, const IntRect&); + + virtual IntSize buttonSize(Scrollbar*); + virtual int minimumThumbLength(Scrollbar*); + }; +} // namespace WebCore + +#endif diff --git a/WebCore/platform/chromium/ScrollbarThemeChromiumWin.cpp b/WebCore/platform/chromium/ScrollbarThemeChromiumWin.cpp index 0337f63..334b767 100644 --- a/WebCore/platform/chromium/ScrollbarThemeChromiumWin.cpp +++ b/WebCore/platform/chromium/ScrollbarThemeChromiumWin.cpp @@ -25,7 +25,7 @@ */ #include "config.h" -#include "ScrollbarThemeChromium.h" +#include "ScrollbarThemeChromiumWin.h" #include <windows.h> #include <vsstyle.h> @@ -39,12 +39,43 @@ namespace WebCore { +ScrollbarTheme* ScrollbarTheme::nativeTheme() +{ + static ScrollbarThemeChromiumWin theme; + return &theme; +} + // The scrollbar size in DumpRenderTree on the Mac - so we can match their // layout results. Entries are for regular, small, and mini scrollbars. // Metrics obtained using [NSScroller scrollerWidthForControlSize:] static const int kMacScrollbarSize[3] = { 15, 11, 15 }; -int ScrollbarThemeChromium::scrollbarThickness(ScrollbarControlSize controlSize) +// Constants used to figure the drag rect outside which we should snap the +// scrollbar thumb back to its origin. These calculations are based on +// observing the behavior of the MSVC8 main window scrollbar + some +// guessing/extrapolation. +static const int kOffEndMultiplier = 3; +static const int kOffSideMultiplier = 8; + +IntRect ScrollbarThemeChromium::trackRect(Scrollbar* scrollbar, bool) +{ + IntSize bs = buttonSize(scrollbar); + // The buttons at the top and bottom of the scrollbar are square, so the + // thickness of the scrollbar is also their height. + int thickness = scrollbarThickness(scrollbar->controlSize()); + if (scrollbar->orientation() == HorizontalScrollbar) { + // Once the scrollbar becomes smaller than the natural size of the + // two buttons, the track disappears. + if (scrollbar->width() < 2 * thickness) + return IntRect(); + return IntRect(scrollbar->x() + bs.width(), scrollbar->y(), scrollbar->width() - 2 * bs.width(), thickness); + } + if (scrollbar->height() < 2 * thickness) + return IntRect(); + return IntRect(scrollbar->x(), scrollbar->y() + bs.height(), thickness, scrollbar->height() - 2 * bs.height()); +} + +int ScrollbarThemeChromiumWin::scrollbarThickness(ScrollbarControlSize controlSize) { static int thickness; if (!thickness) { @@ -55,12 +86,30 @@ int ScrollbarThemeChromium::scrollbarThickness(ScrollbarControlSize controlSize) return thickness; } -bool ScrollbarThemeChromium::invalidateOnMouseEnterExit() +bool ScrollbarThemeChromiumWin::invalidateOnMouseEnterExit() { return isVistaOrNewer(); } -void ScrollbarThemeChromium::paintTrackPiece(GraphicsContext* gc, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart partType) +bool ScrollbarThemeChromiumWin::shouldSnapBackToDragOrigin(Scrollbar* scrollbar, const PlatformMouseEvent& evt) +{ + // Find the rect within which we shouldn't snap, by expanding the track rect + // in both dimensions. + IntRect rect = trackRect(scrollbar); + const bool horz = scrollbar->orientation() == HorizontalScrollbar; + const int thickness = scrollbarThickness(scrollbar->controlSize()); + rect.inflateX((horz ? kOffEndMultiplier : kOffSideMultiplier) * thickness); + rect.inflateY((horz ? kOffSideMultiplier : kOffEndMultiplier) * thickness); + + // Convert the event to local coordinates. + IntPoint mousePosition = scrollbar->convertFromContainingWindow(evt.pos()); + mousePosition.move(scrollbar->x(), scrollbar->y()); + + // We should snap iff the event is outside our calculated rect. + return !rect.contains(mousePosition); +} + +void ScrollbarThemeChromiumWin::paintTrackPiece(GraphicsContext* gc, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart partType) { bool horz = scrollbar->orientation() == HorizontalScrollbar; @@ -82,7 +131,7 @@ void ScrollbarThemeChromium::paintTrackPiece(GraphicsContext* gc, Scrollbar* scr alignRect); } -void ScrollbarThemeChromium::paintButton(GraphicsContext* gc, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart part) +void ScrollbarThemeChromiumWin::paintButton(GraphicsContext* gc, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart part) { bool horz = scrollbar->orientation() == HorizontalScrollbar; @@ -100,7 +149,7 @@ void ScrollbarThemeChromium::paintButton(GraphicsContext* gc, Scrollbar* scrollb rect); } -void ScrollbarThemeChromium::paintThumb(GraphicsContext* gc, Scrollbar* scrollbar, const IntRect& rect) +void ScrollbarThemeChromiumWin::paintThumb(GraphicsContext* gc, Scrollbar* scrollbar, const IntRect& rect) { bool horz = scrollbar->orientation() == HorizontalScrollbar; @@ -121,7 +170,7 @@ void ScrollbarThemeChromium::paintThumb(GraphicsContext* gc, Scrollbar* scrollba rect); } -int ScrollbarThemeChromium::getThemeState(Scrollbar* scrollbar, ScrollbarPart part) const +int ScrollbarThemeChromiumWin::getThemeState(Scrollbar* scrollbar, ScrollbarPart part) const { // When dragging the thumb, draw thumb pressed and other segments normal // regardless of where the cursor actually is. See also four places in @@ -140,7 +189,7 @@ int ScrollbarThemeChromium::getThemeState(Scrollbar* scrollbar, ScrollbarPart pa return (scrollbar->pressedPart() == part) ? SCRBS_PRESSED : SCRBS_NORMAL; } -int ScrollbarThemeChromium::getThemeArrowState(Scrollbar* scrollbar, ScrollbarPart part) const +int ScrollbarThemeChromiumWin::getThemeArrowState(Scrollbar* scrollbar, ScrollbarPart part) const { // We could take advantage of knowing the values in the state enum to write // some simpler code, but treating the state enum as a black box seems @@ -190,7 +239,7 @@ int ScrollbarThemeChromium::getThemeArrowState(Scrollbar* scrollbar, ScrollbarPa return (scrollbar->pressedPart() == part) ? ABS_DOWNPRESSED : ABS_DOWNNORMAL; } -int ScrollbarThemeChromium::getClassicThemeState(Scrollbar* scrollbar, ScrollbarPart part) const +int ScrollbarThemeChromiumWin::getClassicThemeState(Scrollbar* scrollbar, ScrollbarPart part) const { // When dragging the thumb, draw the buttons normal even when hovered. if (scrollbar->pressedPart() == ThumbPart) @@ -204,4 +253,32 @@ int ScrollbarThemeChromium::getClassicThemeState(Scrollbar* scrollbar, Scrollbar return (scrollbar->pressedPart() == part) ? (DFCS_PUSHED | DFCS_FLAT) : 0; } +IntSize ScrollbarThemeChromiumWin::buttonSize(Scrollbar* scrollbar) +{ + // Our desired rect is essentially thickness by thickness. + + // Our actual rect will shrink to half the available space when we have < 2 + // times thickness pixels left. This allows the scrollbar to scale down + // and function even at tiny sizes. + + int thickness = scrollbarThickness(scrollbar->controlSize()); + + // In layout test mode, we force the button "girth" (i.e., the length of + // the button along the axis of the scrollbar) to be a fixed size. + // FIXME: This is retarded! scrollbarThickness is already fixed in layout + // test mode so that should be enough to result in repeatable results, but + // preserving this hack avoids having to rebaseline pixel tests. + const int kLayoutTestModeGirth = 17; + int girth = ChromiumBridge::layoutTestMode() ? kLayoutTestModeGirth : thickness; + + if (scrollbar->orientation() == HorizontalScrollbar) { + int width = scrollbar->width() < 2 * girth ? scrollbar->width() / 2 : girth; + return IntSize(width, thickness); + } + + int height = scrollbar->height() < 2 * girth ? scrollbar->height() / 2 : girth; + return IntSize(thickness, height); +} + + } // namespace WebCore diff --git a/WebCore/platform/chromium/ScrollbarThemeChromiumWin.h b/WebCore/platform/chromium/ScrollbarThemeChromiumWin.h new file mode 100644 index 0000000..5b4d0ea --- /dev/null +++ b/WebCore/platform/chromium/ScrollbarThemeChromiumWin.h @@ -0,0 +1,56 @@ +/* + * 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 ScrollbarThemeChromiumWin_h +#define ScrollbarThemeChromiumWin_h + +#include "ScrollbarThemeChromium.h" + +namespace WebCore { + class ScrollbarThemeChromiumWin : public ScrollbarThemeChromium { + public: + virtual int scrollbarThickness(ScrollbarControlSize); + virtual bool invalidateOnMouseEnterExit(); + virtual bool shouldSnapBackToDragOrigin(Scrollbar*, const PlatformMouseEvent&); + + protected: + virtual void paintTrackPiece(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarPart); + virtual void paintButton(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarPart); + virtual void paintThumb(GraphicsContext*, Scrollbar*, const IntRect&); + virtual IntSize buttonSize(Scrollbar*); + + private: + int getThemeState(Scrollbar*, ScrollbarPart) const; + int getThemeArrowState(Scrollbar*, ScrollbarPart) const; + int getClassicThemeState(Scrollbar*, ScrollbarPart) const; + }; +} // namespace WebCore + +#endif diff --git a/WebCore/platform/chromium/SuddenTerminationChromium.cpp b/WebCore/platform/chromium/SuddenTerminationChromium.cpp new file mode 100644 index 0000000..54b8304 --- /dev/null +++ b/WebCore/platform/chromium/SuddenTerminationChromium.cpp @@ -0,0 +1,48 @@ +/*
+ * 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 "SuddenTermination.h"
+
+#include "ChromiumBridge.h"
+
+namespace WebCore {
+
+void disableSuddenTermination()
+{
+ ChromiumBridge::suddenTerminationChanged(false);
+}
+
+void enableSuddenTermination()
+{
+ ChromiumBridge::suddenTerminationChanged(true);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/BitmapImage.cpp b/WebCore/platform/graphics/BitmapImage.cpp index 1d97632..2f9412d 100644 --- a/WebCore/platform/graphics/BitmapImage.cpp +++ b/WebCore/platform/graphics/BitmapImage.cpp @@ -95,7 +95,7 @@ void BitmapImage::destroyDecodedDataIfNecessary(bool destroyAll) // Animated images >5MB are considered large enough that we'll only hang on // to one frame at a time. static const unsigned cLargeAnimationCutoff = 5242880; - if (frameCount() * frameBytes(m_size) > cLargeAnimationCutoff) + if (m_frames.size() * frameBytes(m_size) > cLargeAnimationCutoff) destroyDecodedData(destroyAll); } diff --git a/WebCore/platform/graphics/BitmapImage.h b/WebCore/platform/graphics/BitmapImage.h index db05d1c..a2de5d7 100644 --- a/WebCore/platform/graphics/BitmapImage.h +++ b/WebCore/platform/graphics/BitmapImage.h @@ -44,11 +44,6 @@ class NSImage; typedef struct HBITMAP__ *HBITMAP; #endif -#if PLATFORM(SGL) -class SkBitmap; -class SkBitmapRef; -#endif - namespace WebCore { struct FrameData; } @@ -146,10 +141,13 @@ public: #endif #if PLATFORM(SGL) -// virtual SkBitmapRef* getBitmap(); virtual void setURL(const String& str); #endif +#if PLATFORM(GTK) + virtual GdkPixbuf* getGdkPixbuf(); +#endif + virtual NativeImagePtr nativeImageForCurrentFrame() { return frameAtIndex(currentFrame()); } protected: diff --git a/WebCore/platform/graphics/Color.cpp b/WebCore/platform/graphics/Color.cpp index e85ac00..d98b202 100644 --- a/WebCore/platform/graphics/Color.cpp +++ b/WebCore/platform/graphics/Color.cpp @@ -321,6 +321,41 @@ void Color::getRGBA(double& r, double& g, double& b, double& a) const a = alpha() / 255.0; } +void Color::getHSL(double& hue, double& saturation, double& lightness) const +{ + // http://en.wikipedia.org/wiki/HSL_color_space. This is a direct copy of + // the algorithm therein, although it's 360^o based and we end up wanting + // [0...1) based. It's clearer if we stick to 360^o until the end. + double r = static_cast<double>(red()) / 255.0; + double g = static_cast<double>(green()) / 255.0; + double b = static_cast<double>(blue()) / 255.0; + double max = std::max(std::max(r, g), b); + double min = std::min(std::min(r, g), b); + + if (max == min) + hue = 0.0; + else if (max == r) + hue = (60.0 * ((g - b) / (max - min))) + 360.0; + else if (max == g) + hue = (60.0 * ((b - r) / (max - min))) + 120.0; + else + hue = (60.0 * ((r - g) / (max - min))) + 240.0; + + if (hue >= 360.0) + hue -= 360.0; + + // makeRGBAFromHSLA assumes that hue is in [0...1). + hue /= 360.0; + + lightness = 0.5 * (max + min); + if (max == min) + saturation = 0.0; + else if (lightness <= 0.5) + saturation = ((max - min) / (max + min)); + else + saturation = ((max - min) / (2.0 - (max + min))); +} + Color colorFromPremultipliedARGB(unsigned pixelColor) { RGBA32 rgba; diff --git a/WebCore/platform/graphics/Color.h b/WebCore/platform/graphics/Color.h index 3c889f9..3b815d2 100644 --- a/WebCore/platform/graphics/Color.h +++ b/WebCore/platform/graphics/Color.h @@ -94,6 +94,7 @@ public: void setRGB(RGBA32 rgb) { m_color = rgb; m_valid = true; } void getRGBA(float& r, float& g, float& b, float& a) const; void getRGBA(double& r, double& g, double& b, double& a) const; + void getHSL(double& h, double& s, double& l) const; Color light() const; Color dark() const; diff --git a/WebCore/platform/graphics/FloatQuad.cpp b/WebCore/platform/graphics/FloatQuad.cpp index a32d8ab..427230d 100644 --- a/WebCore/platform/graphics/FloatQuad.cpp +++ b/WebCore/platform/graphics/FloatQuad.cpp @@ -46,6 +46,34 @@ static inline float max4(float a, float b, float c, float d) return max(max(a, b), max(c, d)); } +inline float dot(const FloatSize& a, const FloatSize& b) +{ + return a.width() * b.width() + a.height() * b.height(); +} + +inline bool isPointInTriangle(const FloatPoint& p, const FloatPoint& t1, const FloatPoint& t2, const FloatPoint& t3) +{ + // Compute vectors + FloatSize v0 = t3 - t1; + FloatSize v1 = t2 - t1; + FloatSize v2 = p - t1; + + // Compute dot products + float dot00 = dot(v0, v0); + float dot01 = dot(v0, v1); + float dot02 = dot(v0, v2); + float dot11 = dot(v1, v1); + float dot12 = dot(v1, v2); + + // Compute barycentric coordinates + float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01); + float u = (dot11 * dot02 - dot01 * dot12) * invDenom; + float v = (dot00 * dot12 - dot01 * dot02) * invDenom; + + // Check if point is in triangle + return (u >= 0) && (v >= 0) && (u + v <= 1); +} + FloatRect FloatQuad::boundingBox() const { float left = min4(m_p1.x(), m_p2.x(), m_p3.x(), m_p4.x()); @@ -57,4 +85,15 @@ FloatRect FloatQuad::boundingBox() const return FloatRect(left, top, right - left, bottom - top); } +bool FloatQuad::containsPoint(const FloatPoint& p) const +{ + return isPointInTriangle(p, m_p1, m_p2, m_p3) || isPointInTriangle(p, m_p1, m_p3, m_p4); +} + +// Note that we only handle convex quads here. +bool FloatQuad::containsQuad(const FloatQuad& other) const +{ + return containsPoint(other.p1()) && containsPoint(other.p2()) && containsPoint(other.p3()) && containsPoint(other.p4()); +} + } // namespace WebCore diff --git a/WebCore/platform/graphics/FloatQuad.h b/WebCore/platform/graphics/FloatQuad.h index e05b27d..5982967 100644 --- a/WebCore/platform/graphics/FloatQuad.h +++ b/WebCore/platform/graphics/FloatQuad.h @@ -74,6 +74,14 @@ public: // "slanted" empty quads. bool isEmpty() const { return boundingBox().isEmpty(); } + // Tests whether the given point is inside, or on an edge or corner of this quad. + bool containsPoint(const FloatPoint&) const; + + // Tests whether the four corners of other are inside, or coincident with the sides of this quad. + // Note that this only works for convex quads, but that includes all quads that originate + // from transformed rects. + bool containsQuad(const FloatQuad&) const; + FloatRect boundingBox() const; IntRect enclosingBoundingBox() const { diff --git a/WebCore/platform/graphics/Font.cpp b/WebCore/platform/graphics/Font.cpp index f8bec82..85fe882 100644 --- a/WebCore/platform/graphics/Font.cpp +++ b/WebCore/platform/graphics/Font.cpp @@ -32,6 +32,7 @@ #include "GlyphBuffer.h" #include "WidthIterator.h" #include <wtf/MathExtras.h> +#include <wtf/UnusedParam.h> using namespace WTF; using namespace Unicode; @@ -198,7 +199,7 @@ void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoi return drawComplexText(context, run, point, from, to); } -float Font::floatWidth(const TextRun& run) const +float Font::floatWidth(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const { #if ENABLE(SVG_FONTS) if (primaryFont()->isSVGFont()) @@ -206,16 +207,22 @@ float Font::floatWidth(const TextRun& run) const #endif #if USE(FONT_FAST_PATH) - if (canUseGlyphCache(run)) - return floatWidthForSimpleText(run, 0); + if (canUseGlyphCache(run)) { + // If the complex text implementation cannot return fallback fonts, avoid + // returning them for simple text as well. + static bool returnFallbackFonts = canReturnFallbackFontsForComplexText(); + return floatWidthForSimpleText(run, 0, returnFallbackFonts ? fallbackFonts : 0); + } #endif - return floatWidthForComplexText(run); + return floatWidthForComplexText(run, fallbackFonts); } float Font::floatWidth(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const { -#if ENABLE(SVG_FONTS) +#if !ENABLE(SVG_FONTS) + UNUSED_PARAM(extraCharsAvailable); +#else if (primaryFont()->isSVGFont()) return floatWidthUsingSVGFont(run, extraCharsAvailable, charsConsumed, glyphName); #endif @@ -275,4 +282,17 @@ FontSelector* Font::fontSelector() const return m_fontList ? m_fontList->fontSelector() : 0; } +static bool shouldUseFontSmoothing = true; + +void Font::setShouldUseSmoothing(bool shouldUseSmoothing) +{ + ASSERT(isMainThread()); + shouldUseFontSmoothing = shouldUseSmoothing; +} + +bool Font::shouldUseSmoothing() +{ + return shouldUseFontSmoothing; +} + } diff --git a/WebCore/platform/graphics/Font.h b/WebCore/platform/graphics/Font.h index 1bfee8f..8d85d8b 100644 --- a/WebCore/platform/graphics/Font.h +++ b/WebCore/platform/graphics/Font.h @@ -78,8 +78,8 @@ public: void drawText(GraphicsContext*, const TextRun&, const FloatPoint&, int from = 0, int to = -1) const; - int width(const TextRun& run) const { return lroundf(floatWidth(run)); } - float floatWidth(const TextRun&) const; + int width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts = 0) const { return lroundf(floatWidth(run, fallbackFonts)); } + float floatWidth(const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0) const; float floatWidth(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const; int offsetForPosition(const TextRun&, int position, bool includePartialGlyphs) const; @@ -112,17 +112,19 @@ public: int lineGap() const { return primaryFont()->lineGap(); } float xHeight() const { return primaryFont()->xHeight(); } unsigned unitsPerEm() const { return primaryFont()->unitsPerEm(); } - int spaceWidth() const { return (int)ceilf(primaryFont()->m_adjustedSpaceWidth + m_letterSpacing); } + int spaceWidth() const { return (int)ceilf(primaryFont()->adjustedSpaceWidth() + m_letterSpacing); } int tabWidth() const { return 8 * spaceWidth(); } - const SimpleFontData* primaryFont() const { + const SimpleFontData* primaryFont() const + { + ASSERT(isMainThread()); if (!m_cachedPrimaryFont) cachePrimaryFont(); return m_cachedPrimaryFont; } const FontData* fontDataAt(unsigned) const; - const GlyphData& glyphDataForCharacter(UChar32, bool mirror, bool forceSmallCaps = false) const; + GlyphData glyphDataForCharacter(UChar32, bool mirror, bool forceSmallCaps = false) const; // Used for complex text, and does not utilize the glyph map cache. const FontData* fontDataForCharacters(const UChar*, int length) const; @@ -130,6 +132,9 @@ public: QFont font() const; #endif + static void setShouldUseSmoothing(bool); + static bool shouldUseSmoothing(); + private: #if ENABLE(SVG_FONTS) void drawTextUsingSVGFont(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const; @@ -144,13 +149,15 @@ private: void drawSimpleText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const; void drawGlyphs(GraphicsContext*, const SimpleFontData*, const GlyphBuffer&, int from, int to, const FloatPoint&) const; void drawGlyphBuffer(GraphicsContext*, const GlyphBuffer&, const TextRun&, const FloatPoint&) const; - float floatWidthForSimpleText(const TextRun&, GlyphBuffer*) const; + float floatWidthForSimpleText(const TextRun&, GlyphBuffer*, HashSet<const SimpleFontData*>* fallbackFonts = 0) const; int offsetForPositionForSimpleText(const TextRun&, int position, bool includePartialGlyphs) const; FloatRect selectionRectForSimpleText(const TextRun&, const IntPoint&, int h, int from, int to) const; + + static bool canReturnFallbackFontsForComplexText(); #endif void drawComplexText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const; - float floatWidthForComplexText(const TextRun&) const; + float floatWidthForComplexText(const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0) const; int offsetForPositionForComplexText(const TextRun&, int position, bool includePartialGlyphs) const; FloatRect selectionRectForComplexText(const TextRun&, const IntPoint&, int h, int from, int to) const; void cachePrimaryFont() const; diff --git a/WebCore/platform/graphics/FontCache.cpp b/WebCore/platform/graphics/FontCache.cpp index 130313d..d9b4b28 100644 --- a/WebCore/platform/graphics/FontCache.cpp +++ b/WebCore/platform/graphics/FontCache.cpp @@ -307,12 +307,13 @@ void FontCache::purgeInactiveFontData(int count) isPurging = true; + Vector<const SimpleFontData*, 20> fontDataToDelete; ListHashSet<const SimpleFontData*>::iterator end = gInactiveFontData->end(); ListHashSet<const SimpleFontData*>::iterator it = gInactiveFontData->begin(); for (int i = 0; i < count && it != end; ++it, ++i) { const SimpleFontData* fontData = *it.get(); gFontDataCache->remove(fontData->platformData()); - delete fontData; + fontDataToDelete.append(fontData); } if (it == end) { @@ -323,6 +324,10 @@ void FontCache::purgeInactiveFontData(int count) gInactiveFontData->remove(gInactiveFontData->begin()); } + size_t fontDataToDeleteCount = fontDataToDelete.size(); + for (size_t i = 0; i < fontDataToDeleteCount; ++i) + delete fontDataToDelete[i]; + Vector<FontPlatformDataCacheKey> keysToRemove; keysToRemove.reserveInitialCapacity(gFontPlatformDataCache->size()); FontPlatformDataCache::iterator platformDataEnd = gFontPlatformDataCache->end(); diff --git a/WebCore/platform/graphics/FontCache.h b/WebCore/platform/graphics/FontCache.h index 8820045..3c0f2d9 100644 --- a/WebCore/platform/graphics/FontCache.h +++ b/WebCore/platform/graphics/FontCache.h @@ -85,6 +85,7 @@ public: private: FontCache(); + ~FontCache(); // These methods are implemented by each platform. FontPlatformData* getSimilarFontPlatformData(const Font&); diff --git a/WebCore/platform/graphics/FontDescription.h b/WebCore/platform/graphics/FontDescription.h index d13e86a..c893b8a 100644 --- a/WebCore/platform/graphics/FontDescription.h +++ b/WebCore/platform/graphics/FontDescription.h @@ -81,7 +81,7 @@ public: GenericFamilyType genericFamily() const { return static_cast<GenericFamilyType>(m_genericFamily); } bool usePrinterFont() const { return m_usePrinterFont; } FontRenderingMode renderingMode() const { return static_cast<FontRenderingMode>(m_renderingMode); } - int keywordSize() const { return m_keywordSize; } + unsigned keywordSize() const { return m_keywordSize; } FontTraitsMask traitsMask() const; @@ -95,7 +95,7 @@ public: void setGenericFamily(GenericFamilyType genericFamily) { m_genericFamily = genericFamily; } void setUsePrinterFont(bool p) { m_usePrinterFont = p; } void setRenderingMode(FontRenderingMode mode) { m_renderingMode = mode; } - void setKeywordSize(int s) { m_keywordSize = s; } + void setKeywordSize(unsigned s) { m_keywordSize = s; } private: FontFamily m_familyList; // The list of font families to be used. @@ -114,7 +114,7 @@ private: unsigned m_renderingMode : 1; // Used to switch between CG and GDI text on Windows. - int m_keywordSize : 4; // We cache whether or not a font is currently represented by a CSS keyword (e.g., medium). If so, + unsigned m_keywordSize : 4; // We cache whether or not a font is currently represented by a CSS keyword (e.g., medium). If so, // then we can accurately translate across different generic families to adjust for different preference settings // (e.g., 13px monospace vs. 16px everything else). Sizes are 1-8 (like the HTML size values for <font>). }; diff --git a/WebCore/platform/graphics/FontFallbackList.cpp b/WebCore/platform/graphics/FontFallbackList.cpp index 06d52d7..decacc5 100644 --- a/WebCore/platform/graphics/FontFallbackList.cpp +++ b/WebCore/platform/graphics/FontFallbackList.cpp @@ -36,10 +36,10 @@ namespace WebCore { FontFallbackList::FontFallbackList() - : m_familyIndex(0) + : m_fontSelector(0) + , m_familyIndex(0) , m_pitch(UnknownPitch) , m_loadingCustomFonts(false) - , m_fontSelector(0) , m_generation(fontCache()->generation()) { } diff --git a/WebCore/platform/graphics/FontFallbackList.h b/WebCore/platform/graphics/FontFallbackList.h index a23b32c..07938ae 100644 --- a/WebCore/platform/graphics/FontFallbackList.h +++ b/WebCore/platform/graphics/FontFallbackList.h @@ -66,10 +66,10 @@ private: void releaseFontData(); mutable Vector<pair<const FontData*, bool>, 1> m_fontList; + RefPtr<FontSelector> m_fontSelector; mutable int m_familyIndex; mutable Pitch m_pitch; mutable bool m_loadingCustomFonts; - RefPtr<FontSelector> m_fontSelector; unsigned m_generation; friend class Font; diff --git a/WebCore/platform/graphics/FontFastPath.cpp b/WebCore/platform/graphics/FontFastPath.cpp index 635aba9..deac1b6 100644 --- a/WebCore/platform/graphics/FontFastPath.cpp +++ b/WebCore/platform/graphics/FontFastPath.cpp @@ -39,11 +39,13 @@ using namespace Unicode; namespace WebCore { -const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCaps) const +GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCaps) const { + ASSERT(isMainThread()); + bool useSmallCapsFont = forceSmallCaps; if (m_fontDescription.smallCaps()) { - UChar32 upperC = Unicode::toUpper(c); + UChar32 upperC = toUpper(c); if (upperC != c) { c = upperC; useSmallCapsFont = true; @@ -70,7 +72,7 @@ const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceS while (true) { page = node->page(); if (page) { - const GlyphData& data = page->glyphDataForCharacter(c); + GlyphData data = page->glyphDataForCharacter(c); if (data.fontData) return data; if (node->isSystemFallback()) @@ -88,7 +90,7 @@ const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceS while (true) { page = node->page(); if (page) { - const GlyphData& data = page->glyphDataForCharacter(c); + GlyphData data = page->glyphDataForCharacter(c); if (data.fontData) { // The smallCapsFontData function should not normally return 0. // But if it does, we will just render the capital letter big. @@ -99,7 +101,7 @@ const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceS GlyphPageTreeNode* smallCapsNode = GlyphPageTreeNode::getRootChild(smallCapsFontData, pageNumber); const GlyphPage* smallCapsPage = smallCapsNode->page(); if (smallCapsPage) { - const GlyphData& data = smallCapsPage->glyphDataForCharacter(c); + GlyphData data = smallCapsPage->glyphDataForCharacter(c); if (data.fontData) return data; } @@ -150,7 +152,7 @@ const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceS if (characterFontData) { // Got the fallback glyph and font. GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page(); - const GlyphData& data = fallbackPage && fallbackPage->glyphDataForCharacter(c).fontData ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData(); + GlyphData data = fallbackPage && fallbackPage->fontDataForCharacter(c) ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData(); // Cache it so we don't have to do system fallback again next time. if (!useSmallCapsFont) page->setGlyphDataForCharacter(c, data.glyph, data.fontData); @@ -159,7 +161,7 @@ const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceS // Even system fallback can fail; use the missing glyph in that case. // FIXME: It would be nicer to use the missing glyph from the last resort font instead. - const GlyphData& data = primaryFont()->missingGlyphData(); + GlyphData data = primaryFont()->missingGlyphData(); if (!useSmallCapsFont) page->setGlyphDataForCharacter(c, data.glyph, data.fontData); return data; @@ -296,9 +298,9 @@ void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuf drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); } -float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer) const +float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts) const { - WidthIterator it(this, run); + WidthIterator it(this, run, fallbackFonts); it.advance(run.length(), glyphBuffer); return it.m_runWidthSoFar; } diff --git a/WebCore/platform/graphics/GeneratedImage.cpp b/WebCore/platform/graphics/GeneratedImage.cpp index 15e27d7..c40a40a 100644 --- a/WebCore/platform/graphics/GeneratedImage.cpp +++ b/WebCore/platform/graphics/GeneratedImage.cpp @@ -51,7 +51,7 @@ void GeneratedImage::drawPattern(GraphicsContext* context, const FloatRect& srcR const FloatPoint& phase, CompositeOperator compositeOp, const FloatRect& destRect) { // Create a BitmapImage and call drawPattern on it. - auto_ptr<ImageBuffer> imageBuffer = ImageBuffer::create(m_size, false); + OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(m_size, false); ASSERT(imageBuffer.get()); // Fill with the gradient. diff --git a/WebCore/platform/graphics/GlyphPageTreeNode.cpp b/WebCore/platform/graphics/GlyphPageTreeNode.cpp index bd838de..a34a192 100644 --- a/WebCore/platform/graphics/GlyphPageTreeNode.cpp +++ b/WebCore/platform/graphics/GlyphPageTreeNode.cpp @@ -220,8 +220,8 @@ void GlyphPageTreeNode::initializePage(const FontData* fontData, unsigned pageNu if (scratchPage) { ASSERT(to <= static_cast<int>(GlyphPage::size)); for (int j = from; j < to; j++) { - if (!m_page->m_glyphs[j].glyph && pageToFill->m_glyphs[j].glyph) - m_page->m_glyphs[j] = pageToFill->m_glyphs[j]; + if (!m_page->glyphAt(j) && pageToFill->glyphAt(j)) + m_page->setGlyphDataForIndex(j, pageToFill->glyphDataForIndex(j)); } } } @@ -265,15 +265,13 @@ void GlyphPageTreeNode::initializePage(const FontData* fontData, unsigned pageNu // has added anything. bool newGlyphs = false; for (unsigned i = 0; i < GlyphPage::size; i++) { - if (parentPage->m_glyphs[i].glyph) - m_page->m_glyphs[i] = parentPage->m_glyphs[i]; - else if (fallbackPage->m_glyphs[i].glyph) { - m_page->m_glyphs[i] = fallbackPage->m_glyphs[i]; + if (parentPage->glyphAt(i)) + m_page->setGlyphDataForIndex(i, parentPage->glyphDataForIndex(i)); + else if (fallbackPage->glyphAt(i)) { + m_page->setGlyphDataForIndex(i, fallbackPage->glyphDataForIndex(i)); newGlyphs = true; - } else { - const GlyphData data = { 0, 0 }; - m_page->m_glyphs[i] = data; - } + } else + m_page->setGlyphDataForIndex(i, 0, 0); } if (!newGlyphs) @@ -288,12 +286,9 @@ void GlyphPageTreeNode::initializePage(const FontData* fontData, unsigned pageNu // ever finds it needs a glyph out of the system fallback page, it will // ask the system for the best font to use and fill that glyph in for us. if (parentPage) - memcpy(m_page->m_glyphs, parentPage->m_glyphs, GlyphPage::size * sizeof(m_page->m_glyphs[0])); - else { - const GlyphData data = { 0, 0 }; - for (unsigned i = 0; i < GlyphPage::size; i++) - m_page->m_glyphs[i] = data; - } + m_page->copyFrom(*parentPage); + else + m_page->clear(); } } diff --git a/WebCore/platform/graphics/GlyphPageTreeNode.h b/WebCore/platform/graphics/GlyphPageTreeNode.h index 240b492..80e87aa 100644 --- a/WebCore/platform/graphics/GlyphPageTreeNode.h +++ b/WebCore/platform/graphics/GlyphPageTreeNode.h @@ -29,6 +29,7 @@ #ifndef GlyphPageTreeNode_h #define GlyphPageTreeNode_h +#include <string.h> #include <wtf/HashMap.h> #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> @@ -45,6 +46,11 @@ typedef unsigned short Glyph; // Holds the glyph index and the corresponding SimpleFontData information for a given // character. struct GlyphData { + GlyphData(Glyph g = 0, const SimpleFontData* f = 0) + : glyph(g) + , fontData(f) + { + } Glyph glyph; const SimpleFontData* fontData; }; @@ -54,30 +60,69 @@ struct GlyphData { // starting from 0 and incrementing for each 256 glyphs. // // One page may actually include glyphs from other fonts if the characters are -// missing in the parimary font. It is owned by exactly one GlyphPageTreeNode, +// missing in the primary font. It is owned by exactly one GlyphPageTreeNode, // although multiple nodes may reference it as their "page" if they are supposed // to be overriding the parent's node, but provide no additional information. -struct GlyphPage : public RefCounted<GlyphPage> { +class GlyphPage : public RefCounted<GlyphPage> { +public: static PassRefPtr<GlyphPage> create(GlyphPageTreeNode* owner) { return adoptRef(new GlyphPage(owner)); } static const size_t size = 256; // Covers Latin-1 in a single page. - GlyphData m_glyphs[size]; - GlyphPageTreeNode* m_owner; - const GlyphData& glyphDataForCharacter(UChar32 c) const { return m_glyphs[c % size]; } + unsigned indexForCharacter(UChar32 c) const { return c % size; } + GlyphData glyphDataForCharacter(UChar32 c) const + { + unsigned index = indexForCharacter(c); + return GlyphData(m_glyphs[index], m_glyphFontData[index]); + } + + GlyphData glyphDataForIndex(unsigned index) const + { + ASSERT(index < size); + return GlyphData(m_glyphs[index], m_glyphFontData[index]); + } + + Glyph glyphAt(unsigned index) const + { + ASSERT(index < size); + return m_glyphs[index]; + } + + const SimpleFontData* fontDataForCharacter(UChar32 c) const + { + return m_glyphFontData[indexForCharacter(c)]; + } + void setGlyphDataForCharacter(UChar32 c, Glyph g, const SimpleFontData* f) { - setGlyphDataForIndex(c % size, g, f); + setGlyphDataForIndex(indexForCharacter(c), g, f); } void setGlyphDataForIndex(unsigned index, Glyph g, const SimpleFontData* f) { ASSERT(index < size); - m_glyphs[index].glyph = g; - m_glyphs[index].fontData = f; + m_glyphs[index] = g; + m_glyphFontData[index] = f; + } + void setGlyphDataForIndex(unsigned index, const GlyphData& glyphData) + { + setGlyphDataForIndex(index, glyphData.glyph, glyphData.fontData); + } + + void copyFrom(const GlyphPage& other) + { + memcpy(m_glyphs, other.m_glyphs, sizeof(m_glyphs)); + memcpy(m_glyphFontData, other.m_glyphFontData, sizeof(m_glyphFontData)); + } + + void clear() + { + memset(m_glyphs, 0, sizeof(m_glyphs)); + memset(m_glyphFontData, 0, sizeof(m_glyphFontData)); } + GlyphPageTreeNode* owner() const { return m_owner; } // Implemented by the platform. @@ -88,6 +133,12 @@ private: : m_owner(owner) { } + + // Separate arrays, rather than array of GlyphData, to save space. + Glyph m_glyphs[size]; + const SimpleFontData* m_glyphFontData[size]; + + GlyphPageTreeNode* m_owner; }; // The glyph page tree is a data structure that maps (FontData, glyph page number) diff --git a/WebCore/platform/graphics/Gradient.cpp b/WebCore/platform/graphics/Gradient.cpp index 24e8bbf..51c7162 100644 --- a/WebCore/platform/graphics/Gradient.cpp +++ b/WebCore/platform/graphics/Gradient.cpp @@ -52,6 +52,7 @@ Gradient::Gradient(const FloatPoint& p0, float r0, const FloatPoint& p1, float r , m_r1(r1) , m_stopsSorted(false) , m_lastStop(0) + , m_spreadMethod(SpreadMethodPad) { platformInit(); } diff --git a/WebCore/platform/graphics/GraphicsContext.cpp b/WebCore/platform/graphics/GraphicsContext.cpp index 8cad794..4dae3d2 100644 --- a/WebCore/platform/graphics/GraphicsContext.cpp +++ b/WebCore/platform/graphics/GraphicsContext.cpp @@ -30,7 +30,6 @@ #include "Generator.h" #include "GraphicsContextPrivate.h" #include "Font.h" -#include "NotImplemented.h" using namespace std; @@ -337,7 +336,7 @@ void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const F BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver; WTF::Unicode::Direction paragraphDirection = run.ltr() ? WTF::Unicode::LeftToRight : WTF::Unicode::RightToLeft; - bidiResolver.setStatus(BidiStatus(paragraphDirection, paragraphDirection, paragraphDirection, new BidiContext(run.ltr() ? 0 : 1, paragraphDirection, run.directionalOverride()))); + bidiResolver.setStatus(BidiStatus(paragraphDirection, paragraphDirection, paragraphDirection, BidiContext::create(run.ltr() ? 0 : 1, paragraphDirection, run.directionalOverride()))); bidiResolver.setPosition(TextRunIterator(&run, 0)); bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length())); diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h index 7c1c4b0..3fdafad 100644 --- a/WebCore/platform/graphics/GraphicsContext.h +++ b/WebCore/platform/graphics/GraphicsContext.h @@ -374,6 +374,7 @@ namespace WebCore { #if PLATFORM(QT) && defined(Q_WS_WIN) 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(QT) diff --git a/WebCore/platform/graphics/GraphicsLayer.h b/WebCore/platform/graphics/GraphicsLayer.h index f928ce8..ae51951 100644 --- a/WebCore/platform/graphics/GraphicsLayer.h +++ b/WebCore/platform/graphics/GraphicsLayer.h @@ -288,8 +288,10 @@ public: int incrementRepaintCount() { return ++m_repaintCount; } #endif - // Platform behaviors - static bool graphicsContextsFlipped(); + // Report whether the underlying compositing system uses a top-down + // or a bottom-up coordinate system. + enum CompositingCoordinatesOrientation { CompositingCoordinatesTopDown, CompositingCoordinatesBottomUp }; + static CompositingCoordinatesOrientation compositingCoordinatesOrientation(); #ifndef NDEBUG static bool showDebugBorders(); diff --git a/WebCore/platform/graphics/Image.h b/WebCore/platform/graphics/Image.h index 70f6d49..cff8b22 100644 --- a/WebCore/platform/graphics/Image.h +++ b/WebCore/platform/graphics/Image.h @@ -61,8 +61,8 @@ class NativeImageSkia; #include <QPixmap> #endif -#if PLATFORM(SGL) -class SkBitmapRef; +#if PLATFORM(GTK) +typedef struct _GdkPixbuf GdkPixbuf; #endif namespace WebCore { @@ -147,10 +147,13 @@ public: #endif #if PLATFORM(SGL) - virtual SkBitmapRef* getBitmap() { return 0; } virtual void setURL(const String& str) {} #endif +#if PLATFORM(GTK) + virtual GdkPixbuf* getGdkPixbuf() { return 0; } +#endif + protected: Image(ImageObserver* = 0); diff --git a/WebCore/platform/graphics/ImageBuffer.h b/WebCore/platform/graphics/ImageBuffer.h index 14f7461..573e274 100644 --- a/WebCore/platform/graphics/ImageBuffer.h +++ b/WebCore/platform/graphics/ImageBuffer.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> - * 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 @@ -32,8 +32,8 @@ #include "IntSize.h" #include "ImageBufferData.h" #include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> #include <wtf/PassRefPtr.h> -#include <memory> namespace WebCore { @@ -46,13 +46,13 @@ namespace WebCore { class ImageBuffer : Noncopyable { public: // Will return a null pointer on allocation failure. - static std::auto_ptr<ImageBuffer> create(const IntSize& size, bool grayScale) + static PassOwnPtr<ImageBuffer> create(const IntSize& size, bool grayScale) { bool success = false; - std::auto_ptr<ImageBuffer> buf(new ImageBuffer(size, grayScale, success)); + OwnPtr<ImageBuffer> buf(new ImageBuffer(size, grayScale, success)); if (success) - return buf; - return std::auto_ptr<ImageBuffer>(); + return buf.release(); + return 0; } ~ImageBuffer(); @@ -80,7 +80,7 @@ namespace WebCore { OwnPtr<GraphicsContext> m_context; mutable RefPtr<Image> m_image; - // This constructor will place its succes into the given out-variable + // This constructor will place its success into the given out-variable // so that create() knows when it should return failure. ImageBuffer(const IntSize&, bool grayScale, bool& success); }; diff --git a/WebCore/platform/graphics/ImageSource.h b/WebCore/platform/graphics/ImageSource.h index 07cc2c2..d4a1658 100644 --- a/WebCore/platform/graphics/ImageSource.h +++ b/WebCore/platform/graphics/ImageSource.h @@ -31,6 +31,7 @@ #if PLATFORM(WX) class wxBitmap; +class wxGraphicsBitmap; #elif PLATFORM(CG) typedef struct CGImageSource* CGImageSourceRef; typedef struct CGImage* CGImageRef; @@ -61,7 +62,11 @@ class String; class ImageDecoder; typedef ImageDecoder* NativeImageSourcePtr; typedef const Vector<char>* NativeBytePtr; +#if USE(WXGC) +typedef wxGraphicsBitmap* NativeImagePtr; +#else typedef wxBitmap* NativeImagePtr; +#endif #elif PLATFORM(CG) typedef CGImageSourceRef NativeImageSourcePtr; typedef CGImageRef NativeImagePtr; diff --git a/WebCore/platform/graphics/IntPoint.h b/WebCore/platform/graphics/IntPoint.h index a05b1f0..1bfeeaa 100644 --- a/WebCore/platform/graphics/IntPoint.h +++ b/WebCore/platform/graphics/IntPoint.h @@ -70,6 +70,7 @@ class IntPoint { public: IntPoint() : m_x(0), m_y(0) { } IntPoint(int x, int y) : m_x(x), m_y(y) { } + explicit IntPoint(const IntSize& size) : m_x(size.width()), m_y(size.height()) { } int x() const { return m_x; } int y() const { return m_y; } diff --git a/WebCore/platform/graphics/IntSize.h b/WebCore/platform/graphics/IntSize.h index 4d36545..cac0bd1 100644 --- a/WebCore/platform/graphics/IntSize.h +++ b/WebCore/platform/graphics/IntSize.h @@ -73,6 +73,12 @@ public: m_height += height; } + void scale(float scale) + { + m_width = static_cast<int>(static_cast<float>(m_width) * scale); + m_height = static_cast<int>(static_cast<float>(m_height) * scale); + } + IntSize expandedTo(const IntSize& other) const { return IntSize(m_width > other.m_width ? m_width : other.m_width, diff --git a/WebCore/platform/graphics/MediaPlayer.cpp b/WebCore/platform/graphics/MediaPlayer.cpp index 99d6aa4..b580474 100644 --- a/WebCore/platform/graphics/MediaPlayer.cpp +++ b/WebCore/platform/graphics/MediaPlayer.cpp @@ -183,6 +183,7 @@ MediaPlayer::MediaPlayer(MediaPlayerClient* client) , m_visible(false) , m_rate(1.0f) , m_volume(1.0f) + , m_autobuffer(false) #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) , m_playerProxy(0) #endif @@ -206,11 +207,20 @@ void MediaPlayer::load(const String& url, const ContentType& contentType) String type = contentType.type(); String codecs = contentType.parameter("codecs"); - // if we don't know the MIME type, see if the path can help - if (type.isEmpty()) - type = MIMETypeRegistry::getMIMETypeForPath(url); + // if we don't know the MIME type, see if the extension can help + if (type.isEmpty() || type == "application/octet-stream" || type == "text/plain") { + int pos = url.reverseFind('.'); + if (pos >= 0) { + String extension = url.substring(pos + 1); + String mediaType = MIMETypeRegistry::getMediaMIMETypeForExtension(extension); + if (!mediaType.isEmpty()) + type = mediaType; + } + } - MediaPlayerFactory* engine = chooseBestEngineForTypeAndCodecs(type, codecs); + MediaPlayerFactory* engine = 0; + if (!type.isEmpty()) + engine = chooseBestEngineForTypeAndCodecs(type, codecs); // if we didn't find an engine that claims the MIME type, just use the first engine if (!engine) @@ -260,6 +270,11 @@ float MediaPlayer::duration() const return m_private->duration(); } +float MediaPlayer::startTime() const +{ + return m_private->startTime(); +} + float MediaPlayer::currentTime() const { return m_private->currentTime(); @@ -382,6 +397,19 @@ void MediaPlayer::setVisible(bool b) m_private->setVisible(b); } +bool MediaPlayer::autobuffer() const +{ + return m_autobuffer; +} + +void MediaPlayer::setAutobuffer(bool b) +{ + if (m_autobuffer != b) { + m_autobuffer = b; + m_private->setAutobuffer(b); + } +} + void MediaPlayer::paint(GraphicsContext* p, const IntRect& r) { m_private->paint(p, r); diff --git a/WebCore/platform/graphics/MediaPlayer.h b/WebCore/platform/graphics/MediaPlayer.h index 7d90e44..9b2f685 100644 --- a/WebCore/platform/graphics/MediaPlayer.h +++ b/WebCore/platform/graphics/MediaPlayer.h @@ -76,6 +76,11 @@ public: // the movie size has changed virtual void mediaPlayerSizeChanged(MediaPlayer*) { } + + // The MediaPlayer has found potentially problematic media content. + // This is used internally to trigger swapping from a <video> + // element to an <embed> in standalone documents + virtual void mediaPlayerSawUnsupportedTracks(MediaPlayer*) { } }; class MediaPlayer : Noncopyable { @@ -88,7 +93,7 @@ public: static MediaPlayer::SupportsType supportsType(ContentType contentType); static void getSupportedTypes(HashSet<String>&); static bool isAvailable(); - + IntSize naturalSize(); bool hasVideo(); @@ -114,6 +119,8 @@ public: float duration() const; float currentTime() const; void seek(float time); + + float startTime() const; void setEndTime(float time); @@ -131,7 +138,10 @@ public: void setVolume(float); int dataRate() const; - + + bool autobuffer() const; + void setAutobuffer(bool); + void paint(GraphicsContext*, const IntRect&); enum NetworkState { Empty, Idle, Loading, Loaded, FormatError, NetworkError, DecodeError }; @@ -169,6 +179,7 @@ private: bool m_visible; float m_rate; float m_volume; + bool m_autobuffer; #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) WebMediaPlayerProxy* m_playerProxy; // not owned or used, passed to m_private #endif diff --git a/WebCore/platform/graphics/MediaPlayerPrivate.h b/WebCore/platform/graphics/MediaPlayerPrivate.h index 2e73e7e..e17259c 100644 --- a/WebCore/platform/graphics/MediaPlayerPrivate.h +++ b/WebCore/platform/graphics/MediaPlayerPrivate.h @@ -58,7 +58,9 @@ public: virtual void seek(float time) = 0; virtual bool seeking() const = 0; - virtual void setEndTime(float time) = 0; + virtual float startTime() const { return 0; } + + virtual void setEndTime(float) = 0; virtual void setRate(float) = 0; virtual bool paused() const = 0; @@ -81,6 +83,8 @@ public: virtual void paint(GraphicsContext*, const IntRect&) = 0 ; + virtual void setAutobuffer(bool) { }; + #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) virtual void setPoster(const String& url) = 0; virtual void deliverNotification(MediaPlayerProxyNotificationType) = 0; diff --git a/WebCore/platform/graphics/Path.cpp b/WebCore/platform/graphics/Path.cpp index f3450be..e30703c 100644 --- a/WebCore/platform/graphics/Path.cpp +++ b/WebCore/platform/graphics/Path.cpp @@ -35,7 +35,7 @@ #include <math.h> #include <wtf/MathExtras.h> -const float QUARTER = 0.552f; // approximation of control point positions on a bezier +static const float QUARTER = 0.552f; // approximation of control point positions on a bezier // to simulate a quarter of a circle. namespace WebCore { diff --git a/WebCore/platform/graphics/SimpleFontData.cpp b/WebCore/platform/graphics/SimpleFontData.cpp index 9f51037..bab7d99 100644 --- a/WebCore/platform/graphics/SimpleFontData.cpp +++ b/WebCore/platform/graphics/SimpleFontData.cpp @@ -32,18 +32,24 @@ #include "Font.h" #include "FontCache.h" + #if ENABLE(SVG_FONTS) #include "SVGFontData.h" +#include "SVGFontElement.h" #include "SVGFontFaceElement.h" +#include "SVGGlyphElement.h" #endif #include <wtf/MathExtras.h> +#include <wtf/UnusedParam.h> + +using namespace std; namespace WebCore { SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool loading, SVGFontData* svgFontData) : m_unitsPerEm(defaultUnitsPerEm) - , m_font(f) + , m_platformData(f) , m_treatAsFixedPitch(false) #if ENABLE(SVG_FONTS) , m_svgFontData(svgFontData) @@ -52,24 +58,40 @@ SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool , m_isLoading(loading) , m_smallCapsFontData(0) { -#if ENABLE(SVG_FONTS) +#if !ENABLE(SVG_FONTS) + UNUSED_PARAM(svgFontData); +#else if (SVGFontFaceElement* svgFontFaceElement = svgFontData ? svgFontData->svgFontFaceElement() : 0) { - m_unitsPerEm = svgFontFaceElement->unitsPerEm(); + m_unitsPerEm = svgFontFaceElement->unitsPerEm(); - double scale = f.size(); - if (m_unitsPerEm) - scale /= m_unitsPerEm; + double scale = f.size(); + if (m_unitsPerEm) + scale /= m_unitsPerEm; m_ascent = static_cast<int>(svgFontFaceElement->ascent() * scale); m_descent = static_cast<int>(svgFontFaceElement->descent() * scale); m_xHeight = static_cast<int>(svgFontFaceElement->xHeight() * scale); m_lineGap = 0.1f * f.size(); m_lineSpacing = m_ascent + m_descent + m_lineGap; - + + SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement(); + + Vector<SVGGlyphIdentifier> spaceGlyphs; + associatedFontElement->getGlyphIdentifiersForString(String(" ", 1), spaceGlyphs); + m_spaceWidth = spaceGlyphs.isEmpty() ? m_xHeight : static_cast<float>(spaceGlyphs.first().horizontalAdvanceX * scale); + + Vector<SVGGlyphIdentifier> numeralZeroGlyphs; + associatedFontElement->getGlyphIdentifiersForString(String("0", 1), numeralZeroGlyphs); + m_avgCharWidth = numeralZeroGlyphs.isEmpty() ? m_spaceWidth : static_cast<float>(numeralZeroGlyphs.first().horizontalAdvanceX * scale); + + Vector<SVGGlyphIdentifier> letterWGlyphs; + associatedFontElement->getGlyphIdentifiersForString(String("W", 1), letterWGlyphs); + m_maxCharWidth = letterWGlyphs.isEmpty() ? m_ascent : static_cast<float>(letterWGlyphs.first().horizontalAdvanceX * scale); + + // FIXME: is there a way we can get the space glyph from the SVGGlyphIdentifier above? m_spaceGlyph = 0; - m_spaceWidth = 0; - m_adjustedSpaceWidth = 0; determinePitch(); + m_adjustedSpaceWidth = roundf(m_spaceWidth); m_missingGlyphData.fontData = this; m_missingGlyphData.glyph = 0; return; @@ -78,9 +100,31 @@ SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool platformInit(); platformGlyphInit(); + platformCharWidthInit(); } #if !PLATFORM(QT) +// Estimates of avgCharWidth and maxCharWidth for platforms that don't support accessing these values from the font. +void SimpleFontData::initCharWidths() +{ + GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); + + // Treat the width of a '0' as the avgCharWidth. + if (m_avgCharWidth <= 0.f && glyphPageZero) { + static const UChar32 digitZeroChar = '0'; + Glyph digitZeroGlyph = glyphPageZero->glyphDataForCharacter(digitZeroChar).glyph; + if (digitZeroGlyph) + m_avgCharWidth = widthForGlyph(digitZeroGlyph); + } + + // If we can't retrieve the width of a '0', fall back to the x height. + if (m_avgCharWidth <= 0.f) + m_avgCharWidth = m_xHeight; + + if (m_maxCharWidth <= 0.f) + m_maxCharWidth = max<float>(m_avgCharWidth, m_ascent); +} + void SimpleFontData::platformGlyphInit() { GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); diff --git a/WebCore/platform/graphics/SimpleFontData.h b/WebCore/platform/graphics/SimpleFontData.h index d2dd0b9..aab6429 100644 --- a/WebCore/platform/graphics/SimpleFontData.h +++ b/WebCore/platform/graphics/SimpleFontData.h @@ -61,7 +61,7 @@ public: virtual ~SimpleFontData(); public: - const FontPlatformData& platformData() const { return m_font; } + const FontPlatformData& platformData() const { return m_platformData; } SimpleFontData* smallCapsFontData(const FontDescription& fontDescription) const; // vertical metrics @@ -69,12 +69,23 @@ public: int descent() const { return m_descent; } int lineSpacing() const { return m_lineSpacing; } int lineGap() const { return m_lineGap; } + float maxCharWidth() const { return m_maxCharWidth; } + float avgCharWidth() const { return m_avgCharWidth; } float xHeight() const { return m_xHeight; } unsigned unitsPerEm() const { return m_unitsPerEm; } float widthForGlyph(Glyph) const; float platformWidthForGlyph(Glyph) const; + float spaceWidth() const { return m_spaceWidth; } + float adjustedSpaceWidth() const { return m_adjustedSpaceWidth; } + +#if PLATFORM(CG) || PLATFORM(CAIRO) + float syntheticBoldOffset() const { return m_syntheticBoldOffset; } +#endif + + Glyph spaceGlyph() const { return m_spaceGlyph; } + virtual const SimpleFontData* fontDataForCharacter(UChar32) const; virtual bool containsCharacters(const UChar*, int length) const; @@ -95,7 +106,7 @@ public: const GlyphData& missingGlyphData() const { return m_missingGlyphData; } #if PLATFORM(MAC) - NSFont* getNSFont() const { return m_font.font(); } + NSFont* getNSFont() const { return m_platformData.font(); } #endif #if USE(CORE_TEXT) @@ -114,7 +125,7 @@ public: #endif #if PLATFORM(QT) - QFont getQtFont() const { return m_font.font(); } + QFont getQtFont() const { return m_platformData.font(); } #endif #if PLATFORM(WIN) @@ -131,14 +142,17 @@ public: #endif #if PLATFORM(WX) - wxFont* getWxFont() const { return m_font.font(); } + wxFont* getWxFont() const { return m_platformData.font(); } #endif private: void platformInit(); void platformGlyphInit(); + void platformCharWidthInit(); void platformDestroy(); + void initCharWidths(); + void commonInit(); #if PLATFORM(WIN) @@ -147,15 +161,16 @@ private: float widthForGDIGlyph(Glyph glyph) const; #endif -public: int m_ascent; int m_descent; int m_lineSpacing; int m_lineGap; + float m_maxCharWidth; + float m_avgCharWidth; float m_xHeight; unsigned m_unitsPerEm; - FontPlatformData m_font; + FontPlatformData m_platformData; mutable GlyphWidthMap m_glyphToWidthMap; @@ -176,22 +191,26 @@ public: mutable SimpleFontData* m_smallCapsFontData; -#if PLATFORM(CG) || PLATFORM(WIN) +#if PLATFORM(CG) || PLATFORM(CAIRO) float m_syntheticBoldOffset; #endif -#if PLATFORM(MAC) #ifdef BUILDING_ON_TIGER +public: void* m_styleGroup; -#endif + +private: #endif #if USE(ATSUI) +public: mutable ATSUStyle m_ATSUStyle; mutable bool m_ATSUStyleInitialized; mutable bool m_ATSUMirrors; mutable bool m_checkedShapesArabic; mutable bool m_shapesArabic; + +private: #endif #if USE(CORE_TEXT) diff --git a/WebCore/platform/graphics/WidthIterator.cpp b/WebCore/platform/graphics/WidthIterator.cpp index a16d739..9157310 100644 --- a/WebCore/platform/graphics/WidthIterator.cpp +++ b/WebCore/platform/graphics/WidthIterator.cpp @@ -39,13 +39,14 @@ namespace WebCore { // According to http://www.unicode.org/Public/UNIDATA/UCD.html#Canonical_Combining_Class_Values static const uint8_t hiraganaKatakanaVoicingMarksCombiningClass = 8; -WidthIterator::WidthIterator(const Font* font, const TextRun& run) +WidthIterator::WidthIterator(const Font* font, const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) : m_font(font) , m_run(run) , m_end(run.length()) , m_currentCharacter(0) , m_runWidthSoFar(0) , m_finalRoundingWidth(0) + , m_fallbackFonts(fallbackFonts) { // If the padding is non-zero, count the number of spaces in the run // and divide that by the padding for per space addition. @@ -78,7 +79,10 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer) float runWidthSoFar = m_runWidthSoFar; float lastRoundingWidth = m_finalRoundingWidth; - + + const SimpleFontData* primaryFont = m_font->primaryFont(); + const SimpleFontData* lastFontData = primaryFont; + while (currentCharacter < offset) { UChar32 c = *cp; unsigned clusterLength = 1; @@ -126,16 +130,29 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer) // First, we round spaces to an adjusted width in all fonts. // Second, in fixed-pitch fonts we ensure that all characters that // match the width of the space character have the same width as the space character. - if (width == fontData->m_spaceWidth && (fontData->m_treatAsFixedPitch || glyph == fontData->m_spaceGlyph) && m_run.applyWordRounding()) { - width = fontData->m_adjustedSpaceWidth; + if (width == fontData->spaceWidth() && (fontData->pitch() == FixedPitch || glyph == fontData->spaceGlyph()) && m_run.applyWordRounding()) + width = fontData->adjustedSpaceWidth(); + } + + if (fontData != lastFontData && width) { + lastFontData = fontData; + if (m_fallbackFonts && fontData != primaryFont) { + // FIXME: This does a little extra work that could be avoided if + // glyphDataForCharacter() returned whether it chose to use a small caps font. + if (!m_font->isSmallCaps() || c == toUpper(c)) + m_fallbackFonts->add(fontData); + else { + const GlyphData& uppercaseGlyphData = m_font->glyphDataForCharacter(toUpper(c), rtl); + if (uppercaseGlyphData.fontData != primaryFont) + m_fallbackFonts->add(uppercaseGlyphData.fontData); + } } } if (hasExtraSpacing) { // Account for letter-spacing. - if (width && m_font->letterSpacing()) { + if (width && m_font->letterSpacing()) width += m_font->letterSpacing(); - } if (Font::treatAsSpace(c)) { // Account for padding. WebCore uses space padding to justify text. @@ -153,9 +170,8 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer) // Account for word spacing. // We apply additional space between "words" by adding width to the space character. - if (currentCharacter != 0 && !Font::treatAsSpace(cp[-1]) && m_font->wordSpacing()) { + if (currentCharacter != 0 && !Font::treatAsSpace(cp[-1]) && m_font->wordSpacing()) width += m_font->wordSpacing(); - } } } @@ -172,9 +188,8 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer) // Force characters that are used to determine word boundaries for the rounding hack // to be integer width, so following words will start on an integer boundary. - if (m_run.applyWordRounding() && Font::isRoundingHackCharacter(c)) { + if (m_run.applyWordRounding() && Font::isRoundingHackCharacter(c)) width = ceilf(width); - } // Check to see if the next character is a "rounding hack character", if so, adjust // width so that the total run width will be on an integer boundary. diff --git a/WebCore/platform/graphics/WidthIterator.h b/WebCore/platform/graphics/WidthIterator.h index 5706d1e..7ca4198 100644 --- a/WebCore/platform/graphics/WidthIterator.h +++ b/WebCore/platform/graphics/WidthIterator.h @@ -22,16 +22,18 @@ #ifndef WidthIterator_h #define WidthIterator_h +#include <wtf/HashSet.h> #include <wtf/unicode/Unicode.h> namespace WebCore { class Font; class GlyphBuffer; +class SimpleFontData; class TextRun; struct WidthIterator { - WidthIterator(const Font*, const TextRun&); + WidthIterator(const Font*, const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0); void advance(int to, GlyphBuffer* = 0); bool advanceOneCharacter(float& width, GlyphBuffer* = 0); @@ -49,6 +51,7 @@ struct WidthIterator { private: UChar32 normalizeVoicingMarks(int currentCharacter); + HashSet<const SimpleFontData*>* m_fallbackFonts; }; } diff --git a/WebCore/platform/graphics/android/FontAndroid.cpp b/WebCore/platform/graphics/android/FontAndroid.cpp index ca2fca1..a430b07 100644 --- a/WebCore/platform/graphics/android/FontAndroid.cpp +++ b/WebCore/platform/graphics/android/FontAndroid.cpp @@ -107,6 +107,11 @@ static bool setupForText(SkPaint* paint, GraphicsContext* gc, return true; } +bool Font::canReturnFallbackFontsForComplexText() +{ + return false; +} + void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const @@ -206,7 +211,7 @@ void Font::drawComplexText(GraphicsContext* gc, TextRun const& run, paint); } -float Font::floatWidthForComplexText(const TextRun& run) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*) const { SkPaint paint; diff --git a/WebCore/platform/graphics/android/FontDataAndroid.cpp b/WebCore/platform/graphics/android/FontDataAndroid.cpp index 3d31eaf..2bb53e4 100644 --- a/WebCore/platform/graphics/android/FontDataAndroid.cpp +++ b/WebCore/platform/graphics/android/FontDataAndroid.cpp @@ -48,7 +48,7 @@ void SimpleFontData::platformInit() SkPaint paint; SkPaint::FontMetrics metrics; - m_font.setupPaint(&paint); + m_platformData.setupPaint(&paint); (void)paint.getFontMetrics(&metrics); // use ceil instead of round to favor descent, given a lot of accidental @@ -64,6 +64,13 @@ void SimpleFontData::platformInit() m_lineGap = SkScalarRound(metrics.fLeading); } +void SimpleFontData::platformCharWidthInit() +{ + m_avgCharWidth = 0.f; + m_maxCharWidth = 0.f; + initCharWidths(); +} + void SimpleFontData::platformDestroy() { delete m_smallCapsFontData; @@ -72,7 +79,7 @@ void SimpleFontData::platformDestroy() SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const { if (!m_smallCapsFontData) { - m_smallCapsFontData = new SimpleFontData(FontPlatformData(m_font, fontDescription.computedSize() * 0.7f)); + m_smallCapsFontData = new SimpleFontData(FontPlatformData(m_platformData, fontDescription.computedSize() * 0.7f)); } return m_smallCapsFontData; } @@ -84,7 +91,7 @@ bool SimpleFontData::containsCharacters(const UChar* characters, int length) con SkPaint paint; uint16_t glyphs[kMaxBufferCount]; - m_font.setupPaint(&paint); + m_platformData.setupPaint(&paint); paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); while (length > 0) { @@ -114,7 +121,7 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const SkPaint paint; - m_font.setupPaint(&paint); + m_platformData.setupPaint(&paint); if (EmojiFont::IsEmojiGlyph(glyph)) return EmojiFont::GetAdvanceWidth(glyph, paint); diff --git a/WebCore/platform/graphics/cairo/FontCairo.cpp b/WebCore/platform/graphics/cairo/FontCairo.cpp index b23182d..0f7ae79 100644 --- a/WebCore/platform/graphics/cairo/FontCairo.cpp +++ b/WebCore/platform/graphics/cairo/FontCairo.cpp @@ -36,6 +36,8 @@ #include "SimpleFontData.h" #include "TransformationMatrix.h" +#define SYNTHETIC_OBLIQUE_ANGLE 14 + namespace WebCore { void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, @@ -48,15 +50,23 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from); - float offset = point.x(); + float offset = 0.0f; for (int i = 0; i < numGlyphs; i++) { glyphs[i].x = offset; - glyphs[i].y = point.y(); + glyphs[i].y = 0.0f; offset += glyphBuffer.advanceAt(from + i); } Color fillColor = context->fillColor(); + // Synthetic Oblique + if(font->platformData().syntheticOblique()) { + cairo_matrix_t mat = {1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, point.x(), point.y()}; + cairo_transform(cr, &mat); + } else { + cairo_translate(cr, point.x(), point.y()); + } + // Text shadow, inspired by FontMac IntSize shadowSize; int shadowBlur = 0; @@ -77,6 +87,12 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons cairo_translate(cr, shadowSize.width(), shadowSize.height()); cairo_show_glyphs(cr, glyphs, numGlyphs); + if (font->syntheticBoldOffset()) { + cairo_save(cr); + cairo_translate(cr, font->syntheticBoldOffset(), 0); + cairo_show_glyphs(cr, glyphs, numGlyphs); + cairo_restore(cr); + } cairo_restore(cr); } @@ -103,6 +119,12 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha()); } cairo_show_glyphs(cr, glyphs, numGlyphs); + if (font->syntheticBoldOffset()) { + cairo_save(cr); + cairo_translate(cr, font->syntheticBoldOffset(), 0); + cairo_show_glyphs(cr, glyphs, numGlyphs); + cairo_restore(cr); + } } if (context->textDrawingMode() & cTextStroke) { diff --git a/WebCore/platform/graphics/cairo/GradientCairo.cpp b/WebCore/platform/graphics/cairo/GradientCairo.cpp index 72fb0c5..0aada55 100644 --- a/WebCore/platform/graphics/cairo/GradientCairo.cpp +++ b/WebCore/platform/graphics/cairo/GradientCairo.cpp @@ -80,11 +80,11 @@ void Gradient::fill(GraphicsContext* context, const FloatRect& rect) { cairo_t* cr = context->platformContext(); - cairo_save(cr); + context->save(); cairo_set_source(cr, platformGradient()); cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); cairo_fill(cr); - cairo_restore(cr); + context->restore(); } } //namespace diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp index 35ebd3c..23f30f3 100644 --- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp +++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp @@ -92,6 +92,7 @@ GraphicsContext::GraphicsContext(PlatformGraphicsContext* cr) , m_data(new GraphicsContextPlatformPrivate) { m_data->cr = cairo_reference(cr); + m_data->syncContext(cr); setPaintingDisabled(!cr); } diff --git a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h index 55b2e25..531ebf4 100644 --- a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h +++ b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h @@ -73,6 +73,7 @@ public: void concatCTM(const TransformationMatrix&); void beginTransparencyLayer() { m_transparencyCount++; } void endTransparencyLayer() { m_transparencyCount--; } + void syncContext(PlatformGraphicsContext* cr); #else // On everything else, we do nothing. void save() {} @@ -85,6 +86,7 @@ public: void concatCTM(const TransformationMatrix&) {} void beginTransparencyLayer() {} void endTransparencyLayer() {} + void syncContext(PlatformGraphicsContext* cr) {} #endif cairo_t* cr; diff --git a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp index dff39b7..d2652d6 100644 --- a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp +++ b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp @@ -34,7 +34,6 @@ #include "GraphicsContext.h" #include "ImageData.h" #include "MIMETypeRegistry.h" -#include "NotImplemented.h" #include "Pattern.h" #include "PlatformString.h" diff --git a/WebCore/platform/graphics/cairo/ImageCairo.cpp b/WebCore/platform/graphics/cairo/ImageCairo.cpp index 224154e..7c34e6f 100644 --- a/WebCore/platform/graphics/cairo/ImageCairo.cpp +++ b/WebCore/platform/graphics/cairo/ImageCairo.cpp @@ -33,10 +33,12 @@ #include "Color.h" #include "FloatRect.h" #include "GraphicsContext.h" +#include "ImageBuffer.h" #include "ImageObserver.h" #include "TransformationMatrix.h" #include <cairo.h> #include <math.h> +#include <wtf/OwnPtr.h> namespace WebCore { @@ -89,15 +91,19 @@ BitmapImage::BitmapImage(cairo_surface_t* surface, ImageObserver* observer) void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, CompositeOperator op) { + FloatRect srcRect(src); + FloatRect dstRect(dst); + + if (dstRect.width() == 0.0f || dstRect.height() == 0.0f || + srcRect.width() == 0.0f || srcRect.height() == 0.0f) + return; + startAnimation(); cairo_surface_t* image = frameAtIndex(m_currentFrame); if (!image) // If it's too early we won't have an image yet. return; - FloatRect srcRect(src); - FloatRect dstRect(dst); - if (mayFillWithSolidColor()) { fillWithSolidColor(context, dstRect, solidColor(), op); return; @@ -106,7 +112,7 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo IntSize selfSize = size(); cairo_t* cr = context->platformContext(); - cairo_save(cr); + context->save(); // Set the compositing operation. if (op == CompositeSourceOver && !frameHasAlphaAtIndex(m_currentFrame)) @@ -138,7 +144,7 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo cairo_clip(cr); cairo_paint_with_alpha(cr, context->getAlpha()); - cairo_restore(cr); + context->restore(); if (imageObserver()) imageObserver()->didDraw(this); @@ -154,7 +160,18 @@ void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, con cairo_t* cr = context->platformContext(); context->save(); - // TODO: Make use of tileRect. + IntRect imageSize = enclosingIntRect(tileRect); + OwnPtr<ImageBuffer> imageSurface = ImageBuffer::create(imageSize.size(), false); + + if (!imageSurface) + return; + + if (tileRect.size() != size()) { + cairo_t* clippedImageContext = imageSurface->context()->platformContext(); + cairo_set_source_surface(clippedImageContext, image, -tileRect.x(), -tileRect.y()); + cairo_paint(clippedImageContext); + image = imageSurface->image()->nativeImageForCurrentFrame(); + } cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image); cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); @@ -163,7 +180,7 @@ void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, con 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(), phase.y()}; + 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; cairo_matrix_multiply(&combined, &pattern_matrix, &phase_matrix); cairo_matrix_invert(&combined); diff --git a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp b/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp index c6d54f2..b51caf6 100644 --- a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp +++ b/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp @@ -190,13 +190,13 @@ NativeImagePtr ImageSource::createFrameAtIndex(size_t index) // Cairo does not like zero height images. // If we have a zero height image, just pretend we don't have enough data yet. - if (!buffer->height()) + if (!size().height()) return 0; return cairo_image_surface_create_for_data((unsigned char*)buffer->bytes().data(), CAIRO_FORMAT_ARGB32, size().width(), - buffer->height(), + size().height(), size().width()*4); } diff --git a/WebCore/platform/graphics/cairo/PathCairo.cpp b/WebCore/platform/graphics/cairo/PathCairo.cpp index 24354d2..13ca1e2 100644 --- a/WebCore/platform/graphics/cairo/PathCairo.cpp +++ b/WebCore/platform/graphics/cairo/PathCairo.cpp @@ -29,7 +29,6 @@ #include "CairoPath.h" #include "FloatRect.h" #include "GraphicsContext.h" -#include "NotImplemented.h" #include "PlatformString.h" #include "StrokeStyleApplier.h" diff --git a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp index 4b8a555..ab8eb3c 100644 --- a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp +++ b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp @@ -116,10 +116,9 @@ void GraphicsContext::drawRect(const IntRect& rect) CGContextRef context = platformContext(); - if (fillColor().alpha()) - CGContextFillRect(context, rect); + CGContextFillRect(context, rect); - if (strokeStyle() != NoStroke && strokeColor().alpha()) { + if (strokeStyle() != NoStroke) { // We do a fill of four rects to simulate the stroke of a border. Color oldFillColor = fillColor(); if (oldFillColor != strokeColor()) @@ -142,7 +141,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) if (paintingDisabled()) return; - if (strokeStyle() == NoStroke || !strokeColor().alpha()) + if (strokeStyle() == NoStroke) return; float width = strokeThickness(); @@ -277,7 +276,7 @@ void GraphicsContext::drawEllipse(const IntRect& rect) void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan) { - if (paintingDisabled() || strokeStyle() == NoStroke || strokeThickness() <= 0.0f || !strokeColor().alpha()) + if (paintingDisabled() || strokeStyle() == NoStroke || strokeThickness() <= 0.0f) return; CGContextRef context = platformContext(); @@ -366,7 +365,7 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool antialiased) { - if (paintingDisabled() || !fillColor().alpha() && (strokeThickness() <= 0 || strokeStyle() == NoStroke)) + if (paintingDisabled()) return; if (npoints <= 1) @@ -491,8 +490,7 @@ void GraphicsContext::fillPath() CGContextRef context = platformContext(); switch (m_common->state.fillColorSpace) { case SolidColorSpace: - if (fillColor().alpha()) - fillPathWithFillRule(context, fillRule()); + fillPathWithFillRule(context, fillRule()); break; case PatternColorSpace: applyFillPattern(); @@ -519,8 +517,7 @@ void GraphicsContext::strokePath() CGContextRef context = platformContext(); switch (m_common->state.strokeColorSpace) { case SolidColorSpace: - if (strokeColor().alpha()) - CGContextStrokePath(context); + CGContextStrokePath(context); break; case PatternColorSpace: applyStrokePattern(); @@ -544,8 +541,7 @@ void GraphicsContext::fillRect(const FloatRect& rect) CGContextRef context = platformContext(); switch (m_common->state.fillColorSpace) { case SolidColorSpace: - if (fillColor().alpha()) - CGContextFillRect(context, rect); + CGContextFillRect(context, rect); break; case PatternColorSpace: applyFillPattern(); @@ -565,20 +561,18 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) { if (paintingDisabled()) return; - if (color.alpha()) { - CGContextRef context = platformContext(); - Color oldFillColor = fillColor(); - if (oldFillColor != color) - setCGFillColor(context, color); - CGContextFillRect(context, rect); - if (oldFillColor != color) - setCGFillColor(context, oldFillColor); - } + CGContextRef context = platformContext(); + Color oldFillColor = fillColor(); + if (oldFillColor != color) + setCGFillColor(context, color); + CGContextFillRect(context, rect); + if (oldFillColor != color) + setCGFillColor(context, oldFillColor); } void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) { - if (paintingDisabled() || !color.alpha()) + if (paintingDisabled()) return; CGContextRef context = platformContext(); @@ -782,8 +776,7 @@ void GraphicsContext::strokeRect(const FloatRect& r, float lineWidth) CGContextRef context = platformContext(); switch (m_common->state.strokeColorSpace) { case SolidColorSpace: - if (strokeColor().alpha()) - CGContextStrokeRectWithWidth(context, r, lineWidth); + CGContextStrokeRectWithWidth(context, r, lineWidth); break; case PatternColorSpace: applyStrokePattern(); @@ -1199,4 +1192,3 @@ void GraphicsContext::setCompositeOperation(CompositeOperator mode) #endif } - diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/WebCore/platform/graphics/cg/ImageSourceCG.cpp index c059985..7cb8799 100644 --- a/WebCore/platform/graphics/cg/ImageSourceCG.cpp +++ b/WebCore/platform/graphics/cg/ImageSourceCG.cpp @@ -33,10 +33,12 @@ #include "MIMETypeRegistry.h" #include "SharedBuffer.h" #include <ApplicationServices/ApplicationServices.h> +#include <wtf/UnusedParam.h> namespace WebCore { static const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32"); +static const CFStringRef kCGImageSourceDoNotCacheImageBlocks = CFSTR("kCGImageSourceDoNotCacheImageBlocks"); ImageSource::ImageSource() : m_decoder(0) @@ -48,11 +50,24 @@ ImageSource::~ImageSource() clear(true); } -void ImageSource::clear(bool, size_t, SharedBuffer* data, bool allDataReceived) +void ImageSource::clear(bool destroyAllFrames, size_t, SharedBuffer* data, bool allDataReceived) { - // We always destroy the decoder, because there is no API to get it to - // selectively release some of the frames it's holding, and if we don't - // release any of them, we use too much memory on large images. +#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + // Recent versions of ImageIO discard previously decoded image frames if the client + // application no longer holds references to them, so there's no need to throw away + // the decoder unless we're explicitly asked to destroy all of the frames. + + if (!destroyAllFrames) + return; +#else + // Older versions of ImageIO hold references to previously decoded image frames. + // There is no API to selectively release some of the frames it is holding, and + // if we don't release the frames we use too much memory on large images. + // Destroying the decoder is the only way to release previous frames. + + UNUSED_PARAM(destroyAllFrames); +#endif + if (m_decoder) { CFRelease(m_decoder); m_decoder = 0; @@ -66,9 +81,9 @@ static CFDictionaryRef imageSourceOptions() static CFDictionaryRef options; if (!options) { - const void* keys[2] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32 }; - const void* values[2] = { kCFBooleanTrue, kCFBooleanTrue }; - options = CFDictionaryCreate(NULL, keys, values, 2, + const void* keys[3] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32, kCGImageSourceDoNotCacheImageBlocks }; + const void* values[3] = { kCFBooleanTrue, kCFBooleanTrue, kCFBooleanTrue }; + options = CFDictionaryCreate(NULL, keys, values, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } return options; @@ -227,9 +242,17 @@ float ImageSource::frameDurationAtIndex(size_t index) bool ImageSource::frameHasAlphaAtIndex(size_t) { - // Might be interesting to do this optimization on Mac some day, but for now we're just using this - // for the Cairo source, since it uses our decoders, and our decoders can answer this question. - // FIXME: Could return false for JPEG and other non-transparent image formats. + if (!m_decoder) + return false; + + CFStringRef imageType = CGImageSourceGetType(m_decoder); + + // Return false if there is no image type or the image type is JPEG, because + // JPEG does not support alpha transparency. + if (!imageType || CFEqual(imageType, CFSTR("public.jpeg"))) + return false; + + // FIXME: Could return false for other non-transparent image formats. // FIXME: Could maybe return false for a GIF Frame if we have enough info in the GIF properties dictionary // to determine whether or not a transparent color was defined. return true; diff --git a/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp index 129776e..bf1cd2e 100644 --- a/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp @@ -414,14 +414,6 @@ FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font) FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& description) { FontDescription::GenericFamilyType generic = description.genericFamily(); - // FIXME: Mapping webkit generic to GenericFamilyType needs to - // be more intelligent. - // This spot rarely gets reached. GetFontDataForCharacters() gets hit a lot - // more often (see FIXME comment there). - const wchar_t* family = getFontFamilyForScript(description.dominantScript(), generic); - - if (family) - return getCachedFontPlatformData(description, AtomicString(family, wcslen(family))); // FIXME: Would be even better to somehow get the user's default font here. // For now we'll pick the default that the user would get without changing @@ -455,13 +447,6 @@ static LONG toGDIFontWeight(FontWeight fontWeight) return gdiFontWeights[fontWeight]; } -// FIXME: This may not be the best place to put this function -AtomicString FontCache::getGenericFontForScript(UScriptCode script, const FontDescription& description) -{ - const wchar_t* scriptFont = getFontFamilyForScript( script, description.genericFamily()); - return scriptFont ? AtomicString(scriptFont, wcslen(scriptFont)) : emptyAtom; -} - static void FillLogFont(const FontDescription& fontDescription, LOGFONT* winfont) { // The size here looks unusual. The negative number is intentional. diff --git a/WebCore/platform/graphics/chromium/FontCacheLinux.cpp b/WebCore/platform/graphics/chromium/FontCacheLinux.cpp index 89433e1..797825e 100644 --- a/WebCore/platform/graphics/chromium/FontCacheLinux.cpp +++ b/WebCore/platform/graphics/chromium/FontCacheLinux.cpp @@ -46,6 +46,8 @@ #include "SkTypeface.h" #include "SkUtils.h" +#include <wtf/Assertions.h> + namespace WebCore { void FontCache::platformInit() @@ -79,9 +81,8 @@ const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, if (match) { FcChar8* family; if (FcPatternGetString(match, FC_FAMILY, 0, &family) == FcResultMatch) { - FontPlatformData* fpd = - createFontPlatformData(font.fontDescription(), AtomicString((char*) family)); - ret = new SimpleFontData(*fpd); + AtomicString fontFamily(reinterpret_cast<char*>(family)); + ret = getCachedFontData(getCachedFontPlatformData(font.fontDescription(), fontFamily, false)); } FcPatternDestroy(match); } @@ -98,8 +99,26 @@ FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font) FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& description) { - static AtomicString arialStr("Arial"); - return getCachedFontPlatformData(description, arialStr); + static const AtomicString sansStr("Sans"); + static const AtomicString serifStr("Serif"); + static const AtomicString monospaceStr("Monospace"); + + FontPlatformData* fontPlatformData = 0; + switch (description.genericFamily()) { + case FontDescription::SerifFamily: + fontPlatformData = getCachedFontPlatformData(description, serifStr); + break; + case FontDescription::MonospaceFamily: + fontPlatformData = getCachedFontPlatformData(description, monospaceStr); + break; + case FontDescription::SansSerifFamily: + default: + fontPlatformData = getCachedFontPlatformData(description, sansStr); + break; + } + + ASSERT(fontPlatformData); + return fontPlatformData; } void FontCache::getTraitsInFamily(const AtomicString& familyName, @@ -146,7 +165,13 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD if (fontDescription.italic()) style |= SkTypeface::kItalic; + // FIXME: This #ifdef can go away once we're firmly using the new Skia. + // During the transition, this makes the code compatible with both versions. +#ifdef SK_USE_OLD_255_TO_256 + SkTypeface* tf = SkTypeface::CreateFromName(name, static_cast<SkTypeface::Style>(style)); +#else SkTypeface* tf = SkTypeface::Create(name, static_cast<SkTypeface::Style>(style)); +#endif if (!tf) return 0; @@ -159,11 +184,4 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD return result; } -AtomicString FontCache::getGenericFontForScript(UScriptCode script, - const FontDescription& descript) -{ - notImplemented(); - return AtomicString(); -} - } // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp index 1b71946..4710245 100644 --- a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp @@ -249,10 +249,28 @@ bool TransparencyAwareGlyphPainter::drawGlyphs(int numGlyphs, // to subtract off the font ascent to get it. int x = lroundf(m_point.x() + startAdvance); int y = lroundf(m_point.y() - m_font->ascent()); + + // If there is a non-blur shadow and both the fill color and shadow color + // are opaque, handle without skia. + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + if (m_graphicsContext->getShadow(shadowSize, shadowBlur, shadowColor)) { + // If there is a shadow and this code is reached, windowsCanHandleDrawTextShadow() + // will have already returned true during the ctor initiatization of m_useGDI + ASSERT(shadowColor.alpha() == 255); + ASSERT(m_graphicsContext->fillColor().alpha() == 255); + ASSERT(shadowBlur == 0); + COLORREF textColor = skia::SkColorToCOLORREF(SkColorSetARGB(255, shadowColor.red(), shadowColor.green(), shadowColor.blue())); + COLORREF savedTextColor = GetTextColor(m_hdc); + SetTextColor(m_hdc, textColor); + ExtTextOut(m_hdc, x + shadowSize.width(), y + shadowSize.height(), ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), numGlyphs, &advances[0]); + SetTextColor(m_hdc, savedTextColor); + } + return !!ExtTextOut(m_hdc, x, y, ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), numGlyphs, &advances[0]); } - class TransparencyAwareUniscribePainter : public TransparencyAwareFontPainter { public: TransparencyAwareUniscribePainter(GraphicsContext*, @@ -305,6 +323,10 @@ IntRect TransparencyAwareUniscribePainter::estimateTextBounds() UniscribeHelperTextRun state(m_run, *m_font); int left = lroundf(m_point.x()) + state.characterToX(m_from); int right = lroundf(m_point.x()) + state.characterToX(m_to); + + // Adjust for RTL script since we just want to know the text bounds. + if (left > right) + std::swap(left, right); // This algorithm for estimating how much extra space we need (the text may // go outside the selection rect) is based roughly on @@ -317,6 +339,11 @@ IntRect TransparencyAwareUniscribePainter::estimateTextBounds() } // namespace +bool Font::canReturnFallbackFontsForComplexText() +{ + return false; +} + void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, @@ -416,6 +443,20 @@ void Font::drawComplexText(GraphicsContext* graphicsContext, SetTextColor(hdc, skia::SkColorToCOLORREF(color)); SetBkMode(hdc, TRANSPARENT); + // If there is a non-blur shadow and both the fill color and shadow color + // are opaque, handle without skia. + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + if (graphicsContext->getShadow(shadowSize, shadowBlur, shadowColor) && windowsCanHandleDrawTextShadow(graphicsContext)) { + COLORREF textColor = skia::SkColorToCOLORREF(SkColorSetARGB(255, shadowColor.red(), shadowColor.green(), shadowColor.blue())); + COLORREF savedTextColor = GetTextColor(hdc); + SetTextColor(hdc, textColor); + state.draw(graphicsContext, hdc, static_cast<int>(point.x()) + shadowSize.width(), + static_cast<int>(point.y() - ascent()) + shadowSize.height(), from, to); + SetTextColor(hdc, savedTextColor); + } + // Uniscribe counts the coordinates from the upper left, while WebKit uses // the baseline, so we have to subtract off the ascent. state.draw(graphicsContext, hdc, static_cast<int>(point.x()), @@ -424,7 +465,7 @@ void Font::drawComplexText(GraphicsContext* graphicsContext, context->canvas()->endPlatformPaint(); } -float Font::floatWidthForComplexText(const TextRun& run) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */) const { UniscribeHelperTextRun state(run, *this); return static_cast<float>(state.width()); diff --git a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp index 1e923ac..e99c12a 100644 --- a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp @@ -116,7 +116,7 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b // Streams the concatenation of a header and font data. class EOTStream { public: - EOTStream(const Vector<uint8_t, 512>& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength) + 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) @@ -130,7 +130,7 @@ public: size_t read(void* buffer, size_t count); private: - const Vector<uint8_t, 512>& m_eotHeader; + const EOTHeader& m_eotHeader; const SharedBuffer* m_fontData; size_t m_overlayDst; size_t m_overlaySrc; @@ -200,7 +200,7 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) // TTLoadEmbeddedFont works only with Embedded OpenType (.eot) data, // so we need to create an EOT header and prepend it to the font data. - Vector<uint8_t, 512> eotHeader; + EOTHeader eotHeader; size_t overlayDst; size_t overlaySrc; size_t overlayLength; diff --git a/WebCore/platform/graphics/chromium/FontLinux.cpp b/WebCore/platform/graphics/chromium/FontLinux.cpp index 2b7c562..a952685 100644 --- a/WebCore/platform/graphics/chromium/FontLinux.cpp +++ b/WebCore/platform/graphics/chromium/FontLinux.cpp @@ -46,6 +46,11 @@ namespace WebCore { +bool Font::canReturnFallbackFontsForComplexText() +{ + return false; +} + void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { @@ -111,7 +116,7 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, notImplemented(); } -float Font::floatWidthForComplexText(const TextRun& run) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */) const { notImplemented(); return 0; diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp index 7b7d197..e6a61f6 100644 --- a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp +++ b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp @@ -95,6 +95,11 @@ void FontPlatformData::setupPaint(SkPaint* paint) const paint->setTextEncoding(SkPaint::kUTF16_TextEncoding); } +SkFontID FontPlatformData::uniqueID() const +{ + return m_typeface->uniqueID(); +} + bool FontPlatformData::operator==(const FontPlatformData& a) const { // If either of the typeface pointers are invalid (either NULL or the diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h index ec7d837..c63a860 100644 --- a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h +++ b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h @@ -36,6 +36,7 @@ class SkPaint; class SkTypeface; +typedef uint32_t SkFontID; namespace WebCore { @@ -90,6 +91,12 @@ public: // ------------------------------------------------------------------------- void setupPaint(SkPaint*) const; + // ------------------------------------------------------------------------- + // Return Skia's unique id for this font. This encodes both the style and + // the font's file name so refers to a single face. + // ------------------------------------------------------------------------- + SkFontID uniqueID() const; + unsigned hash() const; float size() const { return m_textSize; } diff --git a/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp index ed326c8..9596a4c 100644 --- a/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp @@ -120,6 +120,52 @@ void initializeScriptFontMap(ScriptToFontMap& scriptFontMap) scriptFontMap[USCRIPT_HAN] = localeFamily; } +// There are a lot of characters in USCRIPT_COMMON that can be covered +// by fonts for scripts closely related to them. See +// http://unicode.org/cldr/utility/list-unicodeset.jsp?a=[:Script=Common:] +// FIXME: make this more efficient with a wider coverage +UScriptCode getScriptBasedOnUnicodeBlock(int ucs4) +{ + UBlockCode block = ublock_getCode(ucs4); + switch (block) { + case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION: + return USCRIPT_HAN; + case UBLOCK_HIRAGANA: + case UBLOCK_KATAKANA: + return USCRIPT_HIRAGANA; + case UBLOCK_ARABIC: + return USCRIPT_ARABIC; + case UBLOCK_THAI: + return USCRIPT_THAI; + case UBLOCK_GREEK: + return USCRIPT_GREEK; + case UBLOCK_DEVANAGARI: + // For Danda and Double Danda (U+0964, U+0965), use a Devanagari + // font for now although they're used by other scripts as well. + // Without a context, we can't do any better. + return USCRIPT_DEVANAGARI; + case UBLOCK_ARMENIAN: + return USCRIPT_ARMENIAN; + case UBLOCK_GEORGIAN: + return USCRIPT_GEORGIAN; + case UBLOCK_KANNADA: + return USCRIPT_KANNADA; + default: + return USCRIPT_COMMON; + } +} + +UScriptCode getScript(int ucs4) +{ + UErrorCode err = U_ZERO_ERROR; + UScriptCode script = uscript_getScript(ucs4, &err); + // If script is invalid, common or inherited or there's an error, + // infer a script based on the unicode block of a character. + if (script <= USCRIPT_INHERITED || U_FAILURE(err)) + script = getScriptBasedOnUnicodeBlock(ucs4); + return script; +} + const int kUndefinedAscent = std::numeric_limits<int>::min(); // Given an HFONT, return the ascent. If GetTextMetrics fails, @@ -209,11 +255,9 @@ const UChar* getFallbackFamily(const UChar* characters, // to get a font required to render the string. int i = 0; UChar32 ucs4 = 0; - while (i < length && script == USCRIPT_COMMON || script == USCRIPT_INVALID_CODE) { + while (i < length && script == USCRIPT_COMMON) { U16_NEXT(characters, i, length, ucs4); - UErrorCode err = U_ZERO_ERROR; - script = uscript_getScript(ucs4, &err); - // silently ignore the error + script = getScript(ucs4); } // For the full-width ASCII characters (U+FF00 - U+FF5E), use the font for @@ -223,46 +267,8 @@ const UChar* getFallbackFamily(const UChar* characters, if (0xFF00 < ucs4 && ucs4 < 0xFF5F) script = USCRIPT_HAN; - // There are a lot of characters in USCRIPT_COMMON that can be covered - // by fonts for scripts closely related to them. See - // http://unicode.org/cldr/utility/list-unicodeset.jsp?a=[:Script=Common:] - // FIXME: make this more efficient with a wider coverage - if (script == USCRIPT_COMMON || script == USCRIPT_INHERITED) { - UBlockCode block = ublock_getCode(ucs4); - switch (block) { - case UBLOCK_BASIC_LATIN: - script = USCRIPT_LATIN; - break; - case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION: - script = USCRIPT_HAN; - break; - case UBLOCK_HIRAGANA: - case UBLOCK_KATAKANA: - script = USCRIPT_HIRAGANA; - break; - case UBLOCK_ARABIC: - script = USCRIPT_ARABIC; - break; - case UBLOCK_GREEK: - script = USCRIPT_GREEK; - break; - case UBLOCK_DEVANAGARI: - // For Danda and Double Danda (U+0964, U+0965), use a Devanagari - // font for now although they're used by other scripts as well. - // Without a context, we can't do any better. - script = USCRIPT_DEVANAGARI; - break; - case UBLOCK_ARMENIAN: - script = USCRIPT_ARMENIAN; - break; - case UBLOCK_GEORGIAN: - script = USCRIPT_GEORGIAN; - break; - case UBLOCK_KANNADA: - script = USCRIPT_KANNADA; - break; - } - } + if (script == USCRIPT_COMMON) + script = getScriptBasedOnUnicodeBlock(ucs4); // Another lame work-around to cover non-BMP characters. const UChar* family = getFontFamilyForScript(script, generic); diff --git a/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp index 31c5256..2cb1cc5 100644 --- a/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp @@ -72,7 +72,7 @@ static bool fillBMPGlyphs(unsigned offset, bool recurse) { HDC dc = GetDC((HWND)0); - HGDIOBJ oldFont = SelectObject(dc, fontData->m_font.hfont()); + HGDIOBJ oldFont = SelectObject(dc, fontData->platformData().hfont()); TEXTMETRIC tm = {0}; if (!GetTextMetrics(dc, &tm)) { @@ -80,7 +80,7 @@ static bool fillBMPGlyphs(unsigned offset, ReleaseDC(0, dc); if (recurse) { - if (ChromiumBridge::ensureFontLoaded(fontData->m_font.hfont())) + if (ChromiumBridge::ensureFontLoaded(fontData->platformData().hfont())) return fillBMPGlyphs(offset, length, buffer, page, fontData, false); else { fillEmptyGlyphs(page); @@ -191,9 +191,9 @@ static bool fillNonBMPGlyphs(unsigned offset, bool haveGlyphs = false; UniscribeHelperTextRun state(buffer, length * 2, false, - fontData->m_font.hfont(), - fontData->m_font.scriptCache(), - fontData->m_font.scriptFontProperties()); + fontData->platformData().hfont(), + fontData->platformData().scriptCache(), + fontData->platformData().scriptFontProperties()); state.setInhibitLigate(true); state.setDisableFontFallback(true); state.init(); diff --git a/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h b/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h index e8ba0ad..534244d 100644 --- a/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h +++ b/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h @@ -37,67 +37,12 @@ namespace WebCore { -class MediaPlayerPrivate : public MediaPlayerPrivateInterface { +class MediaPlayerPrivate { public: static void registerMediaEngine(MediaEngineRegistrar); - ~MediaPlayerPrivate(); - - IntSize naturalSize() const; - bool hasVideo() const; - - void load(const String& url); - void cancelLoad(); - - void play(); - void pause(); - - bool paused() const; - bool seeking() const; - - float duration() const; - float currentTime() const; - void seek(float time); - void setEndTime(float); - - void setRate(float); - void setVolume(float); - - int dataRate() const; - - MediaPlayer::NetworkState networkState() const; - MediaPlayer::ReadyState readyState() const; - - float maxTimeBuffered() const; - float maxTimeSeekable() const; - unsigned bytesLoaded() const; - bool totalBytesKnown() const; - unsigned totalBytes() const; - - void setVisible(bool); - void setSize(const IntSize&); - - void paint(GraphicsContext*, const IntRect&); - - // Public methods to be called by WebMediaPlayer - FrameView* frameView(); - void networkStateChanged(); - void readyStateChanged(); - void timeChanged(); - void volumeChanged(); - void repaint(); - -private: - MediaPlayerPrivate(MediaPlayer*); - static MediaPlayerPrivateInterface* create(MediaPlayer* player); - static void getSupportedTypes(HashSet<String>&); - static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs); - static bool isAvailable(); - - MediaPlayer* m_player; - void* m_data; }; -} // namespace WebCore +} // namespace WebCore #endif diff --git a/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp b/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp index 06e997f..6f5ce90 100644 --- a/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp @@ -54,11 +54,11 @@ static inline float scaleEmToUnits(float x, int unitsPerEm) void SimpleFontData::platformInit() { HDC dc = GetDC(0); - HGDIOBJ oldFont = SelectObject(dc, m_font.hfont()); + HGDIOBJ oldFont = SelectObject(dc, m_platformData.hfont()); TEXTMETRIC textMetric = {0}; if (!GetTextMetrics(dc, &textMetric)) { - if (ChromiumBridge::ensureFontLoaded(m_font.hfont())) { + if (ChromiumBridge::ensureFontLoaded(m_platformData.hfont())) { // Retry GetTextMetrics. // FIXME: Handle gracefully the error if this call also fails. // See http://crbug.com/6401. @@ -91,6 +91,11 @@ void SimpleFontData::platformInit() ReleaseDC(0, dc); } +void SimpleFontData::platformCharWidthInit() +{ + // charwidths are set in platformInit. +} + void SimpleFontData::platformDestroy() { // We don't hash this on Win32, so it's effectively owned by us. @@ -102,7 +107,7 @@ SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDes { if (!m_smallCapsFontData) { LOGFONT winFont; - GetObject(m_font.hfont(), sizeof(LOGFONT), &winFont); + GetObject(m_platformData.hfont(), sizeof(LOGFONT), &winFont); float smallCapsSize = 0.70f * fontDescription.computedSize(); // Unlike WebKit trunk, we don't multiply the size by 32. That seems // to be some kind of artifact of their CG backend, or something. @@ -125,13 +130,13 @@ void SimpleFontData::determinePitch() { // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that. HDC dc = GetDC(0); - HGDIOBJ oldFont = SelectObject(dc, m_font.hfont()); + HGDIOBJ oldFont = SelectObject(dc, m_platformData.hfont()); // Yes, this looks backwards, but the fixed pitch bit is actually set if the font // is *not* fixed pitch. Unbelievable but true. TEXTMETRIC textMetric = {0}; if (!GetTextMetrics(dc, &textMetric)) { - if (ChromiumBridge::ensureFontLoaded(m_font.hfont())) { + if (ChromiumBridge::ensureFontLoaded(m_platformData.hfont())) { // Retry GetTextMetrics. // FIXME: Handle gracefully the error if this call also fails. // See http://crbug.com/6401. @@ -149,12 +154,12 @@ void SimpleFontData::determinePitch() float SimpleFontData::platformWidthForGlyph(Glyph glyph) const { HDC dc = GetDC(0); - HGDIOBJ oldFont = SelectObject(dc, m_font.hfont()); + HGDIOBJ oldFont = SelectObject(dc, m_platformData.hfont()); int width = 0; if (!GetCharWidthI(dc, glyph, 1, 0, &width)) { // Ask the browser to preload the font and retry. - if (ChromiumBridge::ensureFontLoaded(m_font.hfont())) { + if (ChromiumBridge::ensureFontLoaded(m_platformData.hfont())) { // FIXME: Handle gracefully the error if this call also fails. // See http://crbug.com/6401. if (!GetCharWidthI(dc, glyph, 1, 0, &width)) diff --git a/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp b/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp index 8200175..3bff83f 100644 --- a/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp +++ b/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp @@ -36,33 +36,54 @@ #include "FloatRect.h" #include "FontDescription.h" #include "Logging.h" -#include "NotImplemented.h" +#include "VDMXParser.h" +#include "SkFontHost.h" #include "SkPaint.h" -#include "SkTypeface.h" #include "SkTime.h" +#include "SkTypeface.h" +#include "SkTypes.h" namespace WebCore { // Smallcaps versions of fonts are 70% the size of the normal font. static const float smallCapsFraction = 0.7f; +// This is the largest VDMX table which we'll try to load and parse. +static const size_t maxVDMXTableSize = 1024 * 1024; // 1 MB void SimpleFontData::platformInit() { SkPaint paint; SkPaint::FontMetrics metrics; - m_font.setupPaint(&paint); + m_platformData.setupPaint(&paint); paint.getFontMetrics(&metrics); + const SkFontID fontID = m_platformData.uniqueID(); + + static const uint32_t vdmxTag = SkSetFourByteTag('V', 'D', 'M', 'X'); + int pixelSize = m_platformData.size() + 0.5; + int vdmxAscent, vdmxDescent; + bool isVDMXValid = false; + + size_t vdmxSize = SkFontHost::GetTableSize(fontID, vdmxTag); + if (vdmxSize && vdmxSize < maxVDMXTableSize) { + uint8_t* vdmxTable = (uint8_t*) fastMalloc(vdmxSize); + if (vdmxTable + && SkFontHost::GetTableData(fontID, vdmxTag, 0, vdmxSize, vdmxTable) == vdmxSize + && parseVDMX(&vdmxAscent, &vdmxDescent, vdmxTable, vdmxSize, pixelSize)) + isVDMXValid = true; + fastFree(vdmxTable); + } // Beware those who step here: This code is designed to match Win32 font // metrics *exactly*. - if (metrics.fVDMXMetricsValid) { - m_ascent = metrics.fVDMXAscent; - m_descent = metrics.fVDMXDescent; + if (isVDMXValid) { + m_ascent = vdmxAscent; + m_descent = -vdmxDescent; } else { + SkScalar height = -metrics.fAscent + metrics.fDescent + metrics.fLeading; m_ascent = SkScalarRound(-metrics.fAscent); - m_descent = SkScalarRound(metrics.fHeight) - m_ascent; + m_descent = SkScalarRound(height) - m_ascent; } if (metrics.fXHeight) @@ -79,7 +100,8 @@ void SimpleFontData::platformInit() // calculated for us, but we need to calculate m_maxCharWidth and // m_avgCharWidth in order for text entry widgets to be sized correctly. - m_maxCharWidth = SkScalarRound(metrics.fXRange * SkScalarRound(m_font.size())); + SkScalar xRange = metrics.fXMax - metrics.fXMin; + m_maxCharWidth = SkScalarRound(xRange * SkScalarRound(m_platformData.size())); if (metrics.fAvgCharWidth) m_avgCharWidth = SkScalarRound(metrics.fAvgCharWidth); @@ -98,6 +120,11 @@ void SimpleFontData::platformInit() } } +void SimpleFontData::platformCharWidthInit() +{ + // charwidths are set in platformInit. +} + void SimpleFontData::platformDestroy() { delete m_smallCapsFontData; @@ -108,7 +135,7 @@ SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDes { if (!m_smallCapsFontData) { const float smallCapsSize = lroundf(fontDescription.computedSize() * smallCapsFraction); - m_smallCapsFontData = new SimpleFontData(FontPlatformData(m_font, smallCapsSize)); + m_smallCapsFontData = new SimpleFontData(FontPlatformData(m_platformData, smallCapsSize)); } return m_smallCapsFontData; @@ -120,7 +147,7 @@ bool SimpleFontData::containsCharacters(const UChar* characters, int length) con static const unsigned maxBufferCount = 64; uint16_t glyphs[maxBufferCount]; - m_font.setupPaint(&paint); + m_platformData.setupPaint(&paint); paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); while (length > 0) { @@ -151,11 +178,11 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const SkPaint paint; - m_font.setupPaint(&paint); + m_platformData.setupPaint(&paint); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); SkScalar width = paint.measureText(&glyph, 2); - + return SkScalarToFloat(width); } diff --git a/WebCore/platform/graphics/chromium/TransparencyWin.cpp b/WebCore/platform/graphics/chromium/TransparencyWin.cpp index 8c790af..d3ced81 100644 --- a/WebCore/platform/graphics/chromium/TransparencyWin.cpp +++ b/WebCore/platform/graphics/chromium/TransparencyWin.cpp @@ -109,7 +109,7 @@ class TransparencyWin::OwnedBuffers { public: OwnedBuffers(const IntSize& size, bool needReferenceBuffer) { - m_destBitmap.adopt(ImageBuffer::create(size, false)); + m_destBitmap = ImageBuffer::create(size, false); if (needReferenceBuffer) { m_referenceBitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height()); diff --git a/WebCore/platform/graphics/chromium/VDMXParser.cpp b/WebCore/platform/graphics/chromium/VDMXParser.cpp new file mode 100644 index 0000000..3347226 --- /dev/null +++ b/WebCore/platform/graphics/chromium/VDMXParser.cpp @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2008, 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * 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 <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +// For htons/ntohs +#include <arpa/inet.h> + +// Buffer helper class +// +// This class perform some trival buffer operations while checking for +// out-of-bounds errors. As a family they return false if anything is amiss, +// updating the current offset otherwise. +class Buffer { +public: + Buffer(const uint8_t* buffer, size_t length) + : m_buffer(buffer) + , m_length(length) + , m_offset(0) { } + + bool skip(size_t numBytes) + { + if (m_offset + numBytes > m_length) + return false; + m_offset += numBytes; + return true; + } + + bool readU8(uint8_t* value) + { + if (m_offset + sizeof(uint8_t) > m_length) + return false; + *value = m_buffer[m_offset]; + m_offset += sizeof(uint8_t); + return true; + } + + bool readU16(uint16_t* value) + { + if (m_offset + sizeof(uint16_t) > m_length) + return false; + memcpy(value, m_buffer + m_offset, sizeof(uint16_t)); + *value = ntohs(*value); + m_offset += sizeof(uint16_t); + return true; + } + + bool readS16(int16_t* value) + { + return readU16(reinterpret_cast<uint16_t*>(value)); + } + + size_t offset() const + { + return m_offset; + } + + void setOffset(size_t newoffset) + { + m_offset = newoffset; + } + +private: + const uint8_t *const m_buffer; + const size_t m_length; + size_t m_offset; +}; + +// VDMX parsing code. +// +// VDMX tables are found in some TrueType/OpenType fonts and contain +// ascender/descender overrides for certain (usually small) sizes. This is +// needed in order to match font metrics on Windows. +// +// Freetype does not parse these tables so we do so here. + +namespace WebCore { + +// Parse a TrueType VDMX table. +// yMax: (output) the ascender value from the table +// yMin: (output) the descender value from the table (negative!) +// vdmx: the table bytes +// vdmxLength: length of @vdmx, in bytes +// targetPixelSize: the pixel size of the font (e.g. 16) +// +// Returns true iff a suitable match are found. Otherwise, *yMax and *yMin are +// untouched. size_t must be 32-bits to avoid overflow. +// +// See http://www.microsoft.com/opentype/otspec/vdmx.htm +bool parseVDMX(int* yMax, int* yMin, + const uint8_t* vdmx, size_t vdmxLength, + unsigned targetPixelSize) +{ + Buffer buf(vdmx, vdmxLength); + + // We ignore the version. Future tables should be backwards compatible with + // this layout. + uint16_t numRatios; + if (!buf.skip(4) || !buf.readU16(&numRatios)) + return false; + + // Now we have two tables. Firstly we have @numRatios Ratio records, then a + // matching array of @numRatios offsets. We save the offset of the beginning + // of this second table. + // + // Range 6 <= x <= 262146 + unsigned long offsetTableOffset = + buf.offset() + 4 /* sizeof struct ratio */ * numRatios; + + unsigned desiredRatio = 0xffffffff; + // We read 4 bytes per record, so the offset range is + // 6 <= x <= 524286 + for (unsigned i = 0; i < numRatios; ++i) { + uint8_t xRatio, yRatio1, yRatio2; + + if (!buf.skip(1) + || !buf.readU8(&xRatio) + || !buf.readU8(&yRatio1) + || !buf.readU8(&yRatio2)) + return false; + + // This either covers 1:1, or this is the default entry (0, 0, 0) + if ((xRatio == 1 && yRatio1 <= 1 && yRatio2 >= 1) + || (xRatio == 0 && yRatio1 == 0 && yRatio2 == 0)) { + desiredRatio = i; + break; + } + } + + if (desiredRatio == 0xffffffff) // no ratio found + return false; + + // Range 10 <= x <= 393216 + buf.setOffset(offsetTableOffset + sizeof(uint16_t) * desiredRatio); + + // Now we read from the offset table to get the offset of another array + uint16_t groupOffset; + if (!buf.readU16(&groupOffset)) + return false; + // Range 0 <= x <= 65535 + buf.setOffset(groupOffset); + + uint16_t numRecords; + if (!buf.readU16(&numRecords) || !buf.skip(sizeof(uint16_t))) + return false; + + // We read 6 bytes per record, so the offset range is + // 4 <= x <= 458749 + for (unsigned i = 0; i < numRecords; ++i) { + uint16_t pixelSize; + if (!buf.readU16(&pixelSize)) + return false; + // the entries are sorted, so we can abort early if need be + if (pixelSize > targetPixelSize) + return false; + + if (pixelSize == targetPixelSize) { + int16_t tempYMax, tempYMin; + if (!buf.readS16(&tempYMax) + || !buf.readS16(&tempYMin)) + return false; + *yMin = tempYMin; + *yMax = tempYMax; + return true; + } + if (!buf.skip(2 * sizeof(int16_t))) + return false; + } + + return false; +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/KeyboardCodes.h b/WebCore/platform/graphics/chromium/VDMXParser.h index 10eb0cd..ef625b7 100644 --- a/WebCore/platform/chromium/KeyboardCodes.h +++ b/WebCore/platform/graphics/chromium/VDMXParser.h @@ -1,10 +1,10 @@ /* - * Copyright (c) 2008, 2009, Google 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: - * + * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above @@ -14,7 +14,7 @@ * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -28,13 +28,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef KeyboardCodes_h -#define KeyboardCodes_h +#ifndef VDMXParser_h +#define VDMXParser_h -#if PLATFORM(WIN_OS) -#include "KeyboardCodesWin.h" -#else -#include "KeyboardCodesPosix.h" -#endif +namespace WebCore { + bool parseVDMX(int* ymax, int* ymin, + const uint8_t* vdmx, size_t vdmxLength, + unsigned targetPixelSize); +} // namespace WebCore #endif diff --git a/WebCore/platform/graphics/filters/FEBlend.cpp b/WebCore/platform/graphics/filters/FEBlend.cpp index 7210367..86b702f 100644 --- a/WebCore/platform/graphics/filters/FEBlend.cpp +++ b/WebCore/platform/graphics/filters/FEBlend.cpp @@ -21,9 +21,11 @@ #include "config.h" -#if ENABLE(SVG) && ENABLE(SVG_FILTERS) +#if ENABLE(FILTERS) #include "FEBlend.h" +#include "Filter.h" + namespace WebCore { FEBlend::FEBlend(FilterEffect* in, FilterEffect* in2, BlendModeType mode) @@ -59,7 +61,7 @@ void FEBlend::setBlendMode(BlendModeType mode) m_mode = mode; } -void FEBlend::apply() +void FEBlend::apply(Filter*) { } @@ -69,4 +71,4 @@ void FEBlend::dump() } // namespace WebCore -#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS) +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FEBlend.h b/WebCore/platform/graphics/filters/FEBlend.h index b2835e8..dec04ac 100644 --- a/WebCore/platform/graphics/filters/FEBlend.h +++ b/WebCore/platform/graphics/filters/FEBlend.h @@ -22,9 +22,11 @@ #ifndef SVGFEBlend_h #define SVGFEBlend_h -#if ENABLE(SVG) && ENABLE(SVG_FILTERS) +#if ENABLE(FILTERS) #include "FilterEffect.h" +#include "Filter.h" + namespace WebCore { enum BlendModeType { @@ -46,8 +48,8 @@ namespace WebCore { BlendModeType blendMode() const; void setBlendMode(BlendModeType); - virtual void apply(); - virtual void dump(); + void apply(Filter*); + void dump(); private: FEBlend(FilterEffect*, FilterEffect*, BlendModeType); @@ -59,6 +61,6 @@ namespace WebCore { } // namespace WebCore -#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS) +#endif // ENABLE(FILTERS) #endif // SVGFEBlend_h diff --git a/WebCore/platform/graphics/filters/FEColorMatrix.cpp b/WebCore/platform/graphics/filters/FEColorMatrix.cpp index f783106..8704e64 100644 --- a/WebCore/platform/graphics/filters/FEColorMatrix.cpp +++ b/WebCore/platform/graphics/filters/FEColorMatrix.cpp @@ -21,9 +21,11 @@ #include "config.h" -#if ENABLE(SVG) && ENABLE(SVG_FILTERS) +#if ENABLE(FILTERS) #include "FEColorMatrix.h" +#include "Filter.h" + namespace WebCore { FEColorMatrix::FEColorMatrix(FilterEffect* in, ColorMatrixType type, const Vector<float>& values) @@ -59,7 +61,7 @@ void FEColorMatrix::setValues(const Vector<float> &values) m_values = values; } -void FEColorMatrix::apply() +void FEColorMatrix::apply(Filter*) { } @@ -69,4 +71,4 @@ void FEColorMatrix::dump() } // namespace WebCore -#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS) +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FEColorMatrix.h b/WebCore/platform/graphics/filters/FEColorMatrix.h index d8193ed..eeb3557 100644 --- a/WebCore/platform/graphics/filters/FEColorMatrix.h +++ b/WebCore/platform/graphics/filters/FEColorMatrix.h @@ -22,8 +22,10 @@ #ifndef SVGFEColorMatrix_h #define SVGFEColorMatrix_h -#if ENABLE(SVG) && ENABLE(SVG_FILTERS) +#if ENABLE(FILTERS) #include "FilterEffect.h" + +#include "Filter.h" #include <wtf/Vector.h> namespace WebCore { @@ -46,8 +48,8 @@ namespace WebCore { const Vector<float>& values() const; void setValues(const Vector<float>&); - virtual void apply(); - virtual void dump(); + void apply(Filter*); + void dump(); private: FEColorMatrix(FilterEffect*, ColorMatrixType, const Vector<float>&); @@ -59,6 +61,6 @@ namespace WebCore { } // namespace WebCore -#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS) +#endif // ENABLE(FILTERS) #endif // SVGFEColorMatrix_h diff --git a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp index 708ea3e..54ac123 100644 --- a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp +++ b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp @@ -21,9 +21,11 @@ #include "config.h" -#if ENABLE(SVG) && ENABLE(SVG_FILTERS) +#if ENABLE(FILTERS) #include "FEComponentTransfer.h" +#include "Filter.h" + namespace WebCore { FEComponentTransfer::FEComponentTransfer(FilterEffect* in, const ComponentTransferFunction& redFunc, @@ -83,7 +85,7 @@ void FEComponentTransfer::setAlphaFunction(const ComponentTransferFunction& func m_alphaFunc = func; } -void FEComponentTransfer::apply() +void FEComponentTransfer::apply(Filter*) { } @@ -93,4 +95,4 @@ void FEComponentTransfer::dump() } // namespace WebCore -#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS) +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FEComponentTransfer.h b/WebCore/platform/graphics/filters/FEComponentTransfer.h index 20d70c0..cc1d1f8 100644 --- a/WebCore/platform/graphics/filters/FEComponentTransfer.h +++ b/WebCore/platform/graphics/filters/FEComponentTransfer.h @@ -22,10 +22,11 @@ #ifndef SVGFEComponentTransfer_h #define SVGFEComponentTransfer_h -#if ENABLE(SVG) && ENABLE(SVG_FILTERS) +#if ENABLE(FILTERS) #include "FilterEffect.h" -#include "SVGFEDisplacementMap.h" +#include "SVGFEDisplacementMap.h" +#include "Filter.h" #include <wtf/Vector.h> namespace WebCore { @@ -78,8 +79,8 @@ namespace WebCore { ComponentTransferFunction alphaFunction() const; void setAlphaFunction(const ComponentTransferFunction&); - virtual void apply(); - virtual void dump(); + void apply(Filter*); + void dump(); private: FEComponentTransfer(FilterEffect*,const ComponentTransferFunction&, const ComponentTransferFunction&, @@ -94,6 +95,6 @@ namespace WebCore { } // namespace WebCore -#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS) +#endif // ENABLE(FILTERS) #endif // SVGFEComponentTransfer_h diff --git a/WebCore/platform/graphics/filters/FEComposite.cpp b/WebCore/platform/graphics/filters/FEComposite.cpp index 0b5ce94..0706358 100644 --- a/WebCore/platform/graphics/filters/FEComposite.cpp +++ b/WebCore/platform/graphics/filters/FEComposite.cpp @@ -21,9 +21,11 @@ #include "config.h" -#if ENABLE(SVG) && ENABLE(SVG_FILTERS) +#if ENABLE(FILTERS) #include "FEComposite.h" +#include "Filter.h" + namespace WebCore { FEComposite::FEComposite(FilterEffect* in, FilterEffect* in2, const CompositeOperationType& type, @@ -95,7 +97,7 @@ void FEComposite::setK4(float k4) m_k4 = k4; } -void FEComposite::apply() +void FEComposite::apply(Filter*) { } @@ -105,4 +107,4 @@ void FEComposite::dump() } // namespace WebCore -#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS) +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FEComposite.h b/WebCore/platform/graphics/filters/FEComposite.h index d205395..b623cce 100644 --- a/WebCore/platform/graphics/filters/FEComposite.h +++ b/WebCore/platform/graphics/filters/FEComposite.h @@ -22,9 +22,11 @@ #ifndef SVGFEComposite_h #define SVGFEComposite_h -#if ENABLE(SVG) && ENABLE(SVG_FILTERS) +#if ENABLE(FILTERS) #include "FilterEffect.h" + #include "PlatformString.h" +#include "Filter.h" namespace WebCore { @@ -58,8 +60,8 @@ namespace WebCore { float k4() const; void setK4(float); - virtual void apply(); - virtual void dump(); + void apply(Filter*); + void dump(); private: FEComposite(FilterEffect*, FilterEffect*, const CompositeOperationType&, @@ -76,6 +78,6 @@ namespace WebCore { } // namespace WebCore -#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS) +#endif // ENABLE(FILTERS) #endif // SVGFEComposite_h diff --git a/WebCore/platform/graphics/filters/Filter.h b/WebCore/platform/graphics/filters/Filter.h new file mode 100644 index 0000000..84909da --- /dev/null +++ b/WebCore/platform/graphics/filters/Filter.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * aint with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef Filter_h +#define Filter_h + +#if ENABLE(FILTERS) +#include "Image.h" +#include "StringHash.h" + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + + class FilterEffect; + + class Filter : public RefCounted<Filter> { + public: + virtual ~Filter() { } + + void setSourceImage(PassRefPtr<Image> image) { m_image = image; } + Image* sourceImage() { return m_image.get(); } + + virtual void calculateEffectSubRegion(FilterEffect*) = 0; + + private: + RefPtr<Image> m_image; + }; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // Filter_h diff --git a/WebCore/platform/graphics/filters/FilterEffect.cpp b/WebCore/platform/graphics/filters/FilterEffect.cpp new file mode 100644 index 0000000..cd74992 --- /dev/null +++ b/WebCore/platform/graphics/filters/FilterEffect.cpp @@ -0,0 +1,46 @@ +/* + Copyright (C) Alex Mathews <possessedpenguinbob@gmail.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 + 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 "FilterEffect.h" + +namespace WebCore { + +FilterEffect::FilterEffect() + : m_xBBoxMode(false) + , m_yBBoxMode(false) + , m_widthBBoxMode(false) + , m_heightBBoxMode(false) +{ +} + +FilterEffect::~FilterEffect() +{ +} + +TextStream& FilterEffect::externalRepresentation(TextStream& ts) const +{ + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FilterEffect.h b/WebCore/platform/graphics/filters/FilterEffect.h new file mode 100644 index 0000000..e2a058d --- /dev/null +++ b/WebCore/platform/graphics/filters/FilterEffect.h @@ -0,0 +1,81 @@ +/* + Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com> + 2009 Dirk Schulze <krit@webkit.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef FilterEffect_h +#define FilterEffect_h + +#if ENABLE(FILTERS) +#include "Filter.h" +#include "FloatRect.h" +#include "ImageBuffer.h" +#include "TextStream.h" + +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + + class FilterEffect : public RefCounted<FilterEffect> { + public: + virtual ~FilterEffect(); + + bool xBoundingBoxMode() const { return m_xBBoxMode; } + void setXBoundingBoxMode(bool bboxMode) { m_xBBoxMode = bboxMode; } + + bool yBoundingBoxMode() const { return m_yBBoxMode; } + void setYBoundingBoxMode(bool bboxMode) { m_yBBoxMode = bboxMode; } + + bool widthBoundingBoxMode() const { return m_widthBBoxMode; } + void setWidthBoundingBoxMode(bool bboxMode) { m_widthBBoxMode = bboxMode; } + + bool heightBoundingBoxMode() const { return m_heightBBoxMode; } + void setHeightBoundingBoxMode(bool bboxMode) { m_heightBBoxMode = bboxMode; } + + FloatRect subRegion() const { return m_subRegion; } + void setSubRegion(const FloatRect& subRegion) { m_subRegion = subRegion; } + + // The result is bounded by the size of the filter primitive to save resources + ImageBuffer* resultImage() { return m_effectBuffer.get(); } + void setEffectBuffer(ImageBuffer* effectBuffer) { m_effectBuffer.set(effectBuffer); } + + virtual void apply(Filter*) = 0; + virtual void dump() = 0; + + virtual TextStream& externalRepresentation(TextStream&) const; + protected: + FilterEffect(); + + private: + + bool m_xBBoxMode : 1; + bool m_yBBoxMode : 1; + bool m_widthBBoxMode : 1; + bool m_heightBBoxMode : 1; + + FloatRect m_subRegion; + + mutable OwnPtr<ImageBuffer> m_effectBuffer; + }; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FilterEffect_h diff --git a/WebCore/platform/graphics/filters/SourceAlpha.cpp b/WebCore/platform/graphics/filters/SourceAlpha.cpp new file mode 100644 index 0000000..646a57b --- /dev/null +++ b/WebCore/platform/graphics/filters/SourceAlpha.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * aint with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "SourceAlpha.h" + +#include "GraphicsContext.h" +#include "PlatformString.h" +#include "Filter.h" + +#include <wtf/StdLibExtras.h> + +namespace WebCore { + +PassRefPtr<SourceAlpha> SourceAlpha::create() +{ + return adoptRef(new SourceAlpha); +} + +const AtomicString& SourceAlpha::effectName() +{ + DEFINE_STATIC_LOCAL(const AtomicString, s_effectName, ("SourceAlpha")); + return s_effectName; +} + +void SourceAlpha::apply(Filter*) +{ +} + +void SourceAlpha::dump() +{ +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/SourceAlpha.h b/WebCore/platform/graphics/filters/SourceAlpha.h new file mode 100644 index 0000000..21497aa --- /dev/null +++ b/WebCore/platform/graphics/filters/SourceAlpha.h @@ -0,0 +1,47 @@ +/* + Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef SourceAlpha_h +#define SourceAlpha_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" + +#include "PlatformString.h" +#include "Filter.h" + +namespace WebCore { + + class SourceAlpha : public FilterEffect { + public: + static PassRefPtr<SourceAlpha> create(); + + static const AtomicString& effectName(); + + void apply(Filter*); + void dump(); + + private: + SourceAlpha() { } + }; +} //namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // SourceAlpha_h diff --git a/WebCore/platform/graphics/filters/SourceGraphic.cpp b/WebCore/platform/graphics/filters/SourceGraphic.cpp new file mode 100644 index 0000000..39d4810 --- /dev/null +++ b/WebCore/platform/graphics/filters/SourceGraphic.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * aint with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "SourceGraphic.h" + +#include "GraphicsContext.h" +#include "PlatformString.h" +#include "Filter.h" + +#include <wtf/StdLibExtras.h> + +namespace WebCore { + +PassRefPtr<SourceGraphic> SourceGraphic::create() +{ + return adoptRef(new SourceGraphic); +} + +const AtomicString& SourceGraphic::effectName() +{ + DEFINE_STATIC_LOCAL(const AtomicString, s_effectName, ("SourceGraphic")); + return s_effectName; +} + +void SourceGraphic::apply(Filter*) +{ +} + +void SourceGraphic::dump() +{ +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/SourceGraphic.h b/WebCore/platform/graphics/filters/SourceGraphic.h new file mode 100644 index 0000000..363fb97 --- /dev/null +++ b/WebCore/platform/graphics/filters/SourceGraphic.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com> + 2009 Dirk Schulze <krit@webkit.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef SourceGraphic_h +#define SourceGrahpic_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" + +#include "PlatformString.h" +#include "Filter.h" + +namespace WebCore { + + class SourceGraphic : public FilterEffect { + public: + static PassRefPtr<SourceGraphic> create(); + + static const AtomicString& effectName(); + + void apply(Filter*); + void dump(); + + private: + SourceGraphic() { } + }; +} //namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // SourceGraphic_h diff --git a/WebCore/platform/graphics/gtk/FontCacheGtk.cpp b/WebCore/platform/graphics/gtk/FontCacheGtk.cpp index d2b43cc..e0b88da 100644 --- a/WebCore/platform/graphics/gtk/FontCacheGtk.cpp +++ b/WebCore/platform/graphics/gtk/FontCacheGtk.cpp @@ -37,7 +37,7 @@ const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, cons { #if defined(USE_FREETYPE) FcResult fresult; - FontPlatformData* prim = const_cast<FontPlatformData*>(&font.primaryFont()->m_font); + FontPlatformData* prim = const_cast<FontPlatformData*>(&font.primaryFont()->platformData()); if (!prim->m_fallbacks) prim->m_fallbacks = FcFontSort(NULL, prim->m_pattern, FcTrue, NULL, &fresult); diff --git a/WebCore/platform/graphics/gtk/FontGtk.cpp b/WebCore/platform/graphics/gtk/FontGtk.cpp index 288ba91..6561f02 100644 --- a/WebCore/platform/graphics/gtk/FontGtk.cpp +++ b/WebCore/platform/graphics/gtk/FontGtk.cpp @@ -34,7 +34,6 @@ #include "Font.h" #include "GraphicsContext.h" -#include "NotImplemented.h" #include "SimpleFontData.h" #include <cairo.h> @@ -145,14 +144,14 @@ static gchar* convertUniCharToUTF8(const UChar* characters, gint length, int fro static void setPangoAttributes(const Font* font, const TextRun& run, PangoLayout* layout) { #if defined(USE_FREETYPE) - if (font->primaryFont()->m_font.m_pattern) { - PangoFontDescription* desc = pango_fc_font_description_from_pattern(font->primaryFont()->m_font.m_pattern, FALSE); + if (font->primaryFont()->platformData().m_pattern) { + PangoFontDescription* desc = pango_fc_font_description_from_pattern(font->primaryFont()->platformData().m_pattern, FALSE); pango_layout_set_font_description(layout, desc); pango_font_description_free(desc); } #elif defined(USE_PANGO) - if (font->primaryFont()->m_font.m_font) { - PangoFontDescription* desc = pango_font_describe(font->primaryFont()->m_font.m_font); + if (font->primaryFont()->platformData().m_font) { + PangoFontDescription* desc = pango_font_describe(font->primaryFont()->platformData().m_font); pango_layout_set_font_description(layout, desc); pango_font_description_free(desc); } @@ -183,6 +182,11 @@ static void setPangoAttributes(const Font* font, const TextRun& run, PangoLayout pango_attr_list_unref(list); } +bool Font::canReturnFallbackFontsForComplexText() +{ + return false; +} + void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const { cairo_t* cr = context->platformContext(); @@ -290,7 +294,7 @@ static PangoLayout* getDefaultPangoLayout(const TextRun& run) return layout; } -float Font::floatWidthForComplexText(const TextRun& run) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */) const { if (run.length() == 0) return 0.0f; diff --git a/WebCore/platform/graphics/gtk/FontPlatformData.h b/WebCore/platform/graphics/gtk/FontPlatformData.h index 20c52e5..ae1f134 100644 --- a/WebCore/platform/graphics/gtk/FontPlatformData.h +++ b/WebCore/platform/graphics/gtk/FontPlatformData.h @@ -82,6 +82,8 @@ public: bool isFixedPitch(); float size() const { return m_size; } + bool syntheticBold() const { return m_syntheticBold; } + bool syntheticOblique() const { return m_syntheticOblique; } void setFont(cairo_t*) const; diff --git a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp index 68685e9..f0f0dd5 100644 --- a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp +++ b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp @@ -109,10 +109,9 @@ FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const cairo_matrix_init_scale(&fontMatrix, fontDescription.computedPixelSize(), fontDescription.computedPixelSize()); cairo_matrix_init_identity(&ctm); -#if GTK_CHECK_VERSION(2,10,0) if (GdkScreen* screen = gdk_screen_get_default()) options = gdk_screen_get_font_options(screen); -#endif + // gdk_screen_get_font_options() returns NULL if no default options are // set, so we always have to check. if (!options) @@ -150,10 +149,9 @@ FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, int size, bool b static const cairo_font_options_t* defaultOptions = cairo_font_options_create(); const cairo_font_options_t* options = NULL; -#if GTK_CHECK_VERSION(2,10,0) if (GdkScreen* screen = gdk_screen_get_default()) options = gdk_screen_get_font_options(screen); -#endif + // gdk_screen_get_font_options() returns NULL if no default options are // set, so we always have to check. if (!options) diff --git a/WebCore/platform/graphics/gtk/GlyphPageTreeNodeGtk.cpp b/WebCore/platform/graphics/gtk/GlyphPageTreeNodeGtk.cpp index 24ad864..7c9ffe6 100644 --- a/WebCore/platform/graphics/gtk/GlyphPageTreeNodeGtk.cpp +++ b/WebCore/platform/graphics/gtk/GlyphPageTreeNodeGtk.cpp @@ -42,7 +42,7 @@ bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned b if (bufferLength > GlyphPage::size) return false; - FT_Face face = cairo_ft_scaled_font_lock_face(fontData->m_font.m_scaledFont); + FT_Face face = cairo_ft_scaled_font_lock_face(fontData->platformData().m_scaledFont); if (!face) return false; @@ -57,7 +57,7 @@ bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned b } } - cairo_ft_scaled_font_unlock_face(fontData->m_font.m_scaledFont); + cairo_ft_scaled_font_unlock_face(fontData->platformData().m_scaledFont); return haveGlyphs; } diff --git a/WebCore/platform/graphics/gtk/GlyphPageTreeNodePango.cpp b/WebCore/platform/graphics/gtk/GlyphPageTreeNodePango.cpp index 8fada5c..8d0baa6 100644 --- a/WebCore/platform/graphics/gtk/GlyphPageTreeNodePango.cpp +++ b/WebCore/platform/graphics/gtk/GlyphPageTreeNodePango.cpp @@ -78,12 +78,12 @@ bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned b if (bufferLength > GlyphPage::size) return false; - if (!fontData->m_font.m_font || fontData->m_font.m_font == reinterpret_cast<PangoFont*>(-1)) + if (!fontData->platformData().m_font || fontData->platformData().m_font == reinterpret_cast<PangoFont*>(-1)) return false; bool haveGlyphs = false; for (unsigned i = 0; i < length; i++) { - Glyph glyph = pango_font_get_glyph(fontData->m_font.m_font, fontData->m_font.m_context, buffer[i]); + Glyph glyph = pango_font_get_glyph(fontData->platformData().m_font, fontData->platformData().m_context, buffer[i]); if (!glyph) setGlyphDataForIndex(offset + i, 0, 0); else { diff --git a/WebCore/platform/graphics/gtk/IconGtk.cpp b/WebCore/platform/graphics/gtk/IconGtk.cpp index d8b38a0..e08c1ab 100644 --- a/WebCore/platform/graphics/gtk/IconGtk.cpp +++ b/WebCore/platform/graphics/gtk/IconGtk.cpp @@ -33,7 +33,6 @@ #include "CString.h" #include "GraphicsContext.h" #include "MIMETypeRegistry.h" -#include "NotImplemented.h" #include "PassRefPtr.h" #include <gtk/gtk.h> diff --git a/WebCore/platform/graphics/gtk/ImageGtk.cpp b/WebCore/platform/graphics/gtk/ImageGtk.cpp index b745209..0e92d6c 100644 --- a/WebCore/platform/graphics/gtk/ImageGtk.cpp +++ b/WebCore/platform/graphics/gtk/ImageGtk.cpp @@ -26,12 +26,52 @@ #include "config.h" #include "BitmapImage.h" +#include "CString.h" +#include "GOwnPtr.h" -// This function loads resources from WebKit -Vector<char> loadResourceIntoArray(const char*); +#include <cairo.h> +#include <gtk/gtk.h> + +namespace WTF { + +template <> void freeOwnedGPtr<GtkIconInfo>(GtkIconInfo* info) +{ + if (info) + gtk_icon_info_free(info); +} + +} namespace WebCore { +static CString getIconFileNameOrFallback(const char* name, const char* fallback) +{ + GOwnPtr<GtkIconInfo> info(gtk_icon_theme_lookup_icon(gtk_icon_theme_get_default(), + name, 16, GTK_ICON_LOOKUP_NO_SVG)); + if (!info) + return String::format("%s/webkit-1.0/images/%s.png", DATA_DIR, fallback).utf8(); + + return CString(gtk_icon_info_get_filename(info.get())); +} + +static PassRefPtr<SharedBuffer> loadResourceSharedBuffer(const char* name) +{ + CString fileName; + + // Find the path for the image + if (strcmp("missingImage", name) == 0) + fileName = getIconFileNameOrFallback(GTK_STOCK_MISSING_IMAGE, "missingImage"); + else + fileName = String::format("%s/webkit-1.0/images/%s.png", DATA_DIR, name).utf8(); + + GOwnPtr<gchar> content; + gsize length; + if (!g_file_get_contents(fileName.data(), &content.outPtr(), &length, 0)) + return SharedBuffer::create(); + + return SharedBuffer::create(content.get(), length); +} + void BitmapImage::initPlatformData() { } @@ -40,13 +80,34 @@ void BitmapImage::invalidatePlatformData() { } -PassRefPtr<Image> Image::loadPlatformResource(const char *name) +PassRefPtr<Image> Image::loadPlatformResource(const char* name) { - Vector<char> arr = loadResourceIntoArray(name); RefPtr<BitmapImage> img = BitmapImage::create(); - RefPtr<SharedBuffer> buffer = SharedBuffer::create(arr.data(), arr.size()); - img->setData(buffer, true); + RefPtr<SharedBuffer> buffer = loadResourceSharedBuffer(name); + img->setData(buffer.release(), true); return img.release(); } +GdkPixbuf* BitmapImage::getGdkPixbuf() +{ + int width = cairo_image_surface_get_width(frameAtIndex(currentFrame())); + int height = cairo_image_surface_get_height(frameAtIndex(currentFrame())); + + int bestDepth = gdk_visual_get_best_depth(); + GdkColormap* cmap = gdk_colormap_new(gdk_visual_get_best_with_depth(bestDepth), true); + + GdkPixmap* pixmap = gdk_pixmap_new(0, width, height, bestDepth); + gdk_drawable_set_colormap(GDK_DRAWABLE(pixmap), cmap); + cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(pixmap)); + cairo_set_source_surface(cr, frameAtIndex(currentFrame()), 0, 0); + cairo_paint(cr); + cairo_destroy(cr); + + GdkPixbuf* pixbuf = gdk_pixbuf_get_from_drawable(0, GDK_DRAWABLE(pixmap), 0, 0, 0, 0, 0, width, height); + g_object_unref(pixmap); + g_object_unref(cmap); + + return pixbuf; +} + } diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp index 4203a3c..6684108 100644 --- a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp +++ b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp @@ -49,7 +49,7 @@ void SimpleFontData::platformInit() { cairo_font_extents_t font_extents; cairo_text_extents_t text_extents; - cairo_scaled_font_extents(m_font.m_scaledFont, &font_extents); + cairo_scaled_font_extents(m_platformData.m_scaledFont, &font_extents); m_ascent = static_cast<int>(font_extents.ascent); m_descent = static_cast<int>(font_extents.descent); m_lineSpacing = static_cast<int>(font_extents.height); @@ -60,11 +60,19 @@ void SimpleFontData::platformInit() // while we figure out what's going on. if (m_lineSpacing < m_ascent + m_descent) m_lineSpacing = m_ascent + m_descent; - cairo_scaled_font_text_extents(m_font.m_scaledFont, "x", &text_extents); + cairo_scaled_font_text_extents(m_platformData.m_scaledFont, "x", &text_extents); m_xHeight = text_extents.height; - cairo_scaled_font_text_extents(m_font.m_scaledFont, " ", &text_extents); + cairo_scaled_font_text_extents(m_platformData.m_scaledFont, " ", &text_extents); m_spaceWidth = static_cast<int>(text_extents.x_advance); m_lineGap = m_lineSpacing - m_ascent - m_descent; + m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f; +} + +void SimpleFontData::platformCharWidthInit() +{ + m_avgCharWidth = 0.f; + m_maxCharWidth = 0.f; + initCharWidths(); } void SimpleFontData::platformDestroy() @@ -86,38 +94,38 @@ SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDes bool SimpleFontData::containsCharacters(const UChar* characters, int length) const { - FT_Face face = cairo_ft_scaled_font_lock_face(m_font.m_scaledFont); + FT_Face face = cairo_ft_scaled_font_lock_face(m_platformData.m_scaledFont); if (!face) return false; for (unsigned i = 0; i < length; i++) { if (FcFreeTypeCharIndex(face, characters[i]) == 0) { - cairo_ft_scaled_font_unlock_face(m_font.m_scaledFont); + cairo_ft_scaled_font_unlock_face(m_platformData.m_scaledFont); return false; } } - cairo_ft_scaled_font_unlock_face(m_font.m_scaledFont); + cairo_ft_scaled_font_unlock_face(m_platformData.m_scaledFont); return true; } void SimpleFontData::determinePitch() { - m_treatAsFixedPitch = m_font.isFixedPitch(); + m_treatAsFixedPitch = m_platformData.isFixedPitch(); } float SimpleFontData::platformWidthForGlyph(Glyph glyph) const { - ASSERT(m_font.m_scaledFont); + ASSERT(m_platformData.m_scaledFont); cairo_glyph_t cglyph = { glyph, 0, 0 }; cairo_text_extents_t extents; - cairo_scaled_font_glyph_extents(m_font.m_scaledFont, &cglyph, 1, &extents); + cairo_scaled_font_glyph_extents(m_platformData.m_scaledFont, &cglyph, 1, &extents); float w = (float)m_spaceWidth; - if (cairo_scaled_font_status(m_font.m_scaledFont) == CAIRO_STATUS_SUCCESS && extents.x_advance != 0) + if (cairo_scaled_font_status(m_platformData.m_scaledFont) == CAIRO_STATUS_SUCCESS && extents.x_advance != 0) w = (float)extents.x_advance; return w; } @@ -125,7 +133,7 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const void SimpleFontData::setFont(cairo_t* cr) const { ASSERT(cr); - m_font.setFont(cr); + m_platformData.setFont(cr); } } diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp index e345a8c..e57d9e6 100644 --- a/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp +++ b/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp @@ -48,7 +48,7 @@ void SimpleFontData::platformInit() { cairo_font_extents_t font_extents; cairo_text_extents_t text_extents; - cairo_scaled_font_extents(m_font.m_scaledFont, &font_extents); + cairo_scaled_font_extents(m_platformData.m_scaledFont, &font_extents); m_ascent = static_cast<int>(font_extents.ascent); m_descent = static_cast<int>(font_extents.descent); m_lineSpacing = static_cast<int>(font_extents.height); @@ -59,11 +59,19 @@ void SimpleFontData::platformInit() // while we figure out what's going on. if (m_lineSpacing < m_ascent + m_descent) m_lineSpacing = m_ascent + m_descent; - cairo_scaled_font_text_extents(m_font.m_scaledFont, "x", &text_extents); + cairo_scaled_font_text_extents(m_platformData.m_scaledFont, "x", &text_extents); m_xHeight = text_extents.height; - cairo_scaled_font_text_extents(m_font.m_scaledFont, " ", &text_extents); + cairo_scaled_font_text_extents(m_platformData.m_scaledFont, " ", &text_extents); m_spaceWidth = static_cast<int>(text_extents.x_advance); m_lineGap = m_lineSpacing - m_ascent - m_descent; + m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f; +} + +void SimpleFontData::platformCharWidthInit() +{ + m_avgCharWidth = 0.f; + m_maxCharWidth = 0.f; + initCharWidths(); } void SimpleFontData::platformDestroy() @@ -87,7 +95,7 @@ bool SimpleFontData::containsCharacters(const UChar* characters, int length) con { bool result = true; - PangoCoverage* coverage = pango_font_get_coverage(m_font.m_font, pango_language_get_default()); + PangoCoverage* coverage = pango_font_get_coverage(m_platformData.m_font, pango_language_get_default()); for (int i = 0; i < length; i++) { if (PANGO_COVERAGE_NONE == pango_coverage_get(coverage, characters[i])) { @@ -108,19 +116,19 @@ void SimpleFontData::determinePitch() return; } - m_treatAsFixedPitch = m_font.isFixedPitch(); + m_treatAsFixedPitch = m_platformData.isFixedPitch(); } float SimpleFontData::platformWidthForGlyph(Glyph glyph) const { - ASSERT(m_font.m_scaledFont); + ASSERT(m_platformData.m_scaledFont); cairo_glyph_t cglyph = { glyph, 0, 0 }; cairo_text_extents_t extents; - cairo_scaled_font_glyph_extents(m_font.m_scaledFont, &cglyph, 1, &extents); + cairo_scaled_font_glyph_extents(m_platformData.m_scaledFont, &cglyph, 1, &extents); float w = (float)m_spaceWidth; - if (cairo_scaled_font_status(m_font.m_scaledFont) == CAIRO_STATUS_SUCCESS && extents.x_advance != 0) + if (cairo_scaled_font_status(m_platformData.m_scaledFont) == CAIRO_STATUS_SUCCESS && extents.x_advance != 0) w = (float)extents.x_advance; return w; } @@ -128,7 +136,7 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const void SimpleFontData::setFont(cairo_t* cr) const { ASSERT(cr); - m_font.setFont(cr); + m_platformData.setFont(cr); } } diff --git a/WebCore/platform/graphics/mac/ColorMac.h b/WebCore/platform/graphics/mac/ColorMac.h index 830e9d9..8a5ce31 100644 --- a/WebCore/platform/graphics/mac/ColorMac.h +++ b/WebCore/platform/graphics/mac/ColorMac.h @@ -41,7 +41,7 @@ namespace WebCore { // These functions assume NSColors are in DeviceRGB colorspace Color colorFromNSColor(NSColor *); - NSColor* nsColor(const Color&); + NSColor *nsColor(const Color&); bool usesTestModeFocusRingColor(); void setUsesTestModeFocusRingColor(bool); diff --git a/WebCore/platform/graphics/mac/ColorMac.mm b/WebCore/platform/graphics/mac/ColorMac.mm index 1c4350c..05dd78d 100644 --- a/WebCore/platform/graphics/mac/ColorMac.mm +++ b/WebCore/platform/graphics/mac/ColorMac.mm @@ -24,13 +24,10 @@ */ #import "config.h" -#import "Color.h" #import "ColorMac.h" -#import <AppKit/AppKit.h> -#import <wtf/Assertions.h> -#import <wtf/StdLibExtras.h> #import <wtf/RetainPtr.h> +#import <wtf/StdLibExtras.h> @interface WebCoreControlTintObserver : NSObject + (void)controlTintDidChange; @@ -47,7 +44,13 @@ static bool useOldAquaFocusRingColor; static RGBA32 makeRGBAFromNSColor(NSColor *c) { - return makeRGBA((int)(255 * [c redComponent]), (int)(255 * [c greenComponent]), (int)(255 * [c blueComponent]), (int)(255 * [c alphaComponent])); + CGFloat redComponent; + CGFloat greenComponent; + CGFloat blueComponent; + CGFloat alpha; + [c getRed:&redComponent green:&greenComponent blue:&blueComponent alpha:&alpha]; + + return makeRGBA(255 * redComponent, 255 * greenComponent, 255 * blueComponent, 255 * alpha); } Color colorFromNSColor(NSColor *c) @@ -55,21 +58,21 @@ Color colorFromNSColor(NSColor *c) return Color(makeRGBAFromNSColor(c)); } -NSColor* nsColor(const Color& color) +NSColor *nsColor(const Color& color) { - unsigned c = color.rgb(); + RGBA32 c = color.rgb(); switch (c) { case 0: { // Need this to avoid returning nil because cachedRGBAValues will default to 0. - DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, clearColor, ([NSColor colorWithDeviceRed:0.0f green:0.0f blue:0.0f alpha:0.0f])); + DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, clearColor, ([NSColor colorWithDeviceRed:0 green:0 blue:0 alpha:0])); return clearColor.get(); } case Color::black: { - DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, blackColor, ([NSColor colorWithDeviceRed:0.0f green:0.0f blue:0.0f alpha:1.0f])); + DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, blackColor, ([NSColor colorWithDeviceRed:0 green:0 blue:0 alpha:1])); return blackColor.get(); } case Color::white: { - DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, whiteColor, ([NSColor colorWithDeviceRed:1.0f green:1.0f blue:1.0f alpha:1.0f])); + DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, whiteColor, ([NSColor colorWithDeviceRed:1 green:1 blue:1 alpha:1])); return whiteColor.get(); } default: { @@ -81,10 +84,10 @@ NSColor* nsColor(const Color& color) if (cachedRGBAValues[i] == c) return cachedColors[i].get(); - NSColor* result = [NSColor colorWithDeviceRed:color.red() / 255.0f - green:color.green() / 255.0f - blue:color.blue() / 255.0f - alpha:color.alpha() /255.0f]; + NSColor *result = [NSColor colorWithDeviceRed:static_cast<CGFloat>(color.red()) / 255 + green:static_cast<CGFloat>(color.green()) / 255 + blue:static_cast<CGFloat>(color.blue()) / 255 + alpha:static_cast<CGFloat>(color.alpha()) /255]; static int cursor; cachedRGBAValues[cursor] = c; @@ -96,16 +99,13 @@ NSColor* nsColor(const Color& color) } } -static CGColorRef CGColorFromNSColor(NSColor* color) +static CGColorRef CGColorFromNSColor(NSColor *color) { // This needs to always use device colorspace so it can de-calibrate the color for // CGColor to possibly recalibrate it. - NSColor* deviceColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace]; - CGFloat red = [deviceColor redComponent]; - CGFloat green = [deviceColor greenComponent]; - CGFloat blue = [deviceColor blueComponent]; - CGFloat alpha = [deviceColor alphaComponent]; - const CGFloat components[4] = { red, green, blue, alpha }; + CGFloat components[4]; + NSColor *deviceColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace]; + [deviceColor getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]]; static CGColorSpaceRef deviceRGBColorSpace = CGColorSpaceCreateDeviceRGB(); CGColorRef cgColor = CGColorCreate(deviceRGBColorSpace, components); return cgColor; @@ -130,10 +130,10 @@ Color focusRingColor() [WebCoreControlTintObserver controlTintDidChange]; tintIsKnown = true; } - + if (usesTestModeFocusRingColor()) return oldAquaFocusRingColor; - + return systemFocusRingColor; } @@ -153,7 +153,7 @@ void setUsesTestModeFocusRingColor(bool newValue) + (void)controlTintDidChange { - NSColor* color = [[NSColor keyboardFocusIndicatorColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; + NSColor *color = [[NSColor keyboardFocusIndicatorColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; WebCore::systemFocusRingColor = WebCore::makeRGBAFromNSColor(color); } diff --git a/WebCore/platform/graphics/mac/CoreTextController.cpp b/WebCore/platform/graphics/mac/CoreTextController.cpp index 49e83c4..05f29b5 100644 --- a/WebCore/platform/graphics/mac/CoreTextController.cpp +++ b/WebCore/platform/graphics/mac/CoreTextController.cpp @@ -100,7 +100,7 @@ CoreTextController::CoreTextRun::CoreTextRun(const SimpleFontData* fontData, con m_indices = reinterpret_cast<const CFIndex*>(CFDataGetBytePtr(m_indicesData.get())); } -CoreTextController::CoreTextController(const Font* font, const TextRun& run, bool mayUseNaturalWritingDirection) +CoreTextController::CoreTextController(const Font* font, const TextRun& run, bool mayUseNaturalWritingDirection, HashSet<const SimpleFontData*>* fallbackFonts) : m_font(*font) , m_run(run) , m_mayUseNaturalWritingDirection(mayUseNaturalWritingDirection) @@ -112,6 +112,7 @@ CoreTextController::CoreTextController(const Font* font, const TextRun& run, boo , m_currentRun(0) , m_glyphInCurrentRun(0) , m_finalRoundingWidth(0) + , m_fallbackFonts(fallbackFonts) , m_lastRoundingGlyph(0) { m_padding = m_run.padding(); @@ -156,12 +157,12 @@ int CoreTextController::offsetForPosition(int h, bool includePartialGlyphs) if (x <= adjustedAdvance) { CFIndex hitIndex = coreTextRun.indexAt(j); int stringLength = coreTextRun.stringLength(); - TextBreakIterator* characterIterator = characterBreakIterator(coreTextRun.characters(), stringLength); + TextBreakIterator* cursorPositionIterator = cursorMovementIterator(coreTextRun.characters(), stringLength); int clusterStart; - if (isTextBreak(characterIterator, hitIndex)) + if (isTextBreak(cursorPositionIterator, hitIndex)) clusterStart = hitIndex; else { - clusterStart = textBreakPreceding(characterIterator, hitIndex); + clusterStart = textBreakPreceding(cursorPositionIterator, hitIndex); if (clusterStart == TextBreakDone) clusterStart = 0; } @@ -169,7 +170,7 @@ int CoreTextController::offsetForPosition(int h, bool includePartialGlyphs) if (!includePartialGlyphs) return coreTextRun.stringLocation() + clusterStart; - int clusterEnd = textBreakFollowing(characterIterator, hitIndex); + int clusterEnd = textBreakFollowing(cursorPositionIterator, hitIndex); if (clusterEnd == TextBreakDone) clusterEnd = stringLength; @@ -179,7 +180,7 @@ int CoreTextController::offsetForPosition(int h, bool includePartialGlyphs) // reordering and on font fallback should occur within a CTLine. if (clusterEnd - clusterStart > 1) { int firstGlyphBeforeCluster = j - 1; - while (firstGlyphBeforeCluster && coreTextRun.indexAt(firstGlyphBeforeCluster) >= clusterStart && coreTextRun.indexAt(firstGlyphBeforeCluster) < clusterEnd) { + while (firstGlyphBeforeCluster >= 0 && coreTextRun.indexAt(firstGlyphBeforeCluster) >= clusterStart && coreTextRun.indexAt(firstGlyphBeforeCluster) < clusterEnd) { CGFloat width = m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphBeforeCluster].width; clusterWidth += width; x += width; @@ -359,6 +360,9 @@ void CoreTextController::collectCoreTextRunsForCharacters(const UChar* cp, unsig 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())); @@ -426,7 +430,7 @@ void CoreTextController::adjustGlyphsAndAdvances() bool lastRun = r + 1 == runCount; const UChar* cp = coreTextRun.characters(); - CGFloat roundedSpaceWidth = roundCGFloat(fontData->m_spaceWidth); + 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(); @@ -444,29 +448,29 @@ void CoreTextController::adjustGlyphsAndAdvances() nextCh = *(m_coreTextRuns[r + 1].characters() + m_coreTextRuns[r + 1].indexAt(0)); bool treatAsSpace = Font::treatAsSpace(ch); - CGGlyph glyph = treatAsSpace ? fontData->m_spaceGlyph : glyphs[i]; - CGSize advance = treatAsSpace ? CGSizeMake(fontData->m_spaceWidth, advances[i].height) : advances[i]; + CGGlyph glyph = treatAsSpace ? fontData->spaceGlyph() : glyphs[i]; + CGSize advance = treatAsSpace ? CGSizeMake(fontData->spaceWidth(), advances[i].height) : advances[i]; if (ch == '\t' && m_run.allowTabs()) { float tabWidth = m_font.tabWidth(); advance.width = tabWidth - fmodf(m_run.xPos() + m_totalWidth, tabWidth); } else if (ch == zeroWidthSpace || Font::treatAsZeroWidthSpace(ch) && !treatAsSpace) { advance.width = 0; - glyph = fontData->m_spaceGlyph; + glyph = fontData->spaceGlyph(); } float roundedAdvanceWidth = roundf(advance.width); if (roundsAdvances) advance.width = roundedAdvanceWidth; - advance.width += fontData->m_syntheticBoldOffset; + advance.width += fontData->syntheticBoldOffset(); // We special case spaces in two ways when applying word rounding. // First, we round spaces to an adjusted width in all fonts. // Second, in fixed-pitch fonts we ensure that all glyphs that // match the width of the space glyph have the same width as the space glyph. - if (roundedAdvanceWidth == roundedSpaceWidth && (fontData->m_treatAsFixedPitch || glyph == fontData->m_spaceGlyph) && m_run.applyWordRounding()) - advance.width = fontData->m_adjustedSpaceWidth; + if (roundedAdvanceWidth == roundedSpaceWidth && (fontData->pitch() == FixedPitch || glyph == fontData->spaceGlyph()) && m_run.applyWordRounding()) + advance.width = fontData->adjustedSpaceWidth(); if (hasExtraSpacing) { // If we're a glyph with an advance, go ahead and add in letter-spacing. @@ -475,7 +479,7 @@ void CoreTextController::adjustGlyphsAndAdvances() advance.width += m_font.letterSpacing(); // Handle justification and word-spacing. - if (glyph == fontData->m_spaceGlyph) { + if (glyph == fontData->spaceGlyph()) { // Account for padding. WebCore uses space padding to justify text. // We distribute the specified padding over the available spaces in the run. if (m_padding) { diff --git a/WebCore/platform/graphics/mac/CoreTextController.h b/WebCore/platform/graphics/mac/CoreTextController.h index 8dbb7fb..4dd6f93 100644 --- a/WebCore/platform/graphics/mac/CoreTextController.h +++ b/WebCore/platform/graphics/mac/CoreTextController.h @@ -37,7 +37,7 @@ namespace WebCore { class CoreTextController { public: - CoreTextController(const Font*, const TextRun&, bool mayUseNaturalWritingDirection = false); + 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); @@ -106,6 +106,8 @@ private: float m_padding; float m_padPerSpace; + HashSet<const SimpleFontData*>* m_fallbackFonts; + unsigned m_lastRoundingGlyph; }; diff --git a/WebCore/platform/graphics/mac/FontCacheMac.mm b/WebCore/platform/graphics/mac/FontCacheMac.mm index 2202459..2730d5a 100644 --- a/WebCore/platform/graphics/mac/FontCacheMac.mm +++ b/WebCore/platform/graphics/mac/FontCacheMac.mm @@ -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. * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com> * * Redistribution and use in source and binary forms, with or without @@ -44,16 +44,30 @@ typedef int NSInteger; namespace WebCore { +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +static void fontCacheRegisteredFontsChangedNotificationCallback(CFNotificationCenterRef, void* observer, CFStringRef name, const void *, CFDictionaryRef) +{ + ASSERT_UNUSED(observer, observer == fontCache()); + ASSERT_UNUSED(name, CFEqual(name, kCTFontManagerRegisteredFontsChangedNotification)); + fontCache()->invalidate(); +} +#else static void fontCacheATSNotificationCallback(ATSFontNotificationInfoRef, void*) { fontCache()->invalidate(); } +#endif void FontCache::platformInit() { wkSetUpFontCache(); +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), this, fontCacheRegisteredFontsChangedNotificationCallback, kCTFontManagerRegisteredFontsChangedNotification, 0, CFNotificationSuspensionBehaviorDeliverImmediately); +#else + // kCTFontManagerRegisteredFontsChangedNotification does not exist on Leopard and earlier. // FIXME: Passing kATSFontNotifyOptionReceiveWhileSuspended may be an overkill and does not seem to work anyway. ATSFontNotificationSubscribe(fontCacheATSNotificationCallback, kATSFontNotifyOptionReceiveWhileSuspended, 0, 0); +#endif } static int toAppKitFontWeight(FontWeight fontWeight) diff --git a/WebCore/platform/graphics/mac/FontMac.mm b/WebCore/platform/graphics/mac/FontMac.mm index dc86c4b..df9494a 100644 --- a/WebCore/platform/graphics/mac/FontMac.mm +++ b/WebCore/platform/graphics/mac/FontMac.mm @@ -28,7 +28,6 @@ #import "Logging.h" #import "SimpleFontData.h" #import "WebCoreSystemInterface.h" -#import "WebCoreTextRenderer.h" #import <AppKit/AppKit.h> #define SYNTHETIC_OBLIQUE_ANGLE 14 @@ -43,12 +42,17 @@ using namespace std; namespace WebCore { +bool Font::canReturnFallbackFontsForComplexText() +{ + return true; +} + void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { CGContextRef cgContext = context->platformContext(); bool originalShouldUseFontSmoothing = wkCGContextGetShouldSmoothFonts(cgContext); - bool newShouldUseFontSmoothing = WebCoreShouldUseFontSmoothing(); + bool newShouldUseFontSmoothing = shouldUseSmoothing(); if (originalShouldUseFontSmoothing != newShouldUseFontSmoothing) CGContextSetShouldSmoothFonts(cgContext, newShouldUseFontSmoothing); @@ -99,8 +103,8 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons context->setFillColor(shadowFillColor); CGContextSetTextPosition(cgContext, point.x() + shadowSize.width(), point.y() + shadowSize.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); - if (font->m_syntheticBoldOffset) { - CGContextSetTextPosition(cgContext, point.x() + shadowSize.width() + font->m_syntheticBoldOffset, point.y() + shadowSize.height()); + 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); @@ -108,8 +112,8 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons CGContextSetTextPosition(cgContext, point.x(), point.y()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); - if (font->m_syntheticBoldOffset) { - CGContextSetTextPosition(cgContext, point.x() + font->m_syntheticBoldOffset, point.y()); + if (font->syntheticBoldOffset()) { + CGContextSetTextPosition(cgContext, point.x() + font->syntheticBoldOffset(), point.y()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); } diff --git a/WebCore/platform/graphics/mac/FontMacATSUI.mm b/WebCore/platform/graphics/mac/FontMacATSUI.mm index 3794149..051abb7 100644 --- a/WebCore/platform/graphics/mac/FontMacATSUI.mm +++ b/WebCore/platform/graphics/mac/FontMacATSUI.mm @@ -47,13 +47,15 @@ namespace WebCore { struct ATSULayoutParameters : Noncopyable { - ATSULayoutParameters(const TextRun& run) + 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() { @@ -73,6 +75,7 @@ struct ATSULayoutParameters : Noncopyable bool m_hasSyntheticBold; bool m_syntheticBoldPass; float m_padPerSpace; + HashSet<const SimpleFontData*>* m_fallbackFonts; }; static TextRun copyRunForDirectionalOverrideIfNecessary(const TextRun& run, OwnArrayPtr<UChar>& charactersWithOverride) @@ -124,7 +127,7 @@ static void initializeATSUStyle(const SimpleFontData* fontData) ATSUFontID fontID = fontData->platformData().m_atsuFontID; if (!fontID) { - LOG_ERROR("unable to get ATSUFontID for %@", fontData->m_font.font()); + LOG_ERROR("unable to get ATSUFontID for %@", fontData->platformData().font()); return; } @@ -134,7 +137,7 @@ static void initializeATSUStyle(const SimpleFontData* fontData) LOG_ERROR("ATSUCreateStyle failed (%d)", status); CGAffineTransform transform = CGAffineTransformMakeScale(1, -1); - if (fontData->m_font.m_syntheticOblique) + 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) }; @@ -180,7 +183,6 @@ static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef bool shouldRound = false; bool syntheticBoldPass = params->m_syntheticBoldPass; Fixed syntheticBoldOffset = 0; - ATSGlyphRef spaceGlyph = 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. @@ -190,27 +192,28 @@ static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef for (i = 1; i < count; i++) { bool isLastChar = i == count - 1; renderer = renderers[offset / 2]; - if (renderer != lastRenderer) { - lastRenderer = renderer; - spaceGlyph = renderer->m_spaceGlyph; - // 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->m_syntheticBoldOffset); - } float width; if (nextCh == zeroWidthSpace || Font::treatAsZeroWidthSpace(nextCh) && !Font::treatAsSpace(nextCh)) { width = 0; - layoutRecords[i-1].glyphID = spaceGlyph; + 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->m_syntheticBoldOffset; - if (renderer->m_treatAsFixedPitch ? width == renderer->m_spaceWidth : (layoutRecords[i-1].flags & kATSGlyphInfoIsWhiteSpace)) - width = renderer->m_adjustedSpaceWidth; + width += renderer->syntheticBoldOffset(); + if (renderer->pitch() == FixedPitch ? width == renderer->spaceWidth() : (layoutRecords[i-1].flags & kATSGlyphInfoIsWhiteSpace)) + width = renderer->adjustedSpaceWidth(); } lastNativePos = layoutRecords[i].realPos; @@ -258,7 +261,7 @@ static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef if (syntheticBoldOffset) layoutRecords[i-1].realPos += syntheticBoldOffset; else - layoutRecords[i-1].glyphID = spaceGlyph; + layoutRecords[i-1].glyphID = renderer->spaceGlyph(); } layoutRecords[i].realPos = FloatToFixed(lastAdjustedPos); } @@ -460,7 +463,7 @@ void ATSULayoutParameters::initialize(const Font* font, const GraphicsContext* g } } else m_fonts[i] = r; - if (m_fonts[i]->m_syntheticBoldOffset) + if (m_fonts[i]->syntheticBoldOffset()) m_hasSyntheticBold = true; } substituteOffset += substituteLength; @@ -570,12 +573,12 @@ void Font::drawComplexText(GraphicsContext* graphicsContext, const TextRun& run, graphicsContext->setShadow(shadowSize, shadowBlur, shadowColor); } -float Font::floatWidthForComplexText(const TextRun& run) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const { if (run.length() == 0) return 0; - ATSULayoutParameters params(run); + ATSULayoutParameters params(run, fallbackFonts); params.initialize(this); OSStatus status; diff --git a/WebCore/platform/graphics/mac/FontMacCoreText.cpp b/WebCore/platform/graphics/mac/FontMacCoreText.cpp index 5fb9d5d..9dffc7a 100644 --- a/WebCore/platform/graphics/mac/FontMacCoreText.cpp +++ b/WebCore/platform/graphics/mac/FontMacCoreText.cpp @@ -86,9 +86,9 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F drawGlyphBuffer(context, glyphBuffer, run, startPoint); } -float Font::floatWidthForComplexText(const TextRun& run) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const { - CoreTextController controller(this, run, true); + CoreTextController controller(this, run, true, fallbackFonts); return controller.totalWidth(); } diff --git a/WebCore/platform/graphics/mac/FontPlatformData.h b/WebCore/platform/graphics/mac/FontPlatformData.h index e911867..1b7b884 100644 --- a/WebCore/platform/graphics/mac/FontPlatformData.h +++ b/WebCore/platform/graphics/mac/FontPlatformData.h @@ -82,6 +82,8 @@ struct FontPlatformData { bool isHashTableDeletedValue() const { return m_font == hashTableDeletedFontValue(); } float size() const { return m_size; } + bool syntheticBold() const { return m_syntheticBold; } + bool syntheticOblique() const { return m_syntheticOblique; } bool m_syntheticBold; bool m_syntheticOblique; diff --git a/WebCore/platform/graphics/mac/GraphicsContextMac.mm b/WebCore/platform/graphics/mac/GraphicsContextMac.mm index 4e11602..2404319 100644 --- a/WebCore/platform/graphics/mac/GraphicsContextMac.mm +++ b/WebCore/platform/graphics/mac/GraphicsContextMac.mm @@ -96,27 +96,28 @@ static NSColor* createPatternColor(NSString* name, NSColor* defaultColor, bool& color = defaultColor; return color; } - + +// WebKit on Mac is a standard platform component, so it must use the standard platform artwork for underline. void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& point, int width, bool grammar) { if (paintingDisabled()) return; - // These are the same for misspelling or bad grammar + // These are the same for misspelling or bad grammar. int patternHeight = cMisspellingLineThickness; int patternWidth = cMisspellingLinePatternWidth; bool usingDot; NSColor *patternColor; if (grammar) { - // Constants for grammar pattern color + // Constants for grammar pattern color. static bool usingDotForGrammar = false; DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, grammarPatternColor, (createPatternColor(@"GrammarDot", [NSColor greenColor], usingDotForGrammar))); usingDot = usingDotForGrammar; patternColor = grammarPatternColor.get(); } else { - // Constants for spelling pattern color + // Constants for spelling pattern color. static bool usingDotForSpelling = false; DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, spellingPatternColor, (createPatternColor(@"SpellingDot", [NSColor redColor], usingDotForSpelling))); @@ -141,7 +142,7 @@ void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& point, // FIXME: This code should not be using wkSetPatternPhaseInUserSpace, as this approach is wrong // for transforms. - // Draw underline + // Draw underline. NSGraphicsContext *currentContext = [NSGraphicsContext currentContext]; CGContextRef context = (CGContextRef)[currentContext graphicsPort]; CGContextSaveGState(context); diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.h b/WebCore/platform/graphics/mac/GraphicsLayerCA.h index 3a692d3..50138d5 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.h +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.h @@ -117,9 +117,8 @@ private: bool requiresTiledLayer(const FloatSize&) const; void swapFromOrToTiledLayer(bool useTiledLayer); - void setHasContentsLayer(bool); void setContentsLayer(WebLayer*); - void setContentsLayerFlipped(bool); + WebLayer* contentsLayer() const { return m_contentsLayer.get(); } RetainPtr<WebLayer> m_layer; RetainPtr<WebLayer> m_transformLayer; diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm index f3f2d7f..f361437 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm @@ -271,9 +271,9 @@ static bool forceSoftwareAnimation() return forceSoftwareAnimation; } -bool GraphicsLayer::graphicsContextsFlipped() +GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayer::compositingCoordinatesOrientation() { - return true; + return CompositingCoordinatesBottomUp; } #ifndef NDEBUG @@ -746,8 +746,10 @@ void GraphicsLayerCA::setDrawsContent(bool drawsContent) swapFromOrToTiledLayer(needTiledLayer); BEGIN_BLOCK_OBJC_EXCEPTIONS - // Clobber any existing content. If necessary, CA will create backing store on the next display. - [m_layer.get() setContents:nil]; + if (m_drawsContent) + [m_layer.get() setNeedsDisplay]; + else + [m_layer.get() setContents:nil]; #ifndef NDEBUG updateDebugIndicators(); @@ -761,7 +763,14 @@ void GraphicsLayerCA::setBackgroundColor(const Color& color, const Animation* tr GraphicsLayer::setBackgroundColor(color, transition, beginTime); BEGIN_BLOCK_OBJC_EXCEPTIONS - setHasContentsLayer(true); + + if (!m_contentsLayer.get()) { + WebLayer* colorLayer = [WebLayer layer]; +#ifndef NDEBUG + [colorLayer setName:@"Color Layer"]; +#endif + setContentsLayer(colorLayer); + } if (transition && !transition->isEmptyOrZeroDuration()) { CALayer* presLayer = [m_contentsLayer.get() presentationLayer]; @@ -777,7 +786,6 @@ void GraphicsLayerCA::setBackgroundColor(const Color& color, const Animation* tr CGColorRelease(bgColor); } else { removeAllAnimationsForProperty(AnimatedPropertyBackgroundColor); - setHasContentsLayer(true); setLayerBackgroundColor(m_contentsLayer.get(), m_backgroundColor); } @@ -787,7 +795,7 @@ void GraphicsLayerCA::setBackgroundColor(const Color& color, const Animation* tr void GraphicsLayerCA::clearBackgroundColor() { if (!m_contentLayerForImageOrVideo) - setHasContentsLayer(false); + setContentsLayer(0); else clearLayerBackgroundColor(m_contentsLayer.get()); } @@ -1082,35 +1090,27 @@ bool GraphicsLayerCA::animateFloat(AnimatedPropertyID property, const FloatValue void GraphicsLayerCA::setContentsToImage(Image* image) { if (image) { - setHasContentsLayer(true); - - // FIXME: is image flipping really a property of the graphics context? - bool needToFlip = GraphicsLayer::graphicsContextsFlipped(); - CGPoint anchorPoint = needToFlip ? CGPointMake(0.0f, 1.0f) : CGPointZero; - BEGIN_BLOCK_OBJC_EXCEPTIONS { - CGImageRef theImage = image->nativeImageForCurrentFrame(); + if (!m_contentsLayer.get()) { + WebLayer* imageLayer = [WebLayer layer]; +#ifndef NDEBUG + [imageLayer setName:@"Image Layer"]; +#endif + setContentsLayer(imageLayer); + } + // FIXME: maybe only do trilinear if the image is being scaled down, // but then what if the layer size changes? -#if HAVE_MODERN_QUARTZCORE +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) [m_contentsLayer.get() setMinificationFilter:kCAFilterTrilinear]; #endif - if (needToFlip) { - 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.get() setTransform:flipper]; - } - - [m_contentsLayer.get() setAnchorPoint:anchorPoint]; + CGImageRef theImage = image->nativeImageForCurrentFrame(); [m_contentsLayer.get() setContents:(id)theImage]; } END_BLOCK_OBJC_EXCEPTIONS } else - setHasContentsLayer(false); + setContentsLayer(0); m_contentLayerForImageOrVideo = (image != 0); } @@ -1124,7 +1124,7 @@ void GraphicsLayerCA::setContentsToVideo(PlatformLayer* videoLayer) void GraphicsLayerCA::clearContents() { if (m_contentLayerForImageOrVideo) { - setHasContentsLayer(false); + setContentsLayer(0); m_contentLayerForImageOrVideo = false; } } @@ -1431,7 +1431,7 @@ void GraphicsLayerCA::swapFromOrToTiledLayer(bool userTiledLayer) [tiledLayer setLevelsOfDetail:1]; [tiledLayer setLevelsOfDetailBias:0]; - if (GraphicsLayer::graphicsContextsFlipped()) + if (GraphicsLayer::compositingCoordinatesOrientation() == GraphicsLayer::CompositingCoordinatesBottomUp) [tiledLayer setContentsGravity:@"bottomLeft"]; else [tiledLayer setContentsGravity:@"topLeft"]; @@ -1476,24 +1476,6 @@ void GraphicsLayerCA::swapFromOrToTiledLayer(bool userTiledLayer) #endif } -void GraphicsLayerCA::setHasContentsLayer(bool hasLayer) -{ - BEGIN_BLOCK_OBJC_EXCEPTIONS - - if (hasLayer && !m_contentsLayer) { - // create the inner layer - WebLayer* contentsLayer = [WebLayer layer]; -#ifndef NDEBUG - [contentsLayer setName:@"Contents Layer"]; -#endif - setContentsLayer(contentsLayer); - - } else if (!hasLayer && m_contentsLayer) - setContentsLayer(0); - - END_BLOCK_OBJC_EXCEPTIONS -} - void GraphicsLayerCA::setContentsLayer(WebLayer* contentsLayer) { if (contentsLayer == m_contentsLayer) @@ -1511,14 +1493,26 @@ void GraphicsLayerCA::setContentsLayer(WebLayer* contentsLayer) [contentsLayer setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]]; m_contentsLayer.adoptNS([contentsLayer retain]); - [m_contentsLayer.get() setAnchorPoint:CGPointZero]; - [m_layer.get() addSublayer:m_contentsLayer.get()]; - updateContentsRect(); + bool needToFlip = GraphicsLayer::compositingCoordinatesOrientation() == GraphicsLayer::CompositingCoordinatesBottomUp; + CGPoint anchorPoint = needToFlip ? CGPointMake(0.0f, 1.0f) : CGPointZero; - // Set contents to nil if the layer does not draw its own content. - if (m_client && !drawsContent()) - [m_layer.get() setContents:nil]; + // If the layer world is flipped, we need to un-flip the contents layer + if (needToFlip) { + 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.get() setTransform:flipper]; + } + [m_contentsLayer.get() setAnchorPoint:anchorPoint]; + + // Insert the content layer first. Video elements require this, because they have + // shadow content that must display in front of the video. + [m_layer.get() insertSublayer:m_contentsLayer.get() atIndex:0]; + + updateContentsRect(); #ifndef NDEBUG if (showDebugBorders()) { diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h index 677c31a..f90f258 100644 --- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h +++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h @@ -30,6 +30,7 @@ #include "MediaPlayerPrivate.h" #include "Timer.h" +#include "FloatSize.h" #include <wtf/RetainPtr.h> #ifdef __OBJC__ @@ -127,6 +128,8 @@ private: float maxTimeLoaded() const; void disableUnsupportedTracks(); + void sawUnsupportedTracks(); + void cacheMovieScale(); bool metaDataAvailable() const { return m_qtMovie && m_readyState >= MediaPlayer::HaveMetadata; } MediaPlayer* m_player; @@ -142,7 +145,10 @@ private: bool m_isStreaming; bool m_visible; IntRect m_rect; + FloatSize m_scaleFactor; unsigned m_enabledTrackCount; + unsigned m_totalTrackCount; + bool m_hasUnsupportedTracks; float m_duration; #if DRAW_FRAME_RATE int m_frameCountWhilePlaying; diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm index 74a9ff9..dd41ed3 100644 --- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm +++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm @@ -37,6 +37,7 @@ #import "FrameView.h" #import "GraphicsContext.h" #import "KURL.h" +#import "MIMETypeRegistry.h" #import "SoftLinking.h" #import "WebCoreSystemInterface.h" #import <QTKit/QTKit.h> @@ -67,6 +68,7 @@ SOFT_LINK(QTKit, QTMakeTime, QTTime, (long long timeValue, long timeScale), (tim SOFT_LINK_CLASS(QTKit, QTMovie) SOFT_LINK_CLASS(QTKit, QTMovieView) +SOFT_LINK_POINTER(QTKit, QTTrackMediaTypeAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMediaTypeAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMediaTypeBase, NSString *) SOFT_LINK_POINTER(QTKit, QTMediaTypeMPEG, NSString *) @@ -81,6 +83,7 @@ SOFT_LINK_POINTER(QTKit, QTMovieIsActiveAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieLoadStateAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieLoadStateDidChangeNotification, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieNaturalSizeAttribute, NSString *) +SOFT_LINK_POINTER(QTKit, QTMovieCurrentSizeAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMoviePreventExternalURLLinksAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieRateDidChangeNotification, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieSizeDidChangeNotification, NSString *) @@ -90,10 +93,15 @@ SOFT_LINK_POINTER(QTKit, QTMovieURLAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieVolumeDidChangeNotification, NSString *) SOFT_LINK_POINTER(QTKit, QTSecurityPolicyNoCrossSiteAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTVideoRendererWebKitOnlyNewImageAvailableNotification, NSString *) +#ifndef BUILDING_ON_TIGER +SOFT_LINK_POINTER(QTKit, QTMovieApertureModeClean, NSString *) +SOFT_LINK_POINTER(QTKit, QTMovieApertureModeAttribute, NSString *) +#endif #define QTMovie getQTMovieClass() #define QTMovieView getQTMovieViewClass() +#define QTTrackMediaTypeAttribute getQTTrackMediaTypeAttribute() #define QTMediaTypeAttribute getQTMediaTypeAttribute() #define QTMediaTypeBase getQTMediaTypeBase() #define QTMediaTypeMPEG getQTMediaTypeMPEG() @@ -108,6 +116,7 @@ SOFT_LINK_POINTER(QTKit, QTVideoRendererWebKitOnlyNewImageAvailableNotification, #define QTMovieLoadStateAttribute getQTMovieLoadStateAttribute() #define QTMovieLoadStateDidChangeNotification getQTMovieLoadStateDidChangeNotification() #define QTMovieNaturalSizeAttribute getQTMovieNaturalSizeAttribute() +#define QTMovieCurrentSizeAttribute getQTMovieCurrentSizeAttribute() #define QTMoviePreventExternalURLLinksAttribute getQTMoviePreventExternalURLLinksAttribute() #define QTMovieRateDidChangeNotification getQTMovieRateDidChangeNotification() #define QTMovieSizeDidChangeNotification getQTMovieSizeDidChangeNotification() @@ -117,6 +126,10 @@ SOFT_LINK_POINTER(QTKit, QTVideoRendererWebKitOnlyNewImageAvailableNotification, #define QTMovieVolumeDidChangeNotification getQTMovieVolumeDidChangeNotification() #define QTSecurityPolicyNoCrossSiteAttribute getQTSecurityPolicyNoCrossSiteAttribute() #define QTVideoRendererWebKitOnlyNewImageAvailableNotification getQTVideoRendererWebKitOnlyNewImageAvailableNotification() +#ifndef BUILDING_ON_TIGER +#define QTMovieApertureModeClean getQTMovieApertureModeClean() +#define QTMovieApertureModeAttribute getQTMovieApertureModeAttribute() +#endif // Older versions of the QTKit header don't have these constants. #if !defined QTKIT_VERSION_MAX_ALLOWED || QTKIT_VERSION_MAX_ALLOWED <= QTKIT_VERSION_7_0 @@ -184,7 +197,10 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) , m_isStreaming(false) , m_visible(false) , m_rect() + , m_scaleFactor(1, 1) , m_enabledTrackCount(0) + , m_totalTrackCount(0) + , m_hasUnsupportedTracks(false) , m_duration(-1.0f) #if DRAW_FRAME_RATE , m_frameCountWhilePlaying(0) @@ -221,10 +237,15 @@ void MediaPlayerPrivate::createQTMovie(const String& url) [NSNumber numberWithBool:YES], QTMoviePreventExternalURLLinksAttribute, [NSNumber numberWithBool:YES], QTSecurityPolicyNoCrossSiteAttribute, [NSNumber numberWithBool:NO], QTMovieAskUnresolvedDataRefsAttribute, - [NSNumber numberWithBool:YES], @"QTMovieOpenForPlaybackAttribute", // FIXME: Use defined attribute when required version of QT supports this attribute +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + [NSNumber numberWithBool:YES], @"QTMovieOpenForPlaybackAttribute", +#endif +#ifndef BUILDING_ON_TIGER + QTMovieApertureModeClean, QTMovieApertureModeAttribute, +#endif nil]; - NSError* error = nil; + NSError *error = nil; m_qtMovie.adoptNS([[QTMovie alloc] initWithAttributes:movieAttributes error:&error]); // FIXME: Find a proper way to detect streaming content. @@ -239,6 +260,17 @@ void MediaPlayerPrivate::createQTMovie(const String& url) selector:@selector(loadStateChanged:) name:QTMovieLoadStateDidChangeNotification object:m_qtMovie.get()]; + + // In updateState(), we track when maxTimeLoaded() == duration(). + // In newer version of QuickTime, a notification is emitted when maxTimeLoaded changes. + // In older version of QuickTime, QTMovieLoadStateDidChangeNotification be fired. + if (NSString *maxTimeLoadedChangeNotification = wkQTMovieMaxTimeLoadedChangeNotification()) { + [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get() + selector:@selector(loadStateChanged:) + name:maxTimeLoadedChangeNotification + object:m_qtMovie.get()]; + } + [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get() selector:@selector(rateChanged:) name:QTMovieRateDidChangeNotification @@ -545,7 +577,16 @@ IntSize MediaPlayerPrivate::naturalSize() const { if (!metaDataAvailable()) return IntSize(); - return IntSize([[m_qtMovie.get() attributeForKey:QTMovieNaturalSizeAttribute] sizeValue]); + + // In spite of the name of this method, return QTMovieNaturalSizeAttribute transformed by the + // initial movie scale because the spec says intrinsic size is: + // + // ... the dimensions of the resource in CSS pixels after taking into account the resource's + // dimensions, aspect ratio, clean aperture, resolution, and so forth, as defined for the + // format used by the resource + + NSSize naturalSize = [[m_qtMovie.get() attributeForKey:QTMovieNaturalSizeAttribute] sizeValue]; + return IntSize(naturalSize.width * m_scaleFactor.width(), naturalSize.height * m_scaleFactor.height()); } bool MediaPlayerPrivate::hasVideo() const @@ -586,8 +627,14 @@ float MediaPlayerPrivate::maxTimeBuffered() const float MediaPlayerPrivate::maxTimeSeekable() const { + if (!metaDataAvailable()) + return 0; + // infinite duration means live stream - return isinf(duration()) ? 0 : maxTimeLoaded(); + if (isinf(duration())) + return 0; + + return wkQTMovieMaxTimeSeekable(m_qtMovie.get()); } float MediaPlayerPrivate::maxTimeLoaded() const @@ -629,6 +676,31 @@ void MediaPlayerPrivate::cancelLoad() updateStates(); } +void MediaPlayerPrivate::cacheMovieScale() +{ + NSSize initialSize = NSZeroSize; + NSSize naturalSize = [[m_qtMovie.get() attributeForKey:QTMovieNaturalSizeAttribute] sizeValue]; + +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + // QTMovieCurrentSizeAttribute is not allowed with instances of QTMovie that have been + // opened with QTMovieOpenForPlaybackAttribute, so ask for the display transform attribute instead. + NSAffineTransform *displayTransform = [m_qtMovie.get() attributeForKey:@"QTMoviePreferredTransformAttribute"]; + if (displayTransform) + initialSize = [displayTransform transformSize:naturalSize]; + else { + initialSize.width = naturalSize.width; + initialSize.height = naturalSize.height; + } +#else + initialSize = [[m_qtMovie.get() attributeForKey:QTMovieCurrentSizeAttribute] sizeValue]; +#endif + + if (naturalSize.width) + m_scaleFactor.setWidth(initialSize.width / naturalSize.width); + if (naturalSize.height) + m_scaleFactor.setHeight(initialSize.height / naturalSize.height); +} + void MediaPlayerPrivate::updateStates() { MediaPlayer::NetworkState oldNetworkState = m_networkState; @@ -636,18 +708,37 @@ void MediaPlayerPrivate::updateStates() long loadState = m_qtMovie ? [[m_qtMovie.get() attributeForKey:QTMovieLoadStateAttribute] longValue] : static_cast<long>(QTMovieLoadStateError); - if (loadState >= QTMovieLoadStateLoaded && m_readyState < MediaPlayer::HaveMetadata && !m_player->inMediaDocument()) { + if (loadState >= QTMovieLoadStateLoaded && m_readyState < MediaPlayer::HaveMetadata) { disableUnsupportedTracks(); - if (!m_enabledTrackCount) + if (m_player->inMediaDocument()) { + if (!m_enabledTrackCount || m_enabledTrackCount != m_totalTrackCount) { + // This is a type of media that we do not handle directly with a <video> + // element, likely streamed media or QuickTime VR. Tell the MediaPlayerClient + // that we noticed. + sawUnsupportedTracks(); + return; + } + } else if (!m_enabledTrackCount) { loadState = QTMovieLoadStateError; + } + + if (loadState != QTMovieLoadStateError) + cacheMovieScale(); } - if (loadState >= QTMovieLoadStateComplete && !m_isStreaming) { + BOOL completelyLoaded = !m_isStreaming && (loadState >= QTMovieLoadStateComplete); + + // Note: QT indicates that we are fully loaded with QTMovieLoadStateComplete. + // However newer versions of QT do not, so we check maxTimeLoaded against duration. + if (!completelyLoaded && !m_isStreaming && metaDataAvailable()) + completelyLoaded = maxTimeLoaded() == duration(); + + if (completelyLoaded) { // "Loaded" is reserved for fully buffered movies, never the case when streaming m_networkState = MediaPlayer::Loaded; m_readyState = MediaPlayer::HaveEnoughData; } else if (loadState >= QTMovieLoadStatePlaythroughOK) { - m_readyState = MediaPlayer::HaveFutureData; + m_readyState = MediaPlayer::HaveEnoughData; m_networkState = MediaPlayer::Loading; } else if (loadState >= QTMovieLoadStatePlayable) { // FIXME: This might not work correctly in streaming case, <rdar://problem/5693967> @@ -657,11 +748,17 @@ void MediaPlayerPrivate::updateStates() m_readyState = MediaPlayer::HaveMetadata; m_networkState = MediaPlayer::Loading; } else if (loadState > QTMovieLoadStateError) { - m_readyState = MediaPlayer::HaveNothing; + m_readyState = MediaPlayer::HaveNothing; m_networkState = MediaPlayer::Loading; } else { - float loaded = maxTimeLoaded(); + if (m_player->inMediaDocument()) { + // Something went wrong in the loading of media within a standalone file. + // This can occur with chained refmovies pointing to streamed media. + sawUnsupportedTracks(); + return; + } + float loaded = maxTimeLoaded(); if (!loaded) m_readyState = MediaPlayer::HaveNothing; @@ -684,7 +781,7 @@ void MediaPlayerPrivate::updateStates() if (m_readyState != oldReadyState) m_player->readyStateChanged(); - if (loadState >= QTMovieLoadStateLoaded && oldReadyState < MediaPlayer::HaveMetadata && m_player->visible()) + if (loadState >= QTMovieLoadStateLoaded && (!m_qtMovieView && !m_qtVideoRenderer) && m_player->visible()) setUpVideoRendering(); if (loadState >= QTMovieLoadStateLoaded) { @@ -699,28 +796,39 @@ void MediaPlayerPrivate::updateStates() void MediaPlayerPrivate::loadStateChanged() { - updateStates(); + if (!m_hasUnsupportedTracks) + updateStates(); } void MediaPlayerPrivate::rateChanged() { + if (m_hasUnsupportedTracks) + return; + updateStates(); m_player->rateChanged(); } void MediaPlayerPrivate::sizeChanged() { - m_player->sizeChanged(); + if (!m_hasUnsupportedTracks) + m_player->sizeChanged(); } void MediaPlayerPrivate::timeChanged() { + if (m_hasUnsupportedTracks) + return; + updateStates(); m_player->timeChanged(); } void MediaPlayerPrivate::didEnd() { + if (m_hasUnsupportedTracks) + return; + m_startedPlaying = false; #if DRAW_FRAME_RATE m_timeStoppedPlaying = [NSDate timeIntervalSinceReferenceDate]; @@ -729,22 +837,15 @@ void MediaPlayerPrivate::didEnd() m_player->timeChanged(); } -void MediaPlayerPrivate::setSize(const IntSize& size) +void MediaPlayerPrivate::setSize(const IntSize&) { - if (!m_qtMovieView) - return; - - m_rect.setSize(size); - if (m_player->inMediaDocument()) - // We need the QTMovieView to be placed in the proper location for document mode. - [m_qtMovieView.get() setFrame:m_rect]; - else { - // We don't really need the QTMovieView in any specific location so let's just get it out of the way - // where it won't intercept events or try to bring up the context menu. - IntRect farAwayButCorrectSize(m_rect); - farAwayButCorrectSize.move(-1000000, -1000000); - [m_qtMovieView.get() setFrame:farAwayButCorrectSize]; - } + // Don't resize the view now because [view setFrame] also resizes the movie itself, and because + // the renderer calls this function immediately when we report a size change (QTMovieSizeDidChangeNotification) + // we can get into a feedback loop observing the size change and resetting the size, and this can cause + // QuickTime to miss resetting a movie's size when the media size changes (as happens with an rtsp movie + // once the rtsp server sends the track sizes). Instead we remember the size passed to paint() and resize + // the view when it changes. + // <rdar://problem/6336092> REGRESSION: rtsp movie does not resize correctly } void MediaPlayerPrivate::setVisible(bool b) @@ -761,6 +862,9 @@ void MediaPlayerPrivate::setVisible(bool b) void MediaPlayerPrivate::repaint() { + if (m_hasUnsupportedTracks) + return; + #if DRAW_FRAME_RATE if (m_startedPlaying) { m_frameCountWhilePlaying++; @@ -775,7 +879,7 @@ void MediaPlayerPrivate::repaint() void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r) { - if (context->paintingDisabled()) + if (context->paintingDisabled() || m_hasUnsupportedTracks) return; NSView *view = m_qtMovieView.get(); id qtVideoRenderer = m_qtVideoRenderer.get(); @@ -802,12 +906,28 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r) [(id<WebKitVideoRenderingDetails>)qtVideoRenderer drawInRect:paintRect]; [NSGraphicsContext restoreGraphicsState]; } else { - if (m_player->inMediaDocument() && r != m_rect) { - // the QTMovieView needs to be placed in the proper location for document mode - m_rect = r; - [view setFrame:m_rect]; + if (m_rect != r) { + m_rect = r; + if (m_player->inMediaDocument()) { + // the QTMovieView needs to be placed in the proper location for document mode + [view setFrame:m_rect]; + } + else { + // We don't really need the QTMovieView in any specific location so let's just get it out of the way + // where it won't intercept events or try to bring up the context menu. + IntRect farAwayButCorrectSize(m_rect); + farAwayButCorrectSize.move(-1000000, -1000000); + [view setFrame:farAwayButCorrectSize]; + } } - [view displayRectIgnoringOpacity:paintRect inContext:newContext]; + + if (m_player->inMediaDocument()) { + // If we're using a QTMovieView in a media document, the view may get layer-backed. AppKit won't update + // the layer hosting correctly if we call displayRectIgnoringOpacity:inContext:, so use displayRectIgnoringOpacity: + // in this case. See <rdar://problem/6702882>. + [view displayRectIgnoringOpacity:paintRect]; + } else + [view displayRectIgnoringOpacity:paintRect inContext:newContext]; } #if DRAW_FRAME_RATE @@ -839,25 +959,57 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r) [m_objcObserver.get() setDelayCallbacks:NO]; } -static HashSet<String> mimeTypeCache() +static void addFileTypesToCache(NSArray * fileTypes, HashSet<String> &cache) +{ + int count = [fileTypes count]; + for (int n = 0; n < count; n++) { + CFStringRef ext = reinterpret_cast<CFStringRef>([fileTypes objectAtIndex:n]); + RetainPtr<CFStringRef> uti(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, ext, NULL)); + if (!uti) + continue; + RetainPtr<CFStringRef> mime(AdoptCF, UTTypeCopyPreferredTagWithClass(uti.get(), kUTTagClassMIMEType)); + + // UTI types are missing many media related MIME types supported by QTKit, see rdar://6434168, + // and not all third party movie importers register their types, so if we didn't find a type for + // this extension look it up in the hard coded table in the MIME type regsitry. + if (!mime) { + // -movieFileTypes: returns both file extensions and OSTypes. The later are surrounded by single + // quotes, eg. 'MooV', so don't bother looking at those. + if (CFStringGetCharacterAtIndex(ext, 0) != '\'') { + String mediaType = MIMETypeRegistry::getMediaMIMETypeForExtension(String(ext)); + if (!mediaType.isEmpty()) + mime.adoptCF(mediaType.createCFString()); + } + } + if (!mime) + continue; + cache.add(mime.get()); + } +} + +static HashSet<String> mimeCommonTypesCache() { DEFINE_STATIC_LOCAL(HashSet<String>, cache, ()); static bool typeListInitialized = false; if (!typeListInitialized) { + typeListInitialized = true; NSArray* fileTypes = [QTMovie movieFileTypes:QTIncludeCommonTypes]; - int count = [fileTypes count]; - for (int n = 0; n < count; n++) { - CFStringRef ext = reinterpret_cast<CFStringRef>([fileTypes objectAtIndex:n]); - RetainPtr<CFStringRef> uti(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, ext, NULL)); - if (!uti) - continue; - RetainPtr<CFStringRef> mime(AdoptCF, UTTypeCopyPreferredTagWithClass(uti.get(), kUTTagClassMIMEType)); - if (!mime) - continue; - cache.add(mime.get()); - } + addFileTypesToCache(fileTypes, cache); + } + + return cache; +} + +static HashSet<String> mimeModernTypesCache() +{ + DEFINE_STATIC_LOCAL(HashSet<String>, cache, ()); + static bool typeListInitialized = false; + + if (!typeListInitialized) { typeListInitialized = true; + NSArray* fileTypes = [QTMovie movieFileTypes:(QTMovieFileTypeOptions)wkQTIncludeOnlyModernMediaFileTypes()]; + addFileTypesToCache(fileTypes, cache); } return cache; @@ -865,14 +1017,21 @@ static HashSet<String> mimeTypeCache() void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types) { - types = mimeTypeCache(); + // Note: this method starts QTKitServer if it isn't already running when in 64-bit because it has to return the list + // of every MIME type supported by QTKit. + types = mimeCommonTypesCache(); } MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs) { - // only return "IsSupported" if there is no codecs parameter for now as there is no way to ask QT if it supports an - // extended MIME type yet - return mimeTypeCache().contains(type) ? (codecs && !codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported) : MediaPlayer::IsNotSupported; + // Only return "IsSupported" if there is no codecs parameter for now as there is no way to ask QT if it supports an + // extended MIME type yet. + + // We check the "modern" type cache first, as it doesn't require QTKitServer to start. + if (mimeModernTypesCache().contains(type) || mimeCommonTypesCache().contains(type)) + return (codecs && !codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported); + + return MediaPlayer::IsNotSupported; } bool MediaPlayerPrivate::isAvailable() @@ -900,6 +1059,7 @@ void MediaPlayerPrivate::disableUnsupportedTracks() { if (!m_qtMovie) { m_enabledTrackCount = 0; + m_totalTrackCount = 0; return; } @@ -911,15 +1071,19 @@ void MediaPlayerPrivate::disableUnsupportedTracks() allowedTrackTypes->add(QTMediaTypeText); allowedTrackTypes->add(QTMediaTypeBase); allowedTrackTypes->add(QTMediaTypeMPEG); - allowedTrackTypes->add("clcp"); - allowedTrackTypes->add("sbtl"); + 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("tmcd"); // timecode + allowedTrackTypes->add("tc64"); // timcode-64 } NSArray *tracks = [m_qtMovie.get() tracks]; - unsigned trackCount = [tracks count]; - m_enabledTrackCount = trackCount; - for (unsigned trackIndex = 0; trackIndex < trackCount; trackIndex++) { + m_totalTrackCount = [tracks count]; + m_enabledTrackCount = m_totalTrackCount; + for (unsigned trackIndex = 0; trackIndex < m_totalTrackCount; trackIndex++) { // Grab the track at the current index. If there isn't one there, then // we can move onto the next one. QTTrack *track = [tracks objectAtIndex:trackIndex]; @@ -931,24 +1095,18 @@ void MediaPlayerPrivate::disableUnsupportedTracks() if (![track isEnabled]) continue; - // Grab the track's media. We're going to check to see if we need to - // disable the tracks. They could be unsupported. - QTMedia *trackMedia = [track media]; - if (!trackMedia) - continue; - - // Grab the media type for this track. - NSString *mediaType = [trackMedia attributeForKey:QTMediaTypeAttribute]; + // Get the track's media type. + NSString *mediaType = [track attributeForKey:QTTrackMediaTypeAttribute]; if (!mediaType) continue; - + // Test whether the media type is in our white list. if (!allowedTrackTypes->contains(mediaType)) { // If this track type is not allowed, then we need to disable it. [track setEnabled:NO]; --m_enabledTrackCount; } - + // Disable chapter tracks. These are most likely to lead to trouble, as // they will be composited under the video tracks, forcing QT to do extra // work. @@ -982,6 +1140,12 @@ void MediaPlayerPrivate::disableUnsupportedTracks() } } +void MediaPlayerPrivate::sawUnsupportedTracks() +{ + m_hasUnsupportedTracks = true; + m_player->mediaPlayerClient()->mediaPlayerSawUnsupportedTracks(m_player); +} + } @implementation WebCoreMovieObserver diff --git a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm index a3c10fa..cdde7cf 100644 --- a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm +++ b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm @@ -58,7 +58,7 @@ static inline float scaleEmToUnits(float x, unsigned unitsPerEm) { return x * (c static bool initFontData(SimpleFontData* fontData) { - if (!fontData->m_font.cgFont()) + if (!fontData->platformData().cgFont()) return false; #ifdef BUILDING_ON_TIGER @@ -66,7 +66,7 @@ static bool initFontData(SimpleFontData* fontData) if (ATSUCreateStyle(&fontStyle) != noErr) return false; - ATSUFontID fontId = fontData->m_font.m_atsuFontID; + ATSUFontID fontId = fontData->platformData().m_atsuFontID; if (!fontId) { ATSUDisposeStyle(fontStyle); return false; @@ -153,7 +153,7 @@ void SimpleFontData::platformInit() m_shapesArabic = false; #endif - m_syntheticBoldOffset = m_font.m_syntheticBold ? 1.0f : 0.f; + m_syntheticBoldOffset = m_platformData.m_syntheticBold ? 1.0f : 0.f; bool failedSetup = false; if (!initFontData(this)) { @@ -165,7 +165,7 @@ void SimpleFontData::platformInit() // It overrides the normal "Times" family font. // It also appears to have a corrupt regular variant. NSString *fallbackFontFamily; - if ([[m_font.font() familyName] isEqual:@"Times"]) + if ([[m_platformData.font() familyName] isEqual:@"Times"]) fallbackFontFamily = @"Times New Roman"; else fallbackFontFamily = webFallbackFontFamily(); @@ -173,12 +173,12 @@ void SimpleFontData::platformInit() // Try setting up the alternate font. // This is a last ditch effort to use a substitute font when something has gone wrong. #if !ERROR_DISABLED - RetainPtr<NSFont> initialFont = m_font.font(); + RetainPtr<NSFont> initialFont = m_platformData.font(); #endif - if (m_font.font()) - m_font.setFont([[NSFontManager sharedFontManager] convertFont:m_font.font() toFamily:fallbackFontFamily]); + if (m_platformData.font()) + m_platformData.setFont([[NSFontManager sharedFontManager] convertFont:m_platformData.font() toFamily:fallbackFontFamily]); else - m_font.setFont([NSFont fontWithName:fallbackFontFamily size:m_font.size()]); + m_platformData.setFont([NSFont fontWithName:fallbackFontFamily size:m_platformData.size()]); #if !ERROR_DISABLED NSString *filePath = pathFromFont(initialFont.get()); if (!filePath) @@ -188,7 +188,7 @@ void SimpleFontData::platformInit() if ([fallbackFontFamily isEqual:@"Times New Roman"]) { // OK, couldn't setup Times New Roman as an alternate to Times, fallback // on the system font. If this fails we have no alternative left. - m_font.setFont([[NSFontManager sharedFontManager] convertFont:m_font.font() toFamily:webFallbackFontFamily()]); + m_platformData.setFont([[NSFontManager sharedFontManager] convertFont:m_platformData.font() toFamily:webFallbackFontFamily()]); if (!initFontData(this)) { // We tried, Times, Times New Roman, and the system font. No joy. We have to give up. LOG_ERROR("unable to initialize with font %@ at %@", initialFont.get(), filePath); @@ -203,14 +203,14 @@ void SimpleFontData::platformInit() // Report the problem. LOG_ERROR("Corrupt font detected, using %@ in place of %@ located at \"%@\".", - [m_font.font() familyName], [initialFont.get() familyName], filePath); + [m_platformData.font() familyName], [initialFont.get() familyName], filePath); } // If all else fails, try to set up using the system font. // This is probably because Times and Times New Roman are both unavailable. if (failedSetup) { - m_font.setFont([NSFont systemFontOfSize:[m_font.font() pointSize]]); - LOG_ERROR("failed to set up font, using system font %s", m_font.font()); + m_platformData.setFont([NSFont systemFontOfSize:[m_platformData.font() pointSize]]); + LOG_ERROR("failed to set up font, using system font %s", m_platformData.font()); initFontData(this); } @@ -218,15 +218,15 @@ void SimpleFontData::platformInit() int iDescent; int iLineGap; #ifdef BUILDING_ON_TIGER - wkGetFontMetrics(m_font.cgFont(), &iAscent, &iDescent, &iLineGap, &m_unitsPerEm); + wkGetFontMetrics(m_platformData.cgFont(), &iAscent, &iDescent, &iLineGap, &m_unitsPerEm); #else - iAscent = CGFontGetAscent(m_font.cgFont()); - iDescent = CGFontGetDescent(m_font.cgFont()); - iLineGap = CGFontGetLeading(m_font.cgFont()); - m_unitsPerEm = CGFontGetUnitsPerEm(m_font.cgFont()); + iAscent = CGFontGetAscent(m_platformData.cgFont()); + iDescent = CGFontGetDescent(m_platformData.cgFont()); + iLineGap = CGFontGetLeading(m_platformData.cgFont()); + m_unitsPerEm = CGFontGetUnitsPerEm(m_platformData.cgFont()); #endif - float pointSize = m_font.m_size; + float pointSize = m_platformData.m_size; float fAscent = scaleEmToUnits(iAscent, m_unitsPerEm) * pointSize; float fDescent = -scaleEmToUnits(iDescent, m_unitsPerEm) * pointSize; float fLineGap = scaleEmToUnits(iLineGap, m_unitsPerEm) * pointSize; @@ -236,7 +236,7 @@ void SimpleFontData::platformInit() // web standard. The AppKit adjustment of 20% is too big and is // incorrectly added to line spacing, so we use a 15% adjustment instead // and add it to the ascent. - NSString *familyName = [m_font.font() familyName]; + NSString *familyName = [m_platformData.font() familyName]; if ([familyName isEqualToString:@"Times"] || [familyName isEqualToString:@"Helvetica"] || [familyName isEqualToString:@"Courier"]) fAscent += floorf(((fAscent + fDescent) * 0.15f) + 0.5f); else if ([familyName isEqualToString:@"Geeza Pro"]) { @@ -264,14 +264,49 @@ void SimpleFontData::platformInit() GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); NSGlyph xGlyph = glyphPageZero ? glyphPageZero->glyphDataForCharacter('x').glyph : 0; if (xGlyph) { - NSRect xBox = [m_font.font() boundingRectForGlyph:xGlyph]; + NSRect xBox = [m_platformData.font() boundingRectForGlyph:xGlyph]; // Use the maximum of either width or height because "x" is nearly square // and web pages that foolishly use this metric for width will be laid out // poorly if we return an accurate height. Classic case is Times 13 point, // which has an "x" that is 7x6 pixels. m_xHeight = MAX(NSMaxX(xBox), NSMaxY(xBox)); } else - m_xHeight = [m_font.font() xHeight]; + m_xHeight = [m_platformData.font() xHeight]; +} + +void SimpleFontData::platformCharWidthInit() +{ + m_avgCharWidth = 0.f; + + // Calculate avgCharWidth according to http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6OS2.html + // We can try grabbing it out of the OS/2 table or via ATSFontGetHorizontalMetrics, but + // ATSFontGetHorizontalMetrics never seems to return a non-zero value and the OS/2 table + // contains zero for a large number of fonts. + GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); + if (glyphPageZero) { + static int weights[] = { 64, 14, 27, 35, 100, 20, 14, 42, 63, 3, 6, 35, 20, 56, 56, 17, 4, 49, 56, 71, 31, 10, 18, 3, 18, 2, 166 }; + int numGlyphs = 27; + ASSERT(numGlyphs == sizeof(weights) / sizeof(int)); + // Compute the weighted sum of the space character and the lowercase letters in the Latin alphabet. + float sum = 0.f; + int totalWeight = 0; + for (int i = 0; i < numGlyphs; i++) { + Glyph glyph = glyphPageZero->glyphDataForCharacter((i < 26 ? i + 'a' : ' ')).glyph; + if (glyph) { + totalWeight += weights[i]; + sum += widthForGlyph(glyph) * weights[i]; + } + } + if (sum > 0.f && totalWeight > 0) + m_avgCharWidth = sum / totalWeight; + } + + m_maxCharWidth = 0.f; + if (m_platformData.font()) + m_maxCharWidth = [m_platformData.font() maximumAdvancement].width; + + // Fallback to a cross-platform estimate, which will populate these values if they are non-positive. + initCharWidths(); } void SimpleFontData::platformDestroy() @@ -290,13 +325,13 @@ SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDes { if (!m_smallCapsFontData) { if (isCustomFont()) { - FontPlatformData smallCapsFontData(m_font); + FontPlatformData smallCapsFontData(m_platformData); smallCapsFontData.m_size = smallCapsFontData.m_size * smallCapsFontSizeMultiplier; m_smallCapsFontData = new SimpleFontData(smallCapsFontData, true, false); } else { BEGIN_BLOCK_OBJC_EXCEPTIONS; - float size = [m_font.font() pointSize] * smallCapsFontSizeMultiplier; - FontPlatformData smallCapsFont([[NSFontManager sharedFontManager] convertFont:m_font.font() toSize:size]); + float size = [m_platformData.font() pointSize] * smallCapsFontSizeMultiplier; + FontPlatformData smallCapsFont([[NSFontManager sharedFontManager] convertFont:m_platformData.font() toSize:size]); // AppKit resets the type information (screen/printer) when you convert a font to a different size. // We have to fix up the font that we're handed back. @@ -304,11 +339,11 @@ SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDes if (smallCapsFont.font()) { NSFontManager *fontManager = [NSFontManager sharedFontManager]; - NSFontTraitMask fontTraits = [fontManager traitsOfFont:m_font.font()]; + NSFontTraitMask fontTraits = [fontManager traitsOfFont:m_platformData.font()]; - if (m_font.m_syntheticBold) + if (m_platformData.m_syntheticBold) fontTraits |= NSBoldFontMask; - if (m_font.m_syntheticOblique) + if (m_platformData.m_syntheticOblique) fontTraits |= NSItalicFontMask; NSFontTraitMask smallCapsFontTraits = [fontManager traitsOfFont:smallCapsFont.font()]; @@ -326,7 +361,7 @@ SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDes bool SimpleFontData::containsCharacters(const UChar* characters, int length) const { NSString *string = [[NSString alloc] initWithCharactersNoCopy:const_cast<unichar*>(characters) length:length freeWhenDone:NO]; - NSCharacterSet *set = [[m_font.font() coveredCharacterSet] invertedSet]; + NSCharacterSet *set = [[m_platformData.font() coveredCharacterSet] invertedSet]; bool result = set && [string rangeOfCharacterFromSet:set].location == NSNotFound; [string release]; return result; @@ -334,7 +369,7 @@ bool SimpleFontData::containsCharacters(const UChar* characters, int length) con void SimpleFontData::determinePitch() { - NSFont* f = m_font.font(); + NSFont* f = m_platformData.font(); // Special case Osaka-Mono. // According to <rdar://problem/3999467>, we should treat Osaka-Mono as fixed pitch. // Note that the AppKit does not report Osaka-Mono as fixed pitch. @@ -356,11 +391,11 @@ void SimpleFontData::determinePitch() float SimpleFontData::platformWidthForGlyph(Glyph glyph) const { - NSFont* font = m_font.font(); - float pointSize = m_font.m_size; + NSFont* font = m_platformData.font(); + float pointSize = m_platformData.m_size; CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSize); CGSize advance; - if (!wkGetGlyphTransformedAdvances(m_font.cgFont(), font, &m, &glyph, &advance)) { + if (!wkGetGlyphTransformedAdvances(m_platformData.cgFont(), font, &m, &glyph, &advance)) { LOG_ERROR("Unable to cache glyph widths for %@ %f", [font displayName], pointSize); advance.width = 0; } @@ -374,9 +409,9 @@ void SimpleFontData::checkShapesArabic() const m_checkedShapesArabic = true; - ATSUFontID fontID = m_font.m_atsuFontID; + ATSUFontID fontID = m_platformData.m_atsuFontID; if (!fontID) { - LOG_ERROR("unable to get ATSUFontID for %@", m_font.font()); + LOG_ERROR("unable to get ATSUFontID for %@", m_platformData.font()); return; } @@ -404,7 +439,7 @@ CTFontRef SimpleFontData::getCTFont() const if (getNSFont()) return toCTFontRef(getNSFont()); if (!m_CTFont) - m_CTFont.adoptCF(CTFontCreateWithGraphicsFont(m_font.cgFont(), m_font.size(), NULL, NULL)); + m_CTFont.adoptCF(CTFontCreateWithGraphicsFont(m_platformData.cgFont(), m_platformData.size(), NULL, NULL)); return m_CTFont.get(); } diff --git a/WebCore/platform/graphics/mac/WebLayer.mm b/WebCore/platform/graphics/mac/WebLayer.mm index 267b5bc..fad3916 100644 --- a/WebCore/platform/graphics/mac/WebLayer.mm +++ b/WebCore/platform/graphics/mac/WebLayer.mm @@ -32,7 +32,6 @@ #import "GraphicsContext.h" #import "GraphicsLayer.h" #import <QuartzCore/QuartzCore.h> -#import "WebCoreTextRenderer.h" #import <wtf/UnusedParam.h> using namespace WebCore; diff --git a/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp b/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp index 16c3c00..895887f 100644 --- a/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp +++ b/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 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 @@ -161,11 +161,21 @@ struct nameTable { #pragma pack() -static void appendBigEndianStringToEOTHeader(Vector<uint8_t, 512>& eotHeader, const BigEndianUShort* string, unsigned short length) +EOTHeader::EOTHeader() { - size_t size = eotHeader.size(); - eotHeader.resize(size + length + 2 * sizeof(unsigned short)); - UChar* dst = reinterpret_cast<UChar*>(eotHeader.data() + size); + m_buffer.resize(sizeof(EOTPrefix)); +} + +void EOTHeader::updateEOTSize(size_t fontDataSize) +{ + prefix()->eotSize = m_buffer.size() + fontDataSize; +} + +void EOTHeader::appendBigEndianString(const BigEndianUShort* string, unsigned short length) +{ + size_t oldSize = m_buffer.size(); + m_buffer.resize(oldSize + length + 2 * sizeof(unsigned short)); + UChar* dst = reinterpret_cast<UChar*>(m_buffer.data() + oldSize); unsigned i = 0; dst[i++] = length; unsigned numCharacters = length / 2; @@ -174,7 +184,13 @@ static void appendBigEndianStringToEOTHeader(Vector<uint8_t, 512>& eotHeader, co dst[i] = 0; } -bool getEOTHeader(SharedBuffer* fontData, Vector<uint8_t, 512>& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength) +void EOTHeader::appendPaddingShort() +{ + unsigned short padding = 0; + m_buffer.append(reinterpret_cast<uint8_t*>(&padding), sizeof(padding)); +} + +bool getEOTHeader(SharedBuffer* fontData, EOTHeader& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength) { overlayDst = 0; overlaySrc = 0; @@ -183,8 +199,7 @@ bool getEOTHeader(SharedBuffer* fontData, Vector<uint8_t, 512>& eotHeader, size_ size_t dataLength = fontData->size(); const char* data = fontData->data(); - eotHeader.resize(sizeof(EOTPrefix)); - EOTPrefix* prefix = reinterpret_cast<EOTPrefix*>(eotHeader.data()); + EOTPrefix* prefix = eotHeader.prefix(); prefix->fontDataSize = dataLength; prefix->version = 0x00020001; @@ -306,9 +321,9 @@ bool getEOTHeader(SharedBuffer* fontData, Vector<uint8_t, 512>& eotHeader, size_ prefix->reserved[3] = 0; prefix->padding1 = 0; - appendBigEndianStringToEOTHeader(eotHeader, familyName, familyNameLength); - appendBigEndianStringToEOTHeader(eotHeader, subfamilyName, subfamilyNameLength); - appendBigEndianStringToEOTHeader(eotHeader, versionString, versionStringLength); + eotHeader.appendBigEndianString(familyName, familyNameLength); + eotHeader.appendBigEndianString(subfamilyName, subfamilyNameLength); + eotHeader.appendBigEndianString(versionString, versionStringLength); // If possible, ensure that the family name is a prefix of the full name. if (fullNameLength >= familyNameLength && memcmp(familyName, fullName, familyNameLength)) { @@ -316,13 +331,10 @@ bool getEOTHeader(SharedBuffer* fontData, Vector<uint8_t, 512>& eotHeader, size_ overlayDst = reinterpret_cast<const char*>(familyName) - data; overlayLength = familyNameLength; } + eotHeader.appendBigEndianString(fullName, fullNameLength); - appendBigEndianStringToEOTHeader(eotHeader, fullName, fullNameLength); - - unsigned short padding = 0; - eotHeader.append(reinterpret_cast<uint8_t*>(&padding), sizeof(padding)); - - prefix->eotSize = eotHeader.size() + fontData->size(); + eotHeader.appendPaddingShort(); + eotHeader.updateEOTSize(fontData->size()); return true; } diff --git a/WebCore/platform/graphics/opentype/OpenTypeUtilities.h b/WebCore/platform/graphics/opentype/OpenTypeUtilities.h index a67ffc7..13dad6f 100644 --- a/WebCore/platform/graphics/opentype/OpenTypeUtilities.h +++ b/WebCore/platform/graphics/opentype/OpenTypeUtilities.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 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 @@ -31,9 +31,26 @@ namespace WebCore { +struct BigEndianUShort; +struct EOTPrefix; class SharedBuffer; -bool getEOTHeader(SharedBuffer* fontData, Vector<uint8_t, 512>& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength); +struct EOTHeader { + EOTHeader(); + + size_t size() const { return m_buffer.size(); } + const uint8_t* data() const { return m_buffer.data(); } + + EOTPrefix* prefix() { return reinterpret_cast<EOTPrefix*>(m_buffer.data()); } + void updateEOTSize(size_t); + void appendBigEndianString(const BigEndianUShort*, unsigned short length); + void appendPaddingShort(); + +private: + Vector<uint8_t, 512> m_buffer; +}; + +bool getEOTHeader(SharedBuffer* fontData, EOTHeader& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength); HANDLE renameAndActivateFont(SharedBuffer*, const String&); } // namespace WebCore diff --git a/WebCore/platform/graphics/qt/FontCacheQt.cpp b/WebCore/platform/graphics/qt/FontCacheQt.cpp index 114f073..668912e 100644 --- a/WebCore/platform/graphics/qt/FontCacheQt.cpp +++ b/WebCore/platform/graphics/qt/FontCacheQt.cpp @@ -26,8 +26,11 @@ #include "FontDescription.h" #include "FontPlatformData.h" #include "Font.h" +#include "StringHash.h" #include <wtf/StdLibExtras.h> +#include <QHash> + namespace WebCore { FontCache* fontCache() @@ -44,9 +47,31 @@ void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigne { } +typedef QHash<FontDescription, FontPlatformData*> FontPlatformDataCache; + +// using Q_GLOBAL_STATIC leads to crash. TODO investigate the way to fix this. +static FontPlatformDataCache* gFontPlatformDataCache; + +uint qHash(const FontDescription& key) +{ + uint value = CaseFoldingHash::hash(key.family().family()); + value ^= key.computedPixelSize(); + value ^= static_cast<int>(key.weight()); + return value; +} + FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& description, const AtomicString& family, bool checkingAlternateName) { - return new FontPlatformData(description); + if (!gFontPlatformDataCache) + gFontPlatformDataCache = new FontPlatformDataCache; + + FontPlatformData* fontData = gFontPlatformDataCache->value(description, 0); + if (!fontData) { + fontData = new FontPlatformData(description); + gFontPlatformDataCache->insert(description, fontData); + } + + return fontData; } SimpleFontData* FontCache::getCachedFontData(const FontPlatformData*) @@ -71,4 +96,12 @@ void FontCache::removeClient(FontSelector*) { } +void FontCache::invalidate() +{ + if (!gFontPlatformDataCache) + return; + + gFontPlatformDataCache->clear(); +} + } // namespace WebCore diff --git a/WebCore/platform/graphics/qt/FontFallbackListQt.cpp b/WebCore/platform/graphics/qt/FontFallbackListQt.cpp index 22ae205..50627b7 100644 --- a/WebCore/platform/graphics/qt/FontFallbackListQt.cpp +++ b/WebCore/platform/graphics/qt/FontFallbackListQt.cpp @@ -42,8 +42,6 @@ FontFallbackList::FontFallbackList() void FontFallbackList::invalidate(WTF::PassRefPtr<WebCore::FontSelector> fontSelector) { - releaseFontData(); - m_fontList.clear(); m_familyIndex = 0; m_pitch = UnknownPitch; m_loadingCustomFonts = false; @@ -53,6 +51,9 @@ void FontFallbackList::invalidate(WTF::PassRefPtr<WebCore::FontSelector> fontSel void FontFallbackList::releaseFontData() { + if (m_fontList.size()) + delete m_fontList[0].first; + m_fontList.clear(); } void FontFallbackList::determinePitch(const WebCore::Font* font) const @@ -90,7 +91,12 @@ const FontData* FontFallbackList::fontDataAt(const WebCore::Font* _font, unsigne family = family->next(); } - return new SimpleFontData(FontPlatformData(description), _font->wordSpacing(), _font->letterSpacing()); + if (m_fontList.size()) + return m_fontList[0].first; + + const FontData* result = new SimpleFontData(FontPlatformData(description), _font->wordSpacing(), _font->letterSpacing()); + m_fontList.append(pair<const FontData*, bool>(result, result->isCustomFont())); + return result; } const FontData* FontFallbackList::fontDataForCharacters(const WebCore::Font* font, const UChar*, int) const diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp index 9ed5915..5a4b7b2 100644 --- a/WebCore/platform/graphics/qt/FontQt.cpp +++ b/WebCore/platform/graphics/qt/FontQt.cpp @@ -183,7 +183,7 @@ void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const Float p->drawText(pt, string, flags, run.padding()); } -float Font::floatWidthForComplexText(const TextRun& run) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*) const { if (!run.length()) return 0; diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp index ccf4b06..ed7ac47 100644 --- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -99,7 +99,7 @@ static inline QPainter::CompositionMode toQtCompositionMode(CompositeOperator op case CompositeHighlight: return QPainter::CompositionMode_SourceOver; case CompositePlusLighter: - return QPainter::CompositionMode_SourceOver; + return QPainter::CompositionMode_Plus; } return QPainter::CompositionMode_SourceOver; @@ -153,6 +153,18 @@ static Qt::PenStyle toQPenStyle(StrokeStyle style) return Qt::NoPen; } +static inline Qt::FillRule toQtFillRule(WindRule rule) +{ + switch(rule) { + case RULE_EVENODD: + return Qt::OddEvenFill; + case RULE_NONZERO: + return Qt::WindingFill; + } + qDebug("Qt: unrecognized wind rule!"); + return Qt::OddEvenFill; +} + struct TransparencyLayer { TransparencyLayer(const QPainter* p, const QRect &rect) @@ -563,7 +575,7 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp QPainter *p = m_data->p(); const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); - p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines); + p->setRenderHint(QPainter::Antialiasing, true); p->drawArc(rect, startAngle * 16, angleSpan * 16); @@ -606,6 +618,7 @@ void GraphicsContext::fillPath() QPainter *p = m_data->p(); QPainterPath path = m_data->currentPath; + path.setFillRule(toQtFillRule(fillRule())); switch (m_common->state.fillColorSpace) { case SolidColorSpace: @@ -634,6 +647,7 @@ void GraphicsContext::strokePath() QPainter *p = m_data->p(); QPen pen = p->pen(); QPainterPath path = m_data->currentPath; + path.setFillRule(toQtFillRule(fillRule())); switch (m_common->state.strokeColorSpace) { case SolidColorSpace: @@ -1097,7 +1111,13 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, rect.width() - (thickness * 2), rect.height() - (thickness * 2))); path.setFillRule(Qt::OddEvenFill); - m_data->p()->setClipPath(path, Qt::IntersectClip); + + QPainter *p = m_data->p(); + + const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); + p->setRenderHint(QPainter::Antialiasing, true); + p->setClipPath(path, Qt::IntersectClip); + p->setRenderHint(QPainter::Antialiasing, antiAlias); } void GraphicsContext::concatCTM(const TransformationMatrix& transform) diff --git a/WebCore/platform/graphics/qt/IconQt.cpp b/WebCore/platform/graphics/qt/IconQt.cpp index b04668c..c9f3ced 100644 --- a/WebCore/platform/graphics/qt/IconQt.cpp +++ b/WebCore/platform/graphics/qt/IconQt.cpp @@ -24,7 +24,6 @@ #include "GraphicsContext.h" #include "PlatformString.h" #include "IntRect.h" -#include "NotImplemented.h" #include <qpainter.h> #include <qpixmap.h> diff --git a/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/WebCore/platform/graphics/qt/ImageBufferQt.cpp index d748305..506a8ea 100644 --- a/WebCore/platform/graphics/qt/ImageBufferQt.cpp +++ b/WebCore/platform/graphics/qt/ImageBufferQt.cpp @@ -47,7 +47,24 @@ ImageBufferData::ImageBufferData(const IntSize& size) : m_pixmap(size) { m_pixmap.fill(QColor(Qt::transparent)); - m_painter.set(new QPainter(&m_pixmap)); + + QPainter* painter = new QPainter(&m_pixmap); + m_painter.set(painter); + + // Since ImageBuffer is used mainly for Canvas, explicitly initialize + // its painter's pen and brush with the corresponding canvas defaults + // NOTE: keep in sync with CanvasRenderingContext2D::State + QPen pen = painter->pen(); + pen.setColor(Qt::black); + pen.setWidth(1); + pen.setCapStyle(Qt::FlatCap); + pen.setJoinStyle(Qt::MiterJoin); + pen.setMiterLimit(10); + painter->setPen(pen); + QBrush brush = painter->brush(); + brush.setColor(Qt::black); + painter->setBrush(brush); + painter->setCompositionMode(QPainter::CompositionMode_SourceOver); } ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, bool& success) diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp index 394c7a7..cd32428 100644 --- a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp @@ -197,7 +197,8 @@ ImageDecoderQt* ImageDecoderQt::create(const SharedBuffer& data) } ImageDecoderQt::ImageDecoderQt(const QString &imageFormat) - : m_imageFormat(imageFormat) + : m_hasAlphaChannel(false) + , m_imageFormat(imageFormat) { } @@ -212,6 +213,7 @@ bool ImageDecoderQt::hasFirstImageHeader() const void ImageDecoderQt::reset() { + m_hasAlphaChannel = false; m_failed = false; m_imageList.clear(); m_pixmapCache.clear(); @@ -230,6 +232,9 @@ void ImageDecoderQt::setData(const IncomingData &data, bool allDataReceived) const ReadContext::ReadResult readResult = readContext.read(allDataReceived); + if (hasFirstImageHeader()) + m_hasAlphaChannel = m_imageList[0].m_image.hasAlphaChannel(); + if (debugImageDecoderQt) qDebug() << " read returns " << readResult; @@ -280,7 +285,7 @@ int ImageDecoderQt::repetitionCount() const bool ImageDecoderQt::supportsAlpha() const { - return hasFirstImageHeader() && m_imageList[0].m_image.hasAlphaChannel(); + return m_hasAlphaChannel; } int ImageDecoderQt::duration(size_t index) const @@ -314,6 +319,10 @@ QPixmap* ImageDecoderQt::imageAtIndex(size_t index) const if (!m_pixmapCache.contains(index)) { m_pixmapCache.insert(index, QPixmap::fromImage(m_imageList[index].m_image)); + + // store null image since the converted pixmap is already in pixmap cache + Q_ASSERT(m_imageList[index].m_imageState == ImageComplete); + m_imageList[index].m_image = QImage(); } return &m_pixmapCache[index]; } diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.h b/WebCore/platform/graphics/qt/ImageDecoderQt.h index a2eb6aa..b8c3edd 100644 --- a/WebCore/platform/graphics/qt/ImageDecoderQt.h +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.h @@ -81,8 +81,9 @@ private: int m_duration; }; + bool m_hasAlphaChannel; typedef QList<ImageData> ImageList; - ImageList m_imageList; + mutable ImageList m_imageList; mutable QHash<int, QPixmap> m_pixmapCache; int m_loopCount; QString m_imageFormat; diff --git a/WebCore/platform/graphics/qt/ImageQt.cpp b/WebCore/platform/graphics/qt/ImageQt.cpp index 3bc67ae..a2e96f3 100644 --- a/WebCore/platform/graphics/qt/ImageQt.cpp +++ b/WebCore/platform/graphics/qt/ImageQt.cpp @@ -31,12 +31,12 @@ #include "config.h" #include "Image.h" +#include "ImageObserver.h" #include "BitmapImage.h" #include "FloatRect.h" #include "PlatformString.h" #include "GraphicsContext.h" #include "TransformationMatrix.h" -#include "NotImplemented.h" #include "StillImageQt.h" #include "qwebsettings.h" @@ -117,6 +117,9 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const p->setBrushOrigin(phase); p->fillRect(destRect, b); ctxt->restore(); + + if (imageObserver()) + imageObserver()->didDraw(this); } void BitmapImage::initPlatformData() @@ -159,6 +162,9 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, painter->drawPixmap(dst, *image, src); ctxt->restore(); + + if (imageObserver()) + imageObserver()->didDraw(this); } void BitmapImage::checkForSolidColor() diff --git a/WebCore/platform/graphics/qt/ImageSourceQt.cpp b/WebCore/platform/graphics/qt/ImageSourceQt.cpp index 84de443..621728e 100644 --- a/WebCore/platform/graphics/qt/ImageSourceQt.cpp +++ b/WebCore/platform/graphics/qt/ImageSourceQt.cpp @@ -29,7 +29,6 @@ #include "config.h" #include "ImageSource.h" #include "ImageDecoderQt.h" -#include "NotImplemented.h" #include "SharedBuffer.h" #include <QBuffer> diff --git a/WebCore/platform/graphics/qt/PathQt.cpp b/WebCore/platform/graphics/qt/PathQt.cpp index a8a3ea2..7569031 100644 --- a/WebCore/platform/graphics/qt/PathQt.cpp +++ b/WebCore/platform/graphics/qt/PathQt.cpp @@ -39,6 +39,7 @@ #include <QPainterPath> #include <QTransform> #include <QString> +#include <wtf/OwnPtr.h> #define _USE_MATH_DEFINES #include <math.h> @@ -91,7 +92,7 @@ bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) // FIXME: We should try to use a 'shared Context' instead of creating a new ImageBuffer // on each call. - std::auto_ptr<ImageBuffer> scratchImage = ImageBuffer::create(IntSize(1, 1), false); + OwnPtr<ImageBuffer> scratchImage = ImageBuffer::create(IntSize(1, 1), false); GraphicsContext* gc = scratchImage->context(); QPainterPathStroker stroke; applier->strokeStyle(gc); @@ -123,7 +124,7 @@ FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) { // FIXME: We should try to use a 'shared Context' instead of creating a new ImageBuffer // on each call. - std::auto_ptr<ImageBuffer> scratchImage = ImageBuffer::create(IntSize(1, 1), false); + OwnPtr<ImageBuffer> scratchImage = ImageBuffer::create(IntSize(1, 1), false); GraphicsContext* gc = scratchImage->context(); QPainterPathStroker stroke; if (applier) { diff --git a/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp b/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp index 6cf4e55..f823f84 100644 --- a/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp +++ b/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp @@ -30,7 +30,7 @@ namespace WebCore { void SimpleFontData::determinePitch() { - m_treatAsFixedPitch = m_font.font().fixedPitch(); + m_treatAsFixedPitch = m_platformData.font().fixedPitch(); } bool SimpleFontData::containsCharacters(const UChar*, int length) const @@ -40,7 +40,7 @@ bool SimpleFontData::containsCharacters(const UChar*, int length) const void SimpleFontData::platformInit() { - QFontMetrics fm(m_font.font()); + QFontMetrics fm(m_platformData.font()); m_ascent = fm.ascent(); m_descent = fm.descent(); @@ -59,6 +59,13 @@ void SimpleFontData::platformGlyphInit() m_missingGlyphData.glyph = 0; } +void SimpleFontData::platformCharWidthInit() +{ + QFontMetrics fm(m_platformData.font()); + m_avgCharWidth = fm.averageCharWidth(); + m_maxCharWidth = fm.maxWidth(); +} + void SimpleFontData::platformDestroy() { } diff --git a/WebCore/platform/graphics/skia/GradientSkia.cpp b/WebCore/platform/graphics/skia/GradientSkia.cpp index 2d2000c..ac7366c 100644 --- a/WebCore/platform/graphics/skia/GradientSkia.cpp +++ b/WebCore/platform/graphics/skia/GradientSkia.cpp @@ -60,12 +60,14 @@ static SkColor makeSkColor(float a, float r, float g, float b) // ends as necessary. static size_t totalStopsNeeded(const Gradient::ColorStop* stopData, size_t count) { + // N.B.: The tests in this function should kept in sync with the ones in + // fillStops(), or badness happens. const Gradient::ColorStop* stop = stopData; size_t countUsed = count; if (count < 1 || stop->stop > 0.0) countUsed++; stop += count - 1; - if (count < 2 || stop->stop < 1.0) + if (count < 1 || stop->stop < 1.0) countUsed++; return countUsed; } diff --git a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp index 376fa4b..33ca23a 100644 --- a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp +++ b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp @@ -449,10 +449,8 @@ void GraphicsContext::drawConvexPolygon(size_t numPoints, return; SkPaint paint; - if (fillColor().alpha() > 0) { - platformContext()->setupPaintForFilling(&paint); - platformContext()->canvas()->drawPath(path, paint); - } + platformContext()->setupPaintForFilling(&paint); + platformContext()->canvas()->drawPath(path, paint); if (strokeStyle() != NoStroke) { paint.reset(); @@ -472,10 +470,8 @@ void GraphicsContext::drawEllipse(const IntRect& elipseRect) return; SkPaint paint; - if (fillColor().alpha() > 0) { - platformContext()->setupPaintForFilling(&paint); - platformContext()->canvas()->drawOval(rect, paint); - } + platformContext()->setupPaintForFilling(&paint); + platformContext()->canvas()->drawOval(rect, paint); if (strokeStyle() != NoStroke) { paint.reset(); @@ -685,9 +681,6 @@ void GraphicsContext::fillPath() const GraphicsContextState& state = m_common->state; ColorSpace colorSpace = state.fillColorSpace; - if (colorSpace == SolidColorSpace && !fillColor().alpha()) - return; - path.setFillType(state.fillRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType); @@ -718,9 +711,6 @@ void GraphicsContext::fillRect(const FloatRect& rect) const GraphicsContextState& state = m_common->state; ColorSpace colorSpace = state.fillColorSpace; - if (colorSpace == SolidColorSpace && !fillColor().alpha()) - return; - SkPaint paint; platformContext()->setupPaintForFilling(&paint); @@ -739,9 +729,6 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) if (paintingDisabled()) return; - if (!color.alpha()) - return; - SkRect r = rect; if (!isRectSkiaSafe(getCTM(), r)) { // Special case when the rectangle overflows fixed point. This is a @@ -907,8 +894,13 @@ void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset) // FIXME: This is lifted directly off SkiaSupport, lines 49-74 // so it is not guaranteed to work correctly. size_t dashLength = dashes.size(); - if (!dashLength) + if (!dashLength) { + // If no dash is set, revert to solid stroke + // FIXME: do we need to set NoStroke in some cases? + platformContext()->setStrokeStyle(SolidStroke); + platformContext()->setDashPathEffect(0); return; + } size_t count = (dashLength % 2) == 0 ? dashLength : dashLength * 2; SkScalar* intervals = new SkScalar[count]; @@ -962,6 +954,12 @@ void GraphicsContext::setPlatformShadow(const IntSize& size, if (paintingDisabled()) return; + // Detect when there's no effective shadow and clear the looper. + if (size.width() == 0 && size.height() == 0 && blurInt == 0) { + platformContext()->setDrawLooper(NULL); + return; + } + double width = size.width(); double height = size.height(); double blur = blurInt; @@ -1076,9 +1074,6 @@ void GraphicsContext::strokePath() const GraphicsContextState& state = m_common->state; ColorSpace colorSpace = state.strokeColorSpace; - if (colorSpace == SolidColorSpace && !strokeColor().alpha()) - return; - SkPaint paint; platformContext()->setupPaintForStroking(&paint, 0, 0); @@ -1103,9 +1098,6 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth) const GraphicsContextState& state = m_common->state; ColorSpace colorSpace = state.strokeColorSpace; - if (colorSpace == SolidColorSpace && !strokeColor().alpha()) - return; - SkPaint paint; platformContext()->setupPaintForStroking(&paint, 0, 0); paint.setStrokeWidth(WebCoreFloatToSkScalar(lineWidth)); diff --git a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp index 5e90491..600882d 100644 --- a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp +++ b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp @@ -36,7 +36,6 @@ #include "BitmapImageSingleFrameSkia.h" #include "GraphicsContext.h" #include "ImageData.h" -#include "NotImplemented.h" #include "PlatformContextSkia.h" #include "PNGImageEncoder.h" #include "SkiaUtils.h" diff --git a/WebCore/platform/graphics/skia/ImageSkia.cpp b/WebCore/platform/graphics/skia/ImageSkia.cpp index d7f2830..cb089bb 100644 --- a/WebCore/platform/graphics/skia/ImageSkia.cpp +++ b/WebCore/platform/graphics/skia/ImageSkia.cpp @@ -38,7 +38,6 @@ #include "GraphicsContext.h" #include "Logging.h" #include "NativeImageSkia.h" -#include "NotImplemented.h" #include "PlatformContextSkia.h" #include "PlatformString.h" #include "SkiaUtils.h" @@ -226,6 +225,12 @@ static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImag SkPaint paint; paint.setPorterDuffXfermode(compOp); paint.setFilterBitmap(true); + int alpha = roundf(platformContext->getAlpha() * 256); + if (alpha > 255) + alpha = 255; + else if (alpha < 0) + alpha = 0; + paint.setAlpha(alpha); skia::PlatformCanvas* canvas = platformContext->canvas(); @@ -305,7 +310,8 @@ void Image::drawPattern(GraphicsContext* context, CompositeOperator compositeOp, const FloatRect& destRect) { - if (destRect.isEmpty() || floatSrcRect.isEmpty()) + FloatRect normSrcRect = normalizeRect(floatSrcRect); + if (destRect.isEmpty() || normSrcRect.isEmpty()) return; // nothing to draw NativeImageSkia* bitmap = nativeImageForCurrentFrame(); @@ -316,7 +322,7 @@ void Image::drawPattern(GraphicsContext* context, // it will internally reference the old bitmap's pixels, adjusting the row // stride so the extra pixels appear as padding to the subsetted bitmap. SkBitmap srcSubset; - SkIRect srcRect = enclosingIntRect(floatSrcRect); + SkIRect srcRect = enclosingIntRect(normSrcRect); bitmap->extractSubset(&srcSubset, srcRect); SkBitmap resampled; @@ -363,9 +369,9 @@ void Image::drawPattern(GraphicsContext* context, // origin of the destination rect, which is what WebKit expects. Skia uses // the coordinate system origin as the base for the patter. If WebKit wants // a shifted image, it will shift it from there using the patternTransform. - float adjustedX = phase.x() + floatSrcRect.x() * + float adjustedX = phase.x() + normSrcRect.x() * narrowPrecisionToFloat(patternTransform.a()); - float adjustedY = phase.y() + floatSrcRect.y() * + float adjustedY = phase.y() + normSrcRect.y() * narrowPrecisionToFloat(patternTransform.d()); matrix.postTranslate(SkFloatToScalar(adjustedX), SkFloatToScalar(adjustedY)); diff --git a/WebCore/platform/graphics/skia/PathSkia.cpp b/WebCore/platform/graphics/skia/PathSkia.cpp index 2700da8..9d9df52 100644 --- a/WebCore/platform/graphics/skia/PathSkia.cpp +++ b/WebCore/platform/graphics/skia/PathSkia.cpp @@ -81,9 +81,15 @@ void Path::translate(const FloatSize& size) FloatRect Path::boundingRect() const { + // FIXME: This #ifdef can go away once we're firmly using the new Skia. + // During the transition, this makes the code compatible with both versions. +#ifdef SK_USE_OLD_255_TO_256 + return m_path->getBounds(); +#else SkRect rect; m_path->computeBounds(&rect, SkPath::kExact_BoundsType); return rect; +#endif } void Path::moveTo(const FloatPoint& point) @@ -275,9 +281,15 @@ static FloatRect boundingBoxForCurrentStroke(const GraphicsContext* context) context->platformContext()->setupPaintForStroking(&paint, 0, 0); SkPath boundingPath; paint.getFillPath(context->platformContext()->currentPathInLocalCoordinates(), &boundingPath); + // FIXME: This #ifdef can go away once we're firmly using the new Skia. + // During the transition, this makes the code compatible with both versions. +#ifdef SK_USE_OLD_255_TO_256 + return boundingPath.getBounds(); +#else SkRect r; boundingPath.computeBounds(&r, SkPath::kExact_BoundsType); return r; +#endif } FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp index 6c633f2..74b2bfe 100644 --- a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp @@ -277,13 +277,13 @@ void PlatformContextSkia::drawRect(SkRect rect) if (oldFillColor != m_state->m_strokeColor) setFillColor(m_state->m_strokeColor); setupPaintForFilling(&paint); - SkRect topBorder = { rect.fLeft, rect.fTop, rect.width(), 1 }; + SkRect topBorder = { rect.fLeft, rect.fTop, rect.fRight, rect.fTop + 1 }; canvas()->drawRect(topBorder, paint); - SkRect bottomBorder = { rect.fLeft, rect.fBottom - 1, rect.width(), 1 }; + SkRect bottomBorder = { rect.fLeft, rect.fBottom - 1, rect.fRight, rect.fBottom }; canvas()->drawRect(bottomBorder, paint); - SkRect leftBorder = { rect.fLeft, rect.fTop + 1, 1, rect.height() - 2 }; + SkRect leftBorder = { rect.fLeft, rect.fTop + 1, rect.fLeft + 1, rect.fBottom - 1 }; canvas()->drawRect(leftBorder, paint); - SkRect rightBorder = { rect.fRight - 1, rect.fTop + 1, 1, rect.height() - 2 }; + SkRect rightBorder = { rect.fRight - 1, rect.fTop + 1, rect.fRight, rect.fBottom - 1 }; canvas()->drawRect(rightBorder, paint); if (oldFillColor != m_state->m_strokeColor) setFillColor(oldFillColor); @@ -428,6 +428,11 @@ int PlatformContextSkia::getTextDrawingMode() const return m_state->m_textDrawingMode; } +float PlatformContextSkia::getAlpha() const +{ + return m_state->m_alpha; +} + void PlatformContextSkia::setTextDrawingMode(int mode) { // cTextClip is never used, so we assert that it isn't set: diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.h b/WebCore/platform/graphics/skia/PlatformContextSkia.h index 8850a6a..25495aa 100644 --- a/WebCore/platform/graphics/skia/PlatformContextSkia.h +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.h @@ -130,6 +130,7 @@ public: WebCore::StrokeStyle getStrokeStyle() const; float getStrokeThickness() const; int getTextDrawingMode() const; + float getAlpha() const; void beginPath(); void addPath(const SkPath&); diff --git a/WebCore/platform/graphics/skia/SkiaFontWin.cpp b/WebCore/platform/graphics/skia/SkiaFontWin.cpp index d0cd4c5..7f12508 100644 --- a/WebCore/platform/graphics/skia/SkiaFontWin.cpp +++ b/WebCore/platform/graphics/skia/SkiaFontWin.cpp @@ -220,6 +220,16 @@ void SkiaWinOutlineCache::removePathsForFont(HFONT hfont) deleteOutline(outlineCache.find(*i)); } +bool windowsCanHandleDrawTextShadow(WebCore::GraphicsContext *context) +{ + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + + bool hasShadow = context->getShadow(shadowSize, shadowBlur, shadowColor); + return (hasShadow && (shadowBlur == 0) && (shadowColor.alpha() == 255) && (context->fillColor().alpha() == 255)); +} + bool windowsCanHandleTextDrawing(GraphicsContext* context) { // Check for non-translation transforms. Sometimes zooms will look better in @@ -244,7 +254,7 @@ bool windowsCanHandleTextDrawing(GraphicsContext* context) return false; // Check for shadow effects. - if (context->platformContext()->getDrawLooper()) + if (context->platformContext()->getDrawLooper() && (!windowsCanHandleDrawTextShadow(context))) return false; return true; diff --git a/WebCore/platform/graphics/skia/SkiaFontWin.h b/WebCore/platform/graphics/skia/SkiaFontWin.h index 0e0c953..0bad30f 100644 --- a/WebCore/platform/graphics/skia/SkiaFontWin.h +++ b/WebCore/platform/graphics/skia/SkiaFontWin.h @@ -68,8 +68,12 @@ private: // Remember that Skia's text drawing origin is the baseline, like WebKit, not // the top, like Windows. +// Returns true if the fillColor and shadowColor are opaque and the text-shadow +// is not blurred. +bool windowsCanHandleDrawTextShadow(GraphicsContext*); + // Returns true if advanced font rendering is recommended. -bool windowsCanHandleTextDrawing(GraphicsContext* context); +bool windowsCanHandleTextDrawing(GraphicsContext*); // Note that the offsets parameter is optional. If not NULL it represents a // per glyph offset (such as returned by ScriptPlace Windows API function). diff --git a/WebCore/platform/graphics/skia/SkiaUtils.cpp b/WebCore/platform/graphics/skia/SkiaUtils.cpp index 55cba37..4242e7d 100644 --- a/WebCore/platform/graphics/skia/SkiaUtils.cpp +++ b/WebCore/platform/graphics/skia/SkiaUtils.cpp @@ -47,7 +47,7 @@ static const struct CompositOpToPorterDuffMode { uint8_t mPorterDuffMode; } gMapCompositOpsToPorterDuffModes[] = { { CompositeClear, SkPorterDuff::kClear_Mode }, - { CompositeCopy, SkPorterDuff::kSrcOver_Mode }, // TODO + { CompositeCopy, SkPorterDuff::kSrc_Mode }, { CompositeSourceOver, SkPorterDuff::kSrcOver_Mode }, { CompositeSourceIn, SkPorterDuff::kSrcIn_Mode }, { CompositeSourceOut, SkPorterDuff::kSrcOut_Mode }, @@ -59,7 +59,7 @@ static const struct CompositOpToPorterDuffMode { { CompositeXOR, SkPorterDuff::kXor_Mode }, { CompositePlusDarker, SkPorterDuff::kDarken_Mode }, { CompositeHighlight, SkPorterDuff::kSrcOver_Mode }, // TODO - { CompositePlusLighter, SkPorterDuff::kLighten_Mode } + { CompositePlusLighter, SkPorterDuff::kAdd_Mode } }; SkPorterDuff::Mode WebCoreCompositeToSkiaComposite(CompositeOperator op) @@ -135,12 +135,7 @@ bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath:: int scale = 1; SkRect bounds; -#if PLATFORM(SGL) - // this is the API from skia/trunk bounds = originalPath->getBounds(); -#else - originalPath->computeBounds(&bounds, SkPath::kFast_BoundsType); -#endif // We can immediately return false if the point is outside the bounding rect if (!bounds.contains(SkFloatToScalar(point.x()), SkFloatToScalar(point.y()))) diff --git a/WebCore/platform/graphics/transforms/TransformationMatrix.cpp b/WebCore/platform/graphics/transforms/TransformationMatrix.cpp index 63a7b8e..a358aaf 100644 --- a/WebCore/platform/graphics/transforms/TransformationMatrix.cpp +++ b/WebCore/platform/graphics/transforms/TransformationMatrix.cpp @@ -31,6 +31,7 @@ #include "FloatQuad.h" #include "IntRect.h" +#include <wtf/Assertions.h> #include <wtf/MathExtras.h> namespace WebCore { @@ -556,6 +557,9 @@ FloatQuad TransformationMatrix::projectQuad(const FloatQuad& q) const FloatPoint TransformationMatrix::mapPoint(const FloatPoint& p) const { + if (isIdentityOrTranslation()) + return FloatPoint(p.x() + static_cast<float>(m_matrix[3][0]), p.y() + static_cast<float>(m_matrix[3][1])); + double x, y; multVecMatrix(p.x(), p.y(), x, y); return FloatPoint(static_cast<float>(x), static_cast<float>(y)); @@ -563,20 +567,16 @@ FloatPoint TransformationMatrix::mapPoint(const FloatPoint& p) const FloatPoint3D TransformationMatrix::mapPoint(const FloatPoint3D& p) const { + if (isIdentityOrTranslation()) + return FloatPoint3D(p.x() + static_cast<float>(m_matrix[3][0]), + p.y() + static_cast<float>(m_matrix[3][1]), + p.z() + static_cast<float>(m_matrix[3][2])); + double x, y, z; multVecMatrix(p.x(), p.y(), p.z(), x, y, z); return FloatPoint3D(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z)); } -IntPoint TransformationMatrix::mapPoint(const IntPoint& point) const -{ - double x, y; - multVecMatrix(point.x(), point.y(), x, y); - - // Round the point. - return IntPoint(lround(x), lround(y)); -} - IntRect TransformationMatrix::mapRect(const IntRect &rect) const { return enclosingIntRect(mapRect(FloatRect(rect))); @@ -584,12 +584,24 @@ IntRect TransformationMatrix::mapRect(const IntRect &rect) const FloatRect TransformationMatrix::mapRect(const FloatRect& r) const { + if (isIdentityOrTranslation()) { + FloatRect mappedRect(r); + mappedRect.move(static_cast<float>(m_matrix[3][0]), static_cast<float>(m_matrix[3][1])); + return mappedRect; + } + FloatQuad resultQuad = mapQuad(FloatQuad(r)); return resultQuad.boundingBox(); } FloatQuad TransformationMatrix::mapQuad(const FloatQuad& q) const { + if (isIdentityOrTranslation()) { + FloatQuad mappedQuad(q); + mappedQuad.move(static_cast<float>(m_matrix[3][0]), static_cast<float>(m_matrix[3][1])); + return mappedQuad; + } + FloatQuad result; result.setP1(mapPoint(q.p1())); result.setP2(mapPoint(q.p2())); @@ -781,38 +793,19 @@ TransformationMatrix& TransformationMatrix::rotate3d(double rx, double ry, doubl TransformationMatrix& TransformationMatrix::translate(double tx, double ty) { -#ifdef ANDROID_FASTER_MATRIX m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0]; m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1]; m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2]; m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3]; -#else - // FIXME: optimize to avoid matrix copy - TransformationMatrix mat; - mat.m_matrix[3][0] = tx; - mat.m_matrix[3][1] = ty; - - multLeft(mat); -#endif return *this; } TransformationMatrix& TransformationMatrix::translate3d(double tx, double ty, double tz) { -#ifdef ANDROID_FASTER_MATRIX m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0] + tz * m_matrix[2][0]; m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1] + tz * m_matrix[2][1]; m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2] + tz * m_matrix[2][2]; m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3] + tz * m_matrix[2][3]; -#else - // FIXME: optimize to avoid matrix copy - TransformationMatrix mat; - mat.m_matrix[3][0] = tx; - mat.m_matrix[3][1] = ty; - mat.m_matrix[3][2] = tz; - - multLeft(mat); -#endif return *this; } @@ -945,6 +938,9 @@ void TransformationMatrix::multVecMatrix(double x, double y, double z, double& r bool TransformationMatrix::isInvertible() const { + if (isIdentityOrTranslation()) + return true; + double det = WebCore::determinant4x4(m_matrix); if (fabs(det) < SMALL_NUMBER) @@ -955,8 +951,19 @@ bool TransformationMatrix::isInvertible() const TransformationMatrix TransformationMatrix::inverse() const { - TransformationMatrix invMat; + if (isIdentityOrTranslation()) { + // identity matrix + if (m_matrix[3][0] == 0 && m_matrix[3][1] == 0 && m_matrix[3][2] == 0) + return TransformationMatrix(); + + // translation + return TransformationMatrix(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + -m_matrix[3][0], -m_matrix[3][1], -m_matrix[3][2], 1); + } + TransformationMatrix invMat; bool inverted = WebCore::inverse(m_matrix, invMat.m_matrix); if (!inverted) return TransformationMatrix(); diff --git a/WebCore/platform/graphics/transforms/TransformationMatrix.h b/WebCore/platform/graphics/transforms/TransformationMatrix.h index 62e4eb8..7b93e04 100644 --- a/WebCore/platform/graphics/transforms/TransformationMatrix.h +++ b/WebCore/platform/graphics/transforms/TransformationMatrix.h @@ -26,6 +26,10 @@ #ifndef TransformationMatrix_h #define TransformationMatrix_h +#include "FloatPoint.h" +#include "IntPoint.h" +#include <string.h> //for memcpy + #if PLATFORM(CG) #include <CoreGraphics/CGAffineTransform.h> #elif PLATFORM(CAIRO) @@ -38,13 +42,9 @@ #include <wx/graphics.h> #endif -#include <string.h> //for memcpy - namespace WebCore { -class IntPoint; class IntRect; -class FloatPoint; class FloatPoint3D; class FloatRect; class FloatQuad; @@ -114,7 +114,10 @@ public: FloatPoint mapPoint(const FloatPoint&) const; // Like the version above, except that it rounds the mapped point to the nearest integer value. - IntPoint mapPoint(const IntPoint&) const; + IntPoint mapPoint(const IntPoint& p) const + { + return roundedIntPoint(mapPoint(FloatPoint(p))); + } // If the matrix has 3D components, the z component of the result is // dropped, effectively projecting the rect into the z=0 plane @@ -313,6 +316,14 @@ private: memcpy(m_matrix, m, sizeof(Matrix4)); } + bool isIdentityOrTranslation() const + { + return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0 && + m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0 && + m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0 && + m_matrix[3][3] == 1; + } + Matrix4 m_matrix; }; diff --git a/WebCore/platform/graphics/win/ColorSafari.cpp b/WebCore/platform/graphics/win/ColorSafari.cpp index a04fd81..25b6b89 100644 --- a/WebCore/platform/graphics/win/ColorSafari.cpp +++ b/WebCore/platform/graphics/win/ColorSafari.cpp @@ -29,7 +29,6 @@ #include "config.h" #include "Color.h" -#include "NotImplemented.h" #include <CoreGraphics/CGColor.h> #include <SafariTheme/SafariTheme.h> #include <wtf/Assertions.h> diff --git a/WebCore/platform/graphics/win/FontCGWin.cpp b/WebCore/platform/graphics/win/FontCGWin.cpp index feeb2ae..803f5db 100644 --- a/WebCore/platform/graphics/win/FontCGWin.cpp +++ b/WebCore/platform/graphics/win/FontCGWin.cpp @@ -181,7 +181,7 @@ static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData SetWorldTransform(hdc, &xform); } - SelectObject(hdc, font->m_font.hfont()); + SelectObject(hdc, font->platformData().hfont()); // Set the correct color. if (drawIntoBitmap) @@ -215,9 +215,9 @@ static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData xform.eDy = point.y(); ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data()); - if (font->m_syntheticBoldOffset) { + if (font->syntheticBoldOffset()) { xform.eM21 = 0; - xform.eDx = font->m_syntheticBoldOffset; + xform.eDx = font->syntheticBoldOffset(); xform.eDy = 0; ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data()); @@ -250,21 +250,21 @@ static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData if (drawingMode & cTextFill) { CGContextAddPath(cgContext, glyphPath.get()); CGContextFillPath(cgContext); - if (font->m_syntheticBoldOffset) { - CGContextTranslateCTM(cgContext, font->m_syntheticBoldOffset, 0); + if (font->syntheticBoldOffset()) { + CGContextTranslateCTM(cgContext, font->syntheticBoldOffset(), 0); CGContextAddPath(cgContext, glyphPath.get()); CGContextFillPath(cgContext); - CGContextTranslateCTM(cgContext, -font->m_syntheticBoldOffset, 0); + CGContextTranslateCTM(cgContext, -font->syntheticBoldOffset(), 0); } } if (drawingMode & cTextStroke) { CGContextAddPath(cgContext, glyphPath.get()); CGContextStrokePath(cgContext); - if (font->m_syntheticBoldOffset) { - CGContextTranslateCTM(cgContext, font->m_syntheticBoldOffset, 0); + if (font->syntheticBoldOffset()) { + CGContextTranslateCTM(cgContext, font->syntheticBoldOffset(), 0); CGContextAddPath(cgContext, glyphPath.get()); CGContextStrokePath(cgContext); - CGContextTranslateCTM(cgContext, -font->m_syntheticBoldOffset, 0); + CGContextTranslateCTM(cgContext, -font->syntheticBoldOffset(), 0); } } @@ -341,8 +341,8 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo graphicsContext->setFillColor(shadowFillColor); 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->m_syntheticBoldOffset) { - CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowSize.width() + font->m_syntheticBoldOffset, point.y() + translation.height() + shadowSize.height()); + 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); @@ -350,8 +350,8 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo CGContextSetTextPosition(cgContext, point.x() + translation.width(), point.y() + translation.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); - if (font->m_syntheticBoldOffset) { - CGContextSetTextPosition(cgContext, point.x() + translation.width() + font->m_syntheticBoldOffset, point.y() + translation.height()); + if (font->syntheticBoldOffset()) { + CGContextSetTextPosition(cgContext, point.x() + translation.width() + font->syntheticBoldOffset(), point.y() + translation.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); } diff --git a/WebCore/platform/graphics/win/FontCustomPlatformData.cpp b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp index 1ac3359..24db173 100644 --- a/WebCore/platform/graphics/win/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp @@ -116,7 +116,7 @@ size_t getBytesWithOffset(void *info, void* buffer, size_t offset, size_t count) // Streams the concatenation of a header and font data. class EOTStream { public: - EOTStream(const Vector<uint8_t, 512>& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength) + 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) @@ -130,7 +130,7 @@ public: size_t read(void* buffer, size_t count); private: - const Vector<uint8_t, 512>& m_eotHeader; + const EOTHeader& m_eotHeader; const SharedBuffer* m_fontData; size_t m_overlayDst; size_t m_overlaySrc; @@ -206,7 +206,7 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) // TTLoadEmbeddedFont works only with Embedded OpenType (.eot) data, so we need to create an EOT header // and prepend it to the font data. - Vector<uint8_t, 512> eotHeader; + EOTHeader eotHeader; size_t overlayDst; size_t overlaySrc; size_t overlayLength; diff --git a/WebCore/platform/graphics/win/FontWin.cpp b/WebCore/platform/graphics/win/FontWin.cpp index 5e423e0..27d8dee 100644 --- a/WebCore/platform/graphics/win/FontWin.cpp +++ b/WebCore/platform/graphics/win/FontWin.cpp @@ -30,13 +30,17 @@ #include "GlyphBuffer.h" #include "GraphicsContext.h" #include "IntRect.h" -#include "NotImplemented.h" #include "SimpleFontData.h" #include "UniscribeController.h" #include <wtf/MathExtras.h> namespace WebCore { +bool Font::canReturnFallbackFontsForComplexText() +{ + return true; +} + FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int from, int to) const { @@ -85,9 +89,9 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F drawGlyphBuffer(context, glyphBuffer, run, startPoint); } -float Font::floatWidthForComplexText(const TextRun& run) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const { - UniscribeController controller(this, run); + UniscribeController controller(this, run, fallbackFonts); controller.advance(run.length()); return controller.runWidthSoFar(); } diff --git a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp index da5b503..917631b 100644 --- a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp +++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp @@ -27,7 +27,6 @@ #include "GraphicsContext.h" #include "TransformationMatrix.h" -#include "NotImplemented.h" #include "Path.h" #include <CoreGraphics/CGBitmapContext.h> diff --git a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp index 1980d18..ca3cb5d 100644 --- a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp +++ b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp @@ -27,7 +27,6 @@ #include "GraphicsContext.h" #include "TransformationMatrix.h" -#include "NotImplemented.h" #include "Path.h" #include <cairo-win32.h> @@ -37,13 +36,61 @@ using namespace std; namespace WebCore { +static cairo_t* createCairoContextWithHDC(HDC hdc, bool hasAlpha) +{ + // Put the HDC In advanced mode so it will honor affine transforms. + SetGraphicsMode(hdc, GM_ADVANCED); + + HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)); + + BITMAP info; + GetObject(bitmap, sizeof(info), &info); + ASSERT(info.bmBitsPixel == 32); + + cairo_surface_t* image = cairo_image_surface_create_for_data((unsigned char*)info.bmBits, + CAIRO_FORMAT_ARGB32, + info.bmWidth, + info.bmHeight, + info.bmWidthBytes); + + cairo_t* context = cairo_create(image); + cairo_surface_destroy(image); + + return context; +} + +static BITMAPINFO bitmapInfoForSize(const IntSize& size) +{ + BITMAPINFO bitmapInfo; + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = size.width(); + bitmapInfo.bmiHeader.biHeight = size.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; + + return bitmapInfo; +} + +static void fillWithClearColor(HBITMAP bitmap) +{ + BITMAP bmpInfo; + GetObject(bitmap, sizeof(bmpInfo), &bmpInfo); + int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight; + memset(bmpInfo.bmBits, 0, bufferSize); +} + GraphicsContext::GraphicsContext(HDC dc, bool hasAlpha) : m_common(createGraphicsContextPrivate()) , m_data(new GraphicsContextPlatformPrivate) { if (dc) { - cairo_surface_t* surface = cairo_win32_surface_create(dc); - m_data->cr = cairo_create(surface); + m_data->cr = createCairoContextWithHDC(dc, hasAlpha); m_data->m_hdc = dc; } else { setPaintingDisabled(true); @@ -60,52 +107,95 @@ GraphicsContext::GraphicsContext(HDC dc, bool hasAlpha) HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) { - // FIXME: We aren't really doing anything with the 'mayCreateBitmap' flag. This needs - // to be addressed. - if (dstRect.isEmpty()) - return 0; - - // This is probably wrong, and definitely out of date. Pulled from old SVN - cairo_surface_t* surface = cairo_get_target(platformContext()); - HDC hdc = cairo_win32_surface_get_dc(surface); - SaveDC(hdc); - - // FIXME: We need to make sure a clip is really set on the HDC. - // Call SetWorldTransform to honor the current Cairo transform. - SetGraphicsMode(hdc, GM_ADVANCED); // We need this call for themes to honor world transforms. - cairo_matrix_t mat; - cairo_get_matrix(platformContext(), &mat); - XFORM xform; - xform.eM11 = mat.xx; - xform.eM12 = mat.xy; - xform.eM21 = mat.yx; - xform.eM22 = mat.yy; - xform.eDx = mat.x0; - xform.eDy = mat.y0; - ::SetWorldTransform(hdc, &xform); - - return hdc; + // FIXME: Should a bitmap be created also when a shadow is set? + if (mayCreateBitmap && inTransparencyLayer()) { + if (dstRect.isEmpty()) + return 0; + + // Create a bitmap DC in which to draw. + BITMAPINFO bitmapInfo = bitmapInfoForSize(dstRect.size()); + + void* pixels = 0; + HBITMAP bitmap = ::CreateDIBSection(NULL, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0); + if (!bitmap) + return 0; + + HDC bitmapDC = ::CreateCompatibleDC(m_data->m_hdc); + ::SelectObject(bitmapDC, bitmap); + + // Fill our buffer with clear if we're going to alpha blend. + if (supportAlphaBlend) + fillWithClearColor(bitmap); + + // Make sure we can do world transforms. + SetGraphicsMode(bitmapDC, GM_ADVANCED); + + // Apply a translation to our context so that the drawing done will be at (0,0) of the bitmap. + XFORM xform; + xform.eM11 = 1.0f; + xform.eM12 = 0.0f; + xform.eM21 = 0.0f; + xform.eM22 = 1.0f; + xform.eDx = -dstRect.x(); + xform.eDy = -dstRect.y(); + ::SetWorldTransform(bitmapDC, &xform); + + return bitmapDC; + } + + cairo_surface_t* surface = cairo_win32_surface_create(m_data->m_hdc); + cairo_surface_flush(surface); + cairo_surface_destroy(surface); + + m_data->save(); + + return m_data->m_hdc; } void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) { - // FIXME: We aren't really doing anything with the 'mayCreateBitmap' flag. This needs - // to be addressed. - if (dstRect.isEmpty()) - return; + if (!mayCreateBitmap || !hdc || !inTransparencyLayer()) { + m_data->restore(); + return; + } - cairo_surface_t* surface = cairo_get_target(platformContext()); - HDC hdc2 = cairo_win32_surface_get_dc(surface); - RestoreDC(hdc2, -1); - cairo_surface_mark_dirty(surface); + if (dstRect.isEmpty()) + return; + + HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)); + + BITMAP info; + GetObject(bitmap, sizeof(info), &info); + ASSERT(info.bmBitsPixel == 32); + + // Need to make a cairo_surface_t out of the bitmap's pixel buffer and then draw + // it into our context. + cairo_surface_t* image = cairo_image_surface_create_for_data((unsigned char*)info.bmBits, + CAIRO_FORMAT_ARGB32, + info.bmWidth, + info.bmHeight, + info.bmWidthBytes); + + // Scale the target surface to the new image size, and flip it + // so that when we set the srcImage as the surface it will draw + // right-side-up. + cairo_translate(m_data->cr, 0, dstRect.height()); + cairo_scale(m_data->cr, dstRect.width(), -dstRect.height()); + cairo_set_source_surface (m_data->cr, image, dstRect.x(), dstRect.y()); + + if (m_data->layers.size()) + cairo_paint_with_alpha(m_data->cr, m_data->layers.last()); + else + cairo_paint(m_data->cr); + + // Delete all our junk. + cairo_surface_destroy(image); + ::DeleteDC(hdc); + ::DeleteObject(bitmap); } void GraphicsContextPlatformPrivate::concatCTM(const TransformationMatrix& transform) { - cairo_surface_t* surface = cairo_get_target(cr); - HDC hdc = cairo_win32_surface_get_dc(surface); - SaveDC(hdc); - const cairo_matrix_t* matrix = reinterpret_cast<const cairo_matrix_t*>(&transform); XFORM xform; @@ -116,7 +206,15 @@ void GraphicsContextPlatformPrivate::concatCTM(const TransformationMatrix& trans xform.eDx = matrix->x0; xform.eDy = matrix->y0; - ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); + ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY); +} + +void GraphicsContextPlatformPrivate::syncContext(PlatformGraphicsContext* cr) +{ + cairo_surface_t* surface = cairo_get_target(cr); + m_hdc = cairo_win32_surface_get_dc(surface); + + SetGraphicsMode(m_hdc, GM_ADVANCED); // We need this call for themes to honor world transforms. } } diff --git a/WebCore/platform/graphics/win/ImageCairoWin.cpp b/WebCore/platform/graphics/win/ImageCairoWin.cpp index 95bb7bc..06428b8 100644 --- a/WebCore/platform/graphics/win/ImageCairoWin.cpp +++ b/WebCore/platform/graphics/win/ImageCairoWin.cpp @@ -47,13 +47,17 @@ bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) memset(bmpInfo.bmBits, 255, bufferSize); } - HDC tempDC = CreateCompatibleDC(0); - if (!tempDC) { - LOG_ERROR("Failed to create in-memory DC for Image::blit()"); - return false; - } - SelectObject(tempDC, bmp); - GraphicsContext gc(tempDC); + cairo_surface_t* image = cairo_image_surface_create_for_data((unsigned char*)bmpInfo.bmBits, + CAIRO_FORMAT_ARGB32, + bmpInfo.bmWidth, + bmpInfo.bmHeight, + bmpInfo.bmWidthBytes); + + + cairo_t* targetRef = cairo_create(image); + cairo_surface_destroy(image); + + GraphicsContext gc(targetRef); IntSize imageSize = BitmapImage::size(); if (size) @@ -62,7 +66,7 @@ bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), CompositeCopy); // Do cleanup - DeleteDC(tempDC); + cairo_destroy(targetRef); return true; } diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp index c293f49..35ea786 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp @@ -70,6 +70,8 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) , m_networkState(MediaPlayer::Empty) , m_readyState(MediaPlayer::HaveNothing) , m_enabledTrackCount(0) + , m_totalTrackCount(0) + , m_hasUnsupportedTracks(false) , m_startedPlaying(false) , m_isStreaming(false) #if DRAW_FRAME_RATE @@ -320,9 +322,17 @@ void MediaPlayerPrivate::updateStates() long loadState = m_qtMovie ? m_qtMovie->loadState() : QTMovieLoadStateError; - if (loadState >= QTMovieLoadStateLoaded && m_readyState < MediaPlayer::HaveMetadata && !m_player->inMediaDocument()) { - m_qtMovie->disableUnsupportedTracks(m_enabledTrackCount); - if (!m_enabledTrackCount) + if (loadState >= QTMovieLoadStateLoaded && m_readyState < MediaPlayer::HaveMetadata) { + m_qtMovie->disableUnsupportedTracks(m_enabledTrackCount, m_totalTrackCount); + if (m_player->inMediaDocument()) { + if (!m_enabledTrackCount || m_enabledTrackCount != m_totalTrackCount) { + // This is a type of media that we do not handle directly with a <video> + // element, eg. QuickTime VR, a movie with a sprite track, etc. Tell the + // MediaPlayerClient that we won't support it. + sawUnsupportedTracks(); + return; + } + } else if (!m_enabledTrackCount) loadState = QTMovieLoadStateError; } @@ -341,6 +351,14 @@ void MediaPlayerPrivate::updateStates() m_networkState = MediaPlayer::Loading; m_readyState = MediaPlayer::HaveNothing; } else { + if (m_player->inMediaDocument()) { + // Something went wrong in the loading of media within a standalone file. + // This can occur with chained ref movies that eventually resolve to a + // file we don't support. + sawUnsupportedTracks(); + return; + } + float loaded = maxTimeLoaded(); if (!loaded) m_readyState = MediaPlayer::HaveNothing; @@ -365,9 +383,18 @@ void MediaPlayerPrivate::updateStates() m_player->readyStateChanged(); } +void MediaPlayerPrivate::sawUnsupportedTracks() +{ + m_qtMovie->setDisabled(true); + m_hasUnsupportedTracks = true; + m_player->mediaPlayerClient()->mediaPlayerSawUnsupportedTracks(m_player); +} void MediaPlayerPrivate::didEnd() { + if (m_hasUnsupportedTracks) + return; + m_startedPlaying = false; #if DRAW_FRAME_RATE m_timeStoppedPlaying = GetTickCount(); @@ -378,20 +405,21 @@ void MediaPlayerPrivate::didEnd() void MediaPlayerPrivate::setSize(const IntSize& size) { - if (m_qtMovie) - m_qtMovie->setSize(size.width(), size.height()); + if (m_hasUnsupportedTracks || !m_qtMovie) + return; + m_qtMovie->setSize(size.width(), size.height()); } void MediaPlayerPrivate::setVisible(bool b) { - if (!m_qtMovie) + if (m_hasUnsupportedTracks || !m_qtMovie) return; m_qtMovie->setVisible(b); } void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r) { - if (p->paintingDisabled() || !m_qtMovie) + if (p->paintingDisabled() || !m_qtMovie || m_hasUnsupportedTracks) return; HDC hdc = p->getWindowsContext(r); m_qtMovie->paint(hdc, r.x(), r.y()); @@ -463,18 +491,27 @@ MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, c void MediaPlayerPrivate::movieEnded(QTMovieWin* movie) { + if (m_hasUnsupportedTracks) + return; + ASSERT(m_qtMovie.get() == movie); didEnd(); } void MediaPlayerPrivate::movieLoadStateChanged(QTMovieWin* movie) { + if (m_hasUnsupportedTracks) + return; + ASSERT(m_qtMovie.get() == movie); updateStates(); } void MediaPlayerPrivate::movieTimeChanged(QTMovieWin* movie) { + if (m_hasUnsupportedTracks) + return; + ASSERT(m_qtMovie.get() == movie); updateStates(); m_player->timeChanged(); @@ -482,6 +519,9 @@ void MediaPlayerPrivate::movieTimeChanged(QTMovieWin* movie) void MediaPlayerPrivate::movieNewImageAvailable(QTMovieWin* movie) { + if (m_hasUnsupportedTracks) + return; + ASSERT(m_qtMovie.get() == movie); #if DRAW_FRAME_RATE if (m_startedPlaying) { diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h index 63aa62b..3207867 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h @@ -98,6 +98,7 @@ private: void cancelSeek(); void seekTimerFired(Timer<MediaPlayerPrivate>*); float maxTimeLoaded() const; + void sawUnsupportedTracks(); virtual void movieEnded(QTMovieWin*); virtual void movieLoadStateChanged(QTMovieWin*); @@ -118,6 +119,8 @@ private: MediaPlayer::NetworkState m_networkState; MediaPlayer::ReadyState m_readyState; unsigned m_enabledTrackCount; + unsigned m_totalTrackCount; + bool m_hasUnsupportedTracks; bool m_startedPlaying; bool m_isStreaming; #if DRAW_FRAME_RATE diff --git a/WebCore/platform/graphics/win/QTMovieWin.cpp b/WebCore/platform/graphics/win/QTMovieWin.cpp index 3f23698..1d10006 100644 --- a/WebCore/platform/graphics/win/QTMovieWin.cpp +++ b/WebCore/platform/graphics/win/QTMovieWin.cpp @@ -91,6 +91,7 @@ public: void createGWorld(); void deleteGWorld(); void clearGWorld(); + void cacheMovieScale(); void setSize(int, int); @@ -112,6 +113,11 @@ public: int m_gWorldHeight; GWorldPtr m_savedGWorld; long m_loadError; + float m_widthScaleFactor; + float m_heightScaleFactor; +#if !ASSERT_DISABLED + bool m_scaleCached; +#endif }; QTMovieWinPrivate::QTMovieWinPrivate() @@ -133,6 +139,11 @@ QTMovieWinPrivate::QTMovieWinPrivate() , m_gWorldHeight(0) , m_savedGWorld(0) , m_loadError(0) + , m_widthScaleFactor(1) + , m_heightScaleFactor(1) +#if !ASSERT_DISABLED + , m_scaleCached(false) +#endif { } @@ -179,6 +190,26 @@ void QTMovieWinPrivate::endTask() updateTaskTimer(); } +void QTMovieWinPrivate::cacheMovieScale() +{ + Rect naturalRect; + Rect initialRect; + + GetMovieNaturalBoundsRect(m_movie, &naturalRect); + GetMovieBox(m_movie, &initialRect); + + int naturalWidth = naturalRect.right - naturalRect.left; + int naturalHeight = naturalRect.bottom - naturalRect.top; + + if (naturalWidth) + m_widthScaleFactor = (initialRect.right - initialRect.left) / naturalWidth; + if (naturalHeight) + m_heightScaleFactor = (initialRect.bottom - initialRect.top) / naturalHeight; +#if !ASSERT_DISABLED + m_scaleCached = true;; +#endif +} + void QTMovieWinPrivate::task() { ASSERT(m_tasking); @@ -192,20 +223,27 @@ void QTMovieWinPrivate::task() // GetMovieLoadState documentation says that you should not call it more often than every quarter of a second. if (systemTime() >= m_lastLoadStateCheckTime + 0.25 || m_loadError) { - // If load fails QT's load state is kMovieLoadStateComplete. + // If load fails QT's load state is QTMovieLoadStateComplete. // This is different from QTKit API and seems strange. - long loadState = m_loadError ? kMovieLoadStateError : GetMovieLoadState(m_movie); + long loadState = m_loadError ? QTMovieLoadStateError : GetMovieLoadState(m_movie); if (loadState != m_loadState) { // we only need to erase the movie gworld when the load state changes to loaded while it // is visible as the gworld is destroyed/created when visibility changes - if (loadState >= QTMovieLoadStateLoaded && m_loadState < QTMovieLoadStateLoaded && m_visible) - clearGWorld(); + if (loadState >= QTMovieLoadStateLoaded && m_loadState < QTMovieLoadStateLoaded) { + if (m_visible) + clearGWorld(); + cacheMovieScale(); + } m_loadState = loadState; - if (!m_movieController && m_loadState >= kMovieLoadStateLoaded) + if (!m_movieController && m_loadState >= QTMovieLoadStateLoaded) createMovieController(); m_client->movieLoadStateChanged(m_movieWin); + if (m_movieWin->m_disabled) { + endTask(); + return; + } } m_lastLoadStateCheckTime = systemTime(); } @@ -259,7 +297,7 @@ void QTMovieWinPrivate::registerDrawingCallback() void QTMovieWinPrivate::drawingComplete() { - if (!m_gWorld || m_loadState < kMovieLoadStateLoaded) + if (!m_gWorld || m_movieWin->m_disabled || m_loadState < QTMovieLoadStateLoaded) return; m_client->movieNewImageAvailable(m_movieWin); } @@ -284,7 +322,7 @@ void QTMovieWinPrivate::updateGWorld() void QTMovieWinPrivate::createGWorld() { ASSERT(!m_gWorld); - if (!m_movie) + if (!m_movie || m_loadState < QTMovieLoadStateLoaded) return; m_gWorldWidth = max(cGWorldMinWidth, m_width); @@ -334,8 +372,17 @@ void QTMovieWinPrivate::setSize(int width, int height) return; m_width = width; m_height = height; - if (!m_movie) + + // Do not change movie box before reaching load state loaded as we grab + // the initial size when task() sees that state for the first time, and + // we need the initial size to be able to scale movie properly. + if (!m_movie || m_loadState < QTMovieLoadStateLoaded) return; + +#if !ASSERT_DISABLED + ASSERT(m_scaleCached); +#endif + Rect bounds; bounds.top = 0; bounds.left = 0; @@ -364,6 +411,7 @@ void QTMovieWinPrivate::deleteGWorld() QTMovieWin::QTMovieWin(QTMovieWinClient* client) : m_private(new QTMovieWinPrivate()) + , m_disabled(false) { m_private->m_movieWin = this; m_private->m_client = client; @@ -478,8 +526,8 @@ void QTMovieWin::getNaturalSize(int& width, int& height) if (m_private->m_movie) GetMovieNaturalBoundsRect(m_private->m_movie, &rect); - width = rect.right; - height = rect.bottom; + width = (rect.right - rect.left) * m_private->m_widthScaleFactor; + height = (rect.bottom - rect.top) * m_private->m_heightScaleFactor; } void QTMovieWin::setSize(int width, int height) @@ -593,6 +641,7 @@ void QTMovieWin::load(const UChar* url, int len) movieProps[moviePropCount].propStatus = 0; moviePropCount++; + ASSERT(moviePropCount <= sizeof(movieProps)/sizeof(movieProps[0])); m_private->m_loadError = NewMovieFromProperties(moviePropCount, movieProps, 0, NULL, &m_private->m_movie); CFRelease(urlRef); @@ -601,15 +650,24 @@ end: // get the load fail callback quickly if (m_private->m_loadError) updateTaskTimer(0); - else + else { + OSType mode = kQTApertureMode_CleanAperture; + + // Set the aperture mode property on a movie to signal that we want aspect ratio + // and clean aperture dimensions. Don't worry about errors, we can't do anything if + // the installed version of QT doesn't support it and it isn't serious enough to + // warrant failing. + QTSetMovieProperty(m_private->m_movie, kQTPropertyClass_Visual, kQTVisualPropertyID_ApertureMode, sizeof(mode), &mode); m_private->registerDrawingCallback(); + } CFRelease(urlStringRef); } -void QTMovieWin::disableUnsupportedTracks(unsigned& enabledTrackCount) +void QTMovieWin::disableUnsupportedTracks(unsigned& enabledTrackCount, unsigned& totalTrackCount) { if (!m_private->m_movie) { + totalTrackCount = 0; enabledTrackCount = 0; return; } @@ -623,11 +681,16 @@ void QTMovieWin::disableUnsupportedTracks(unsigned& enabledTrackCount) 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(TimeCodeMediaType); + allowedTrackTypes->add(TimeCode64MediaType); } long trackCount = GetMovieTrackCount(m_private->m_movie); enabledTrackCount = trackCount; - + totalTrackCount = trackCount; + // Track indexes are 1-based. yuck. These things must descend from old- // school mac resources or something. for (long trackIndex = 1; trackIndex <= trackCount; trackIndex++) { @@ -716,6 +779,11 @@ void QTMovieWin::disableUnsupportedTracks(unsigned& enabledTrackCount) } } +void QTMovieWin::setDisabled(bool b) +{ + m_disabled = b; +} + bool QTMovieWin::hasVideo() const { diff --git a/WebCore/platform/graphics/win/QTMovieWin.h b/WebCore/platform/graphics/win/QTMovieWin.h index 2186974..70cbef5 100644 --- a/WebCore/platform/graphics/win/QTMovieWin.h +++ b/WebCore/platform/graphics/win/QTMovieWin.h @@ -84,7 +84,8 @@ public: void setVisible(bool); void paint(HDC, int x, int y); - void disableUnsupportedTracks(unsigned& enabledTrackCount); + void disableUnsupportedTracks(unsigned& enabledTrackCount, unsigned& totalTrackCount); + void setDisabled(bool); bool hasVideo() const; @@ -93,6 +94,7 @@ public: private: QTMovieWinPrivate* m_private; + bool m_disabled; friend class QTMovieWinPrivate; }; diff --git a/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp index 8b5ab87..aaa089a 100644 --- a/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp +++ b/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp @@ -52,27 +52,27 @@ static inline float scaleEmToUnits(float x, unsigned unitsPerEm) { return unitsP void SimpleFontData::platformInit() { - m_syntheticBoldOffset = m_font.syntheticBold() ? 1.0f : 0.f; + m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f; m_scriptCache = 0; m_scriptFontProperties = 0; m_isSystemFont = false; - if (m_font.useGDI()) + if (m_platformData.useGDI()) return initGDIFont(); - CGFontRef font = m_font.cgFont(); + CGFontRef font = m_platformData.cgFont(); int iAscent = CGFontGetAscent(font); int iDescent = CGFontGetDescent(font); int iLineGap = CGFontGetLeading(font); m_unitsPerEm = CGFontGetUnitsPerEm(font); - float pointSize = m_font.size(); + float pointSize = m_platformData.size(); float fAscent = scaleEmToUnits(iAscent, m_unitsPerEm) * pointSize; float fDescent = -scaleEmToUnits(iDescent, m_unitsPerEm) * pointSize; float fLineGap = scaleEmToUnits(iLineGap, m_unitsPerEm) * pointSize; if (!isCustomFont()) { HDC dc = GetDC(0); - HGDIOBJ oldFont = SelectObject(dc, m_font.hfont()); + HGDIOBJ oldFont = SelectObject(dc, m_platformData.hfont()); int faceLength = GetTextFace(dc, 0, 0); Vector<TCHAR> faceName(faceLength); GetTextFace(dc, faceLength, faceName.data()); @@ -116,6 +116,16 @@ void SimpleFontData::platformInit() } } +void SimpleFontData::platformCharWidthInit() +{ + // GDI Fonts init charwidths in initGDIFont. + if (!m_platformData.useGDI()) { + m_avgCharWidth = 0.f; + m_maxCharWidth = 0.f; + initCharWidths(); + } +} + void SimpleFontData::platformDestroy() { platformCommonDestroy(); @@ -123,11 +133,11 @@ void SimpleFontData::platformDestroy() float SimpleFontData::platformWidthForGlyph(Glyph glyph) const { - if (m_font.useGDI()) + if (m_platformData.useGDI()) return widthForGDIGlyph(glyph); - CGFontRef font = m_font.cgFont(); - float pointSize = m_font.size(); + CGFontRef font = m_platformData.cgFont(); + float pointSize = m_platformData.size(); CGSize advance; CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSize); diff --git a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp index 07d5305..2e51621 100644 --- a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp +++ b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp @@ -35,7 +35,6 @@ #include "FontCache.h" #include "FontDescription.h" #include "MathExtras.h" -#include "NotImplemented.h" #include <cairo.h> #include <cairo-win32.h> #include <mlang.h> @@ -50,14 +49,16 @@ void SimpleFontData::platformInit() m_isSystemFont = false; m_syntheticBoldOffset = 0; - if (m_font.useGDI()) + m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f; + + if (m_platformData.useGDI()) return initGDIFont(); HDC hdc = GetDC(0); SaveDC(hdc); - cairo_scaled_font_t* scaledFont = m_font.scaledFont(); - const double metricsMultiplier = cairo_win32_scaled_font_get_metrics_factor(scaledFont) * m_font.size(); + cairo_scaled_font_t* scaledFont = m_platformData.scaledFont(); + const double metricsMultiplier = cairo_win32_scaled_font_get_metrics_factor(scaledFont) * m_platformData.size(); cairo_win32_scaled_font_select_font(scaledFont, hdc); @@ -68,6 +69,8 @@ void SimpleFontData::platformInit() m_xHeight = m_ascent * 0.56f; // Best guess for xHeight for non-Truetype fonts. m_lineGap = lroundf(textMetrics.tmExternalLeading * metricsMultiplier); m_lineSpacing = m_ascent + m_descent + m_lineGap; + m_avgCharWidth = lroundf(textMetrics.tmAveCharWidth * metricsMultiplier); + m_maxCharWidth = lroundf(textMetrics.tmMaxCharWidth * metricsMultiplier); OUTLINETEXTMETRIC metrics; if (GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics) > 0) { @@ -89,25 +92,30 @@ void SimpleFontData::platformInit() ReleaseDC(0, hdc); } +void SimpleFontData::platformCharWidthInit() +{ + // charwidths are set in platformInit. +} + void SimpleFontData::platformDestroy() { - cairo_font_face_destroy(m_font.fontFace()); - cairo_scaled_font_destroy(m_font.scaledFont()); + cairo_font_face_destroy(m_platformData.fontFace()); + cairo_scaled_font_destroy(m_platformData.scaledFont()); - DeleteObject(m_font.hfont()); + DeleteObject(m_platformData.hfont()); platformCommonDestroy(); } float SimpleFontData::platformWidthForGlyph(Glyph glyph) const { - if (m_font.useGDI()) + if (m_platformData.useGDI()) return widthForGDIGlyph(glyph); HDC hdc = GetDC(0); SaveDC(hdc); - cairo_scaled_font_t* scaledFont = m_font.scaledFont(); + cairo_scaled_font_t* scaledFont = m_platformData.scaledFont(); cairo_win32_scaled_font_select_font(scaledFont, hdc); int width; @@ -118,14 +126,14 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const RestoreDC(hdc, -1); ReleaseDC(0, hdc); - const double metricsMultiplier = cairo_win32_scaled_font_get_metrics_factor(scaledFont) * m_font.size(); + const double metricsMultiplier = cairo_win32_scaled_font_get_metrics_factor(scaledFont) * m_platformData.size(); return width * metricsMultiplier; } void SimpleFontData::setFont(cairo_t* cr) const { ASSERT(cr); - m_font.setFont(cr); + m_platformData.setFont(cr); } } diff --git a/WebCore/platform/graphics/win/SimpleFontDataWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp index 9d5c3b9..9835e9f 100644 --- a/WebCore/platform/graphics/win/SimpleFontDataWin.cpp +++ b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp @@ -63,7 +63,7 @@ bool SimpleFontData::shouldApplyMacAscentHack() void SimpleFontData::initGDIFont() { HDC hdc = GetDC(0); - HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont()); + HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont()); OUTLINETEXTMETRIC metrics; GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics); TEXTMETRIC& textMetrics = metrics.otmTextMetrics; @@ -71,6 +71,8 @@ void SimpleFontData::initGDIFont() m_descent = textMetrics.tmDescent; m_lineGap = textMetrics.tmExternalLeading; m_lineSpacing = m_ascent + m_descent + m_lineGap; + m_avgCharWidth = textMetrics.tmAveCharWidth; + m_maxCharWidth = textMetrics.tmMaxCharWidth; m_xHeight = m_ascent * 0.56f; // Best guess for xHeight if no x glyph is present. GLYPHMETRICS gm; @@ -100,17 +102,17 @@ void SimpleFontData::platformCommonDestroy() SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const { if (!m_smallCapsFontData) { - float smallCapsHeight = cSmallCapsFontSizeMultiplier * m_font.size(); + float smallCapsHeight = cSmallCapsFontSizeMultiplier * m_platformData.size(); if (isCustomFont()) { - FontPlatformData smallCapsFontData(m_font); + FontPlatformData smallCapsFontData(m_platformData); smallCapsFontData.setSize(smallCapsHeight); m_smallCapsFontData = new SimpleFontData(smallCapsFontData, true, false); } else { LOGFONT winfont; - GetObject(m_font.hfont(), sizeof(LOGFONT), &winfont); - winfont.lfHeight = -lroundf(smallCapsHeight * (m_font.useGDI() ? 1 : 32)); + GetObject(m_platformData.hfont(), sizeof(LOGFONT), &winfont); + winfont.lfHeight = -lroundf(smallCapsHeight * (m_platformData.useGDI() ? 1 : 32)); HFONT hfont = CreateFontIndirect(&winfont); - m_smallCapsFontData = new SimpleFontData(FontPlatformData(hfont, smallCapsHeight, m_font.syntheticBold(), m_font.syntheticOblique(), m_font.useGDI())); + m_smallCapsFontData = new SimpleFontData(FontPlatformData(hfont, smallCapsHeight, m_platformData.syntheticBold(), m_platformData.syntheticOblique(), m_platformData.useGDI())); } } return m_smallCapsFontData; @@ -135,7 +137,7 @@ bool SimpleFontData::containsCharacters(const UChar* characters, int length) con langFontLink->CodePageToCodePages(CP_ACP, &acpCodePages); DWORD fontCodePages; - langFontLink->GetFontCodePages(dc, m_font.hfont(), &fontCodePages); + langFontLink->GetFontCodePages(dc, m_platformData.hfont(), &fontCodePages); DWORD actualCodePages; long numCharactersProcessed; @@ -162,7 +164,7 @@ void SimpleFontData::determinePitch() // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that. HDC dc = GetDC(0); SaveDC(dc); - SelectObject(dc, m_font.hfont()); + SelectObject(dc, m_platformData.hfont()); // Yes, this looks backwards, but the fixed pitch bit is actually set if the font // is *not* fixed pitch. Unbelievable but true. @@ -178,7 +180,7 @@ float SimpleFontData::widthForGDIGlyph(Glyph glyph) const { HDC hdc = GetDC(0); SetGraphicsMode(hdc, GM_ADVANCED); - HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont()); + HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont()); int width; GetCharWidthI(hdc, glyph, 1, 0, &width); SelectObject(hdc, oldFont); @@ -196,7 +198,7 @@ SCRIPT_FONTPROPERTIES* SimpleFontData::scriptFontProperties() const if (result == E_PENDING) { HDC dc = GetDC(0); SaveDC(dc); - SelectObject(dc, m_font.hfont()); + SelectObject(dc, m_platformData.hfont()); ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties); RestoreDC(dc, -1); ReleaseDC(0, dc); diff --git a/WebCore/platform/graphics/win/UniscribeController.cpp b/WebCore/platform/graphics/win/UniscribeController.cpp index 371bc51..f382857 100644 --- a/WebCore/platform/graphics/win/UniscribeController.cpp +++ b/WebCore/platform/graphics/win/UniscribeController.cpp @@ -38,9 +38,10 @@ namespace WebCore { // that does stuff in that method instead of doing everything in the constructor. Have advance() // take the GlyphBuffer as an arg so that we don't have to populate the glyph buffer when // measuring. -UniscribeController::UniscribeController(const Font* font, const TextRun& run) +UniscribeController::UniscribeController(const Font* font, const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) : m_font(*font) , m_run(run) +, m_fallbackFonts(fallbackFonts) , m_end(run.length()) , m_currentCharacter(0) , m_runWidthSoFar(0) @@ -147,6 +148,9 @@ void UniscribeController::advance(unsigned offset, GlyphBuffer* glyphBuffer) smallCapsBuffer[index] = forceSmallCaps ? c : newC; } + if (m_fallbackFonts && nextFontData != fontData && fontData != m_font.primaryFont()) + m_fallbackFonts->add(fontData); + if (nextFontData != fontData || nextIsSmallCaps != isSmallCaps) { int itemStart = m_run.rtl() ? index + 1 : indexOfFontTransition; int itemLength = m_run.rtl() ? indexOfFontTransition - index : index - indexOfFontTransition; @@ -158,6 +162,9 @@ void UniscribeController::advance(unsigned offset, GlyphBuffer* glyphBuffer) int itemLength = m_run.rtl() ? indexOfFontTransition + 1 : length - indexOfFontTransition; if (itemLength) { + if (m_fallbackFonts && nextFontData != m_font.primaryFont()) + m_fallbackFonts->add(nextFontData); + int itemStart = m_run.rtl() ? 0 : indexOfFontTransition; m_currentCharacter = baseCharacter + itemStart; itemizeShapeAndPlace((nextIsSmallCaps ? smallCapsBuffer.data() : cp) + itemStart, itemLength, nextFontData, glyphBuffer); @@ -258,16 +265,16 @@ bool UniscribeController::shapeAndPlaceItem(const UChar* cp, unsigned i, const S Vector<int> roundingHackWordBoundaries(glyphs.size()); roundingHackWordBoundaries.fill(-1); - const float cLogicalScale = fontData->m_font.useGDI() ? 1.0f : 32.0f; - unsigned logicalSpaceWidth = fontData->m_spaceWidth * cLogicalScale; - float roundedSpaceWidth = roundf(fontData->m_spaceWidth); + const float cLogicalScale = fontData->platformData().useGDI() ? 1.0f : 32.0f; + unsigned logicalSpaceWidth = fontData->spaceWidth() * cLogicalScale; + float roundedSpaceWidth = roundf(fontData->spaceWidth()); for (int k = 0; k < len; k++) { UChar ch = *(str + k); if (Font::treatAsSpace(ch)) { // Substitute in the space glyph at the appropriate place in the glyphs // array. - glyphs[clusters[k]] = fontData->m_spaceGlyph; + glyphs[clusters[k]] = fontData->spaceGlyph(); advances[clusters[k]] = logicalSpaceWidth; spaceCharacters[clusters[k]] = m_currentCharacter + k + item.iCharPos; } @@ -300,15 +307,15 @@ bool UniscribeController::shapeAndPlaceItem(const UChar* cp, unsigned i, const S offsetY = roundf(offsetY); } - advance += fontData->m_syntheticBoldOffset; + advance += fontData->syntheticBoldOffset(); // We special case spaces in two ways when applying word rounding. // First, we round spaces to an adjusted width in all fonts. // Second, in fixed-pitch fonts we ensure that all glyphs that // match the width of the space glyph have the same width as the space glyph. - if (roundedAdvance == roundedSpaceWidth && (fontData->m_treatAsFixedPitch || glyph == fontData->m_spaceGlyph) && + if (roundedAdvance == roundedSpaceWidth && (fontData->pitch() == FixedPitch || glyph == fontData->spaceGlyph()) && m_run.applyWordRounding()) - advance = fontData->m_adjustedSpaceWidth; + advance = fontData->adjustedSpaceWidth(); if (hasExtraSpacing) { // If we're a glyph with an advance, go ahead and add in letter-spacing. @@ -317,7 +324,7 @@ bool UniscribeController::shapeAndPlaceItem(const UChar* cp, unsigned i, const S advance += m_font.letterSpacing(); // Handle justification and word-spacing. - if (glyph == fontData->m_spaceGlyph) { + if (glyph == fontData->spaceGlyph()) { // Account for padding. WebCore uses space padding to justify text. // We distribute the specified padding over the available spaces in the run. if (m_padding) { diff --git a/WebCore/platform/graphics/win/UniscribeController.h b/WebCore/platform/graphics/win/UniscribeController.h index 6ea45e1..23b8108 100644 --- a/WebCore/platform/graphics/win/UniscribeController.h +++ b/WebCore/platform/graphics/win/UniscribeController.h @@ -38,7 +38,7 @@ namespace WebCore { class UniscribeController { public: - UniscribeController(const Font*, const TextRun&); + UniscribeController(const Font*, const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0); // Advance and measure/place up to the specified character. void advance(unsigned to, GlyphBuffer* = 0); @@ -60,6 +60,7 @@ private: const Font& m_font; const TextRun& m_run; + HashSet<const SimpleFontData*>* m_fallbackFonts; SCRIPT_CONTROL m_control; SCRIPT_STATE m_state; diff --git a/WebCore/platform/graphics/wx/FontWx.cpp b/WebCore/platform/graphics/wx/FontWx.cpp index 07223e9..04b2ec4 100644 --- a/WebCore/platform/graphics/wx/FontWx.cpp +++ b/WebCore/platform/graphics/wx/FontWx.cpp @@ -39,6 +39,11 @@ namespace WebCore { +bool Font::canReturnFallbackFontsForComplexText() +{ + return false; +} + void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { @@ -63,7 +68,7 @@ void Font::drawComplexText(GraphicsContext* graphicsContext, const TextRun& run, notImplemented(); } -float Font::floatWidthForComplexText(const TextRun& run) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */) const { notImplemented(); return 0; diff --git a/WebCore/platform/graphics/wx/ImageSourceWx.cpp b/WebCore/platform/graphics/wx/ImageSourceWx.cpp index fc8ce71..2f71d62 100644 --- a/WebCore/platform/graphics/wx/ImageSourceWx.cpp +++ b/WebCore/platform/graphics/wx/ImageSourceWx.cpp @@ -37,6 +37,9 @@ #include <wx/defs.h> #include <wx/bitmap.h> +#if USE(WXGC) +#include <wx/graphics.h> +#endif #include <wx/image.h> #include <wx/rawbmp.h> @@ -224,7 +227,14 @@ NativeImagePtr ImageSource::createFrameAtIndex(size_t index) bmp->UseAlpha(); #endif ASSERT(bmp->IsOk()); + +#if USE(WXGC) + wxGraphicsBitmap* bitmap = new wxGraphicsBitmap(wxGraphicsRenderer::GetDefaultRenderer()->CreateBitmap(*bmp)); + delete bmp; + return bitmap; +#else return bmp; +#endif } float ImageSource::frameDurationAtIndex(size_t index) diff --git a/WebCore/platform/graphics/wx/ImageWx.cpp b/WebCore/platform/graphics/wx/ImageWx.cpp index e1d435e..b0a993e 100644 --- a/WebCore/platform/graphics/wx/ImageWx.cpp +++ b/WebCore/platform/graphics/wx/ImageWx.cpp @@ -26,11 +26,12 @@ #include "config.h" #include "Image.h" -#include "TransformationMatrix.h" #include "BitmapImage.h" +#include "FloatConversion.h" #include "FloatRect.h" #include "GraphicsContext.h" -#include "NotImplemented.h" +#include "ImageObserver.h" +#include "TransformationMatrix.h" #include <math.h> #include <stdio.h> @@ -98,13 +99,13 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR #if USE(WXGC) wxGCDC* context = (wxGCDC*)ctxt->platformContext(); wxGraphicsContext* gc = context->GetGraphicsContext(); + wxGraphicsBitmap* bitmap = frameAtIndex(m_currentFrame); #else wxWindowDC* context = ctxt->platformContext(); + wxBitmap* bitmap = frameAtIndex(m_currentFrame); #endif startAnimation(); - - wxBitmap* bitmap = frameAtIndex(m_currentFrame); if (!bitmap) // If it's too early we won't have an image yet. return; @@ -129,17 +130,15 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR adjustedDestRect.setLocation(FloatPoint(dst.x() - src.x() / scaleX, dst.y() - src.y() / scaleY)); adjustedDestRect.setSize(FloatSize(selfSize.width() / scaleX, selfSize.height() / scaleY)); } - - // If the image is only partially loaded, then shrink the destination rect that we're drawing into accordingly. - int currHeight = bitmap->GetHeight(); - if (currHeight < selfSize.height()) - adjustedDestRect.setHeight(adjustedDestRect.height() * currHeight / selfSize.height()); - gc->PushState(); gc->Clip(dst.x(), dst.y(), dst.width(), dst.height()); +#if wxCHECK_VERSION(2,9,0) gc->DrawBitmap(*bitmap, adjustedDestRect.x(), adjustedDestRect.y(), adjustedDestRect.width(), adjustedDestRect.height()); - gc->PopState(); #else + gc->DrawGraphicsBitmap(*bitmap, adjustedDestRect.x(), adjustedDestRect.y(), adjustedDestRect.width(), adjustedDestRect.height()); +#endif + +#else // USE(WXGC) IntRect srcIntRect(src); IntRect dstIntRect(dst); bool rescaling = false; @@ -172,6 +171,9 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR #endif ctxt->restore(); + + if (ImageObserver* observer = imageObserver()) + observer->didDraw(this); } void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, CompositeOperator, const FloatRect& dstRect) @@ -181,21 +183,29 @@ void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, c #if USE(WXGC) wxGCDC* context = (wxGCDC*)ctxt->platformContext(); + wxGraphicsBitmap* bitmap = frameAtIndex(m_currentFrame); #else wxWindowDC* context = ctxt->platformContext(); + wxBitmap* bitmap = frameAtIndex(m_currentFrame); #endif - ctxt->save(); - ctxt->clip(IntRect(dstRect.x(), dstRect.y(), dstRect.width(), dstRect.height())); - wxBitmap* bitmap = frameAtIndex(m_currentFrame); if (!bitmap) // If it's too early we won't have an image yet. return; + + ctxt->save(); + ctxt->clip(IntRect(dstRect.x(), dstRect.y(), dstRect.width(), dstRect.height())); float currentW = 0; float currentH = 0; #if USE(WXGC) wxGraphicsContext* gc = context->GetGraphicsContext(); + + float adjustedX = phase.x() + srcRect.x() * + narrowPrecisionToFloat(patternTransform.a()); + float adjustedY = phase.y() + srcRect.y() * + narrowPrecisionToFloat(patternTransform.d()); + gc->ConcatTransform(patternTransform); #else wxMemoryDC mydc; @@ -208,7 +218,11 @@ void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, c while ( currentW < dstRect.width() && currentW < clientSize.x - origin.x ) { while ( currentH < dstRect.height() && currentH < clientSize.y - origin.y) { #if USE(WXGC) - gc->DrawBitmap(*bitmap, (wxDouble)dstRect.x() + currentW, (wxDouble)dstRect.y() + currentH, (wxDouble)srcRect.width(), (wxDouble)srcRect.height()); +#if wxCHECK_VERSION(2,9,0) + gc->DrawBitmap(*bitmap, adjustedX + currentW, adjustedY + currentH, (wxDouble)srcRect.width(), (wxDouble)srcRect.height()); +#else + gc->DrawGraphicsBitmap(*bitmap, adjustedX + currentW, adjustedY + currentH, (wxDouble)srcRect.width(), (wxDouble)srcRect.height()); +#endif #else context->Blit((wxCoord)dstRect.x() + currentW, (wxCoord)dstRect.y() + currentH, (wxCoord)srcRect.width(), (wxCoord)srcRect.height(), &mydc, @@ -233,6 +247,8 @@ void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, c startAnimation(); + if (ImageObserver* observer = imageObserver()) + observer->didDraw(this); } void BitmapImage::checkForSolidColor() diff --git a/WebCore/platform/graphics/wx/PathWx.cpp b/WebCore/platform/graphics/wx/PathWx.cpp index 60c71d5..04a952d 100644 --- a/WebCore/platform/graphics/wx/PathWx.cpp +++ b/WebCore/platform/graphics/wx/PathWx.cpp @@ -66,11 +66,12 @@ Path::Path() Path::~Path() { + clear(); } Path::Path(const Path& path) { - m_path = (PlatformPath*)&path.m_path; + m_path = new wxGraphicsPath(*path.m_path); } bool Path::contains(const FloatPoint& point, const WindRule rule) const @@ -89,7 +90,7 @@ bool Path::contains(const FloatPoint& point, const WindRule rule) const void Path::translate(const FloatSize&) { - notImplemented(); + notImplemented(); } FloatRect Path::boundingRect() const diff --git a/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp b/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp index ab50518..2368f83 100644 --- a/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp +++ b/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp @@ -45,7 +45,7 @@ namespace WebCore void SimpleFontData::platformInit() { - wxFont *font = m_font.font(); + wxFont *font = m_platformData.font(); if (font && font->IsOk()) { wxFontProperties props = wxFontProperties(font); m_ascent = props.GetAscent(); @@ -57,6 +57,13 @@ void SimpleFontData::platformInit() } } +void SimpleFontData::platformCharWidthInit() +{ + m_avgCharWidth = 0.f; + m_maxCharWidth = 0.f; + initCharWidths(); +} + void SimpleFontData::platformDestroy() { delete m_smallCapsFontData; @@ -81,8 +88,8 @@ bool SimpleFontData::containsCharacters(const UChar* characters, int length) con void SimpleFontData::determinePitch() { - if (m_font.font() && m_font.font()->Ok()) - m_treatAsFixedPitch = m_font.font()->IsFixedWidth(); + if (m_platformData.font() && m_platformData.font()->Ok()) + m_treatAsFixedPitch = m_platformData.font()->IsFixedWidth(); else m_treatAsFixedPitch = false; } @@ -91,7 +98,7 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const { // TODO: fix this! Make GetTextExtents a method of wxFont in 2.9 int width = 10; - GetTextExtent(*m_font.font(), (wxChar)glyph, &width, NULL); + GetTextExtent(*m_platformData.font(), (wxChar)glyph, &width, NULL); return width; } diff --git a/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp b/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp index f21dc17..9684a3c 100644 --- a/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp +++ b/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp @@ -26,9 +26,9 @@ #include "config.h" #include "TransformationMatrix.h" +#include "Assertions.h" #include "FloatRect.h" #include "IntRect.h" -#include "NotImplemented.h" #include <stdio.h> #include <wx/defs.h> diff --git a/WebCore/platform/gtk/ContextMenuItemGtk.cpp b/WebCore/platform/gtk/ContextMenuItemGtk.cpp index cf34640..aaec206 100644 --- a/WebCore/platform/gtk/ContextMenuItemGtk.cpp +++ b/WebCore/platform/gtk/ContextMenuItemGtk.cpp @@ -56,10 +56,8 @@ static const char* gtkStockIDFromContextMenuAction(const ContextMenuAction& acti return GTK_STOCK_PASTE; case ContextMenuItemTagDelete: return GTK_STOCK_DELETE; -#if GTK_CHECK_VERSION(2, 10, 0) case ContextMenuItemTagSelectAll: return GTK_STOCK_SELECT_ALL; -#endif case ContextMenuItemTagSpellingGuess: return GTK_STOCK_INFO; case ContextMenuItemTagIgnoreSpelling: diff --git a/WebCore/platform/gtk/CursorGtk.cpp b/WebCore/platform/gtk/CursorGtk.cpp index 76f6d00..115760e 100644 --- a/WebCore/platform/gtk/CursorGtk.cpp +++ b/WebCore/platform/gtk/CursorGtk.cpp @@ -28,7 +28,6 @@ #include "config.h" #include "CursorGtk.h" -#include "NotImplemented.h" #include <wtf/Assertions.h> #include <gdk/gdk.h> @@ -63,7 +62,13 @@ Cursor::Cursor(const Cursor& other) Cursor::Cursor(Image*, const IntPoint&) { - notImplemented(); + // FIXME: We don't support images for cursors yet. + // This is just a placeholder to avoid crashes. + Cursor other(crossCursor()); + m_impl = other.m_impl; + + if (m_impl) + gdk_cursor_ref(m_impl); } Cursor::~Cursor() @@ -204,13 +209,13 @@ const Cursor& northWestSouthEastResizeCursor() const Cursor& columnResizeCursor() { - static Cursor c = gdk_cursor_new(GDK_DOUBLE_ARROW); + static Cursor c = gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW); return c; } const Cursor& rowResizeCursor() { - static Cursor c = gdk_cursor_new(GDK_DOUBLE_ARROW); + static Cursor c = gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW); return c; } @@ -268,8 +273,8 @@ const Cursor& verticalTextCursor() const Cursor& cellCursor() { - notImplemented(); - return pointerCursor(); + static Cursor c = gdk_cursor_new(GDK_PLUS); + return c; } const Cursor& contextMenuCursor() @@ -280,8 +285,8 @@ const Cursor& contextMenuCursor() const Cursor& noDropCursor() { - notImplemented(); - return pointerCursor(); + static Cursor c = customCursorNew(CustomCursorNoDrop); + return c; } const Cursor& copyCursor() @@ -292,8 +297,8 @@ const Cursor& copyCursor() const Cursor& progressCursor() { - notImplemented(); - return pointerCursor(); + static Cursor c = customCursorNew(CustomCursorProgress); + return c; } const Cursor& aliasCursor() @@ -304,14 +309,13 @@ const Cursor& aliasCursor() const Cursor& noneCursor() { - notImplemented(); - return pointerCursor(); + static Cursor c = customCursorNew(CustomCursorNone); + return c; } const Cursor& notAllowedCursor() { - notImplemented(); - return pointerCursor(); + return noDropCursor(); } const Cursor& zoomInCursor() @@ -328,14 +332,14 @@ const Cursor& zoomOutCursor() const Cursor& grabCursor() { - notImplemented(); - return pointerCursor(); + static Cursor c = customCursorNew(CustomCursorGrab); + return c; } const Cursor& grabbingCursor() { - notImplemented(); - return pointerCursor(); + static Cursor c = customCursorNew(CustomCursorGrabbing); + return c; } } diff --git a/WebCore/platform/gtk/CursorGtk.h b/WebCore/platform/gtk/CursorGtk.h index 73f05a9..85aaefa 100644 --- a/WebCore/platform/gtk/CursorGtk.h +++ b/WebCore/platform/gtk/CursorGtk.h @@ -1,23 +1,40 @@ -/* - * Copyright (C) 2001 Tim Copperfield <timecop@network.email.ne.jp> - * Copyright (C) 2007 Christian Dywan <christian@twotoasts.de> +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. * - * 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. + * The Original Code is mozilla.org code. * - * 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. + * The Initial Developer of the Original Code is + * Tim Copperfield. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. * - * 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. + * Contributor(s): + * Tim Copperfield <timecop@network.email.ne.jp> + * Christian Dywan <christian@twotoasts.de> * - */ + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ #ifndef CursorGtk_h #define CursorGtk_h @@ -191,31 +208,176 @@ static const char moz_zoom_out_mask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +/* MOZ_CURSOR_NOT_ALLOWED */ +static const char moz_not_allowed_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, + 0xf0, 0xf0, 0x00, 0x00, 0x38, 0xc0, 0x01, 0x00, 0x7c, 0x80, 0x03, 0x00, + 0xec, 0x00, 0x03, 0x00, 0xce, 0x01, 0x07, 0x00, 0x86, 0x03, 0x06, 0x00, + 0x06, 0x07, 0x06, 0x00, 0x06, 0x0e, 0x06, 0x00, 0x06, 0x1c, 0x06, 0x00, + 0x0e, 0x38, 0x07, 0x00, 0x0c, 0x70, 0x03, 0x00, 0x1c, 0xe0, 0x03, 0x00, + 0x38, 0xc0, 0x01, 0x00, 0xf0, 0xf0, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, + 0x80, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +static const char moz_not_allowed_mask_bits[] = { + 0x80, 0x1f, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, + 0xf8, 0xff, 0x01, 0x00, 0xfc, 0xf0, 0x03, 0x00, 0xfe, 0xc0, 0x07, 0x00, + 0xfe, 0x81, 0x07, 0x00, 0xff, 0x83, 0x0f, 0x00, 0xcf, 0x07, 0x0f, 0x00, + 0x8f, 0x0f, 0x0f, 0x00, 0x0f, 0x1f, 0x0f, 0x00, 0x0f, 0x3e, 0x0f, 0x00, + 0x1f, 0xfc, 0x0f, 0x00, 0x1e, 0xf8, 0x07, 0x00, 0x3e, 0xf0, 0x07, 0x00, + 0xfc, 0xf0, 0x03, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf0, 0xff, 0x00, 0x00, + 0xe0, 0x7f, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +/* MOZ_CURSOR_SPINNING */ +static const char moz_spinning_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x7c, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, + 0xfc, 0x3b, 0x00, 0x00, 0x7c, 0x38, 0x00, 0x00, 0x6c, 0x54, 0x00, 0x00, + 0xc4, 0xdc, 0x00, 0x00, 0xc0, 0x44, 0x00, 0x00, 0x80, 0x39, 0x00, 0x00, + 0x80, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +static const char moz_spinning_mask_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, + 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x3b, 0x00, 0x00, + 0xfe, 0x7f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00, + 0xee, 0xff, 0x01, 0x00, 0xe4, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, + 0xc0, 0x7f, 0x00, 0x00, 0x80, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +/* MOZ_CURSOR_NONE */ +static const char moz_none_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +static const char moz_none_mask_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +/* MOZ_CURSOR_HAND_GRAB */ +static const char moz_hand_grab_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x60, 0x39, 0x00, 0x00, 0x90, 0x49, 0x00, 0x00, 0x90, 0x49, 0x01, 0x00, + 0x20, 0xc9, 0x02, 0x00, 0x20, 0x49, 0x02, 0x00, 0x58, 0x40, 0x02, 0x00, + 0x64, 0x00, 0x02, 0x00, 0x44, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x10, 0x00, 0x01, 0x00, 0x10, 0x80, 0x00, 0x00, 0x20, 0x80, 0x00, 0x00, + 0x40, 0x40, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +static const char moz_hand_grab_mask_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x60, 0x3f, 0x00, 0x00, + 0xf0, 0x7f, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x03, 0x00, + 0xf0, 0xff, 0x07, 0x00, 0xf8, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, + 0xfe, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, + 0xf8, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf0, 0xff, 0x01, 0x00, + 0xe0, 0xff, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +/* MOZ_CURSOR_HAND_GRABBING */ +static const char moz_hand_grabbing_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x36, 0x00, 0x00, 0x20, 0xc9, 0x00, 0x00, 0x20, 0x40, 0x01, 0x00, + 0x40, 0x00, 0x01, 0x00, 0x60, 0x00, 0x01, 0x00, 0x10, 0x00, 0x01, 0x00, + 0x10, 0x00, 0x01, 0x00, 0x10, 0x80, 0x00, 0x00, 0x20, 0x80, 0x00, 0x00, + 0x40, 0x40, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +static const char moz_hand_grabbing_mask_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x36, 0x00, 0x00, + 0xe0, 0xff, 0x00, 0x00, 0xf0, 0xff, 0x01, 0x00, 0xf0, 0xff, 0x03, 0x00, + 0xe0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x03, 0x00, + 0xf8, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf0, 0xff, 0x01, 0x00, + 0xe0, 0xff, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + enum CustomCursorType { - CustomCursorCopy = 0, - CustomCursorAlias, - CustomCursorContextMenu, - CustomCursorZoomIn, - CustomCursorZoomOut, - CustomCursorVerticalText -} ; + CustomCursorCopy = 0, + CustomCursorAlias, + CustomCursorContextMenu, + CustomCursorZoomIn, + CustomCursorZoomOut, + CustomCursorVerticalText, + CustomCursorNoDrop, + CustomCursorProgress, + CustomCursorNone, + CustomCursorGrab, + CustomCursorGrabbing, +}; typedef struct { - const char* name; - const char* bits; - const char* mask_bits; - int hot_x; - int hot_y; + const char* name; + const char* bits; + const char* mask_bits; + int hot_x; + int hot_y; } CustomCursor; // create custom pixmap cursor from cursors in nsGTKCursorData.h static const CustomCursor CustomCursors[] = { - { "copy", moz_copy_bits, moz_copy_mask_bits, 2, 2 }, - { "alias", moz_alias_bits, moz_alias_mask_bits, 2, 2 }, - { "context-menu", moz_menu_bits, moz_menu_mask_bits, 2, 2 }, - { "zoom-in", moz_zoom_in_bits, moz_zoom_in_mask_bits, 6, 6 }, - { "zoom-out", moz_zoom_out_bits, moz_zoom_out_mask_bits, 6, 6 }, - { "vertical-text", moz_vertical_text_bits, moz_vertical_text_mask_bits, 8, 4 }, + { "copy", moz_copy_bits, moz_copy_mask_bits, 2, 2 }, + { "alias", moz_alias_bits, moz_alias_mask_bits, 2, 2 }, + { "context-menu", moz_menu_bits, moz_menu_mask_bits, 2, 2 }, + { "zoom-in", moz_zoom_in_bits, moz_zoom_in_mask_bits, 6, 6 }, + { "zoom-out", moz_zoom_out_bits, moz_zoom_out_mask_bits, 6, 6 }, + { "vertical-text", moz_vertical_text_bits, moz_vertical_text_mask_bits, 8, 4 }, + { "dnd-no-drop", moz_not_allowed_bits, moz_not_allowed_mask_bits, 9, 9 }, + { "progress", moz_spinning_bits, moz_spinning_mask_bits, 2, 2}, + { "none", moz_none_bits, moz_none_mask_bits, 0, 0 }, + { "grab", moz_hand_grab_bits, moz_hand_grab_mask_bits, 10, 10 }, + { "grabbing", moz_hand_grabbing_bits, moz_hand_grabbing_mask_bits, 10, 10 } }; #endif // CursorGtk_h diff --git a/WebCore/platform/gtk/FileChooserGtk.cpp b/WebCore/platform/gtk/FileChooserGtk.cpp index e984718..a25d88b 100644 --- a/WebCore/platform/gtk/FileChooserGtk.cpp +++ b/WebCore/platform/gtk/FileChooserGtk.cpp @@ -34,7 +34,6 @@ #include "StringTruncator.h" #include <glib.h> -#include <glib/gi18n.h> #include <gtk/gtk.h> namespace WebCore { diff --git a/WebCore/platform/gtk/FileSystemGtk.cpp b/WebCore/platform/gtk/FileSystemGtk.cpp index 94e06db..fcdc863 100644 --- a/WebCore/platform/gtk/FileSystemGtk.cpp +++ b/WebCore/platform/gtk/FileSystemGtk.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Holger Hans Peter Freyther + * Copyright (C) 2007, 2009 Holger Hans Peter Freyther * Copyright (C) 2008 Collabora, Ltd. * Copyright (C) 2008 Apple Inc. All rights reserved. * @@ -22,8 +22,7 @@ #include "config.h" #include "FileSystem.h" -#include "guriescape.h" -#include "NotImplemented.h" +#include "GOwnPtr.h" #include "PlatformString.h" #include "CString.h" @@ -180,6 +179,9 @@ String homeDirectoryPath() String pathGetFileName(const String& pathName) { + if (pathName.isEmpty()) + return pathName; + char* tmpFilename = filenameFromString(pathName); char* baseName = g_path_get_basename(tmpFilename); String fileName = String::fromUTF8(baseName); @@ -191,8 +193,10 @@ String pathGetFileName(const String& pathName) String directoryName(const String& path) { - notImplemented(); - return String(); + /* No null checking needed */ + GOwnPtr<char> tmpFilename(filenameFromString(path)); + GOwnPtr<char> dirname(g_path_get_dirname(tmpFilename.get())); + return String::fromUTF8(dirname.get()); } Vector<String> listDirectory(const String& path, const String& filter) diff --git a/WebCore/platform/gtk/GeolocationServiceGtk.cpp b/WebCore/platform/gtk/GeolocationServiceGtk.cpp index cc69d44..fc15833 100644 --- a/WebCore/platform/gtk/GeolocationServiceGtk.cpp +++ b/WebCore/platform/gtk/GeolocationServiceGtk.cpp @@ -181,8 +181,8 @@ void GeolocationServiceGtk::updatePosition() m_lastError = 0; RefPtr<Coordinates> coordinates = Coordinates::create(m_latitude, m_longitude, - m_altitude, m_accuracy, - m_altitudeAccuracy, 0.0, 0.0); + true, m_altitude, m_accuracy, + true, m_altitudeAccuracy, false, 0.0, false, 0.0); m_lastPosition = Geoposition::create(coordinates.release(), m_timestamp * 1000.0); positionChanged(); } diff --git a/WebCore/platform/gtk/GtkPluginWidget.cpp b/WebCore/platform/gtk/GtkPluginWidget.cpp new file mode 100644 index 0000000..bc2dd92 --- /dev/null +++ b/WebCore/platform/gtk/GtkPluginWidget.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2009 Holger Hans Peter Freyther + * 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 "GtkPluginWidget.h" + +#include "GraphicsContext.h" +#include "ScrollView.h" + +#include <gtk/gtk.h> + +namespace WebCore { + +GtkPluginWidget::GtkPluginWidget(GtkWidget* widget) + : Widget(widget) +{ + gtk_widget_hide(widget); +} + +void GtkPluginWidget::invalidateRect(const IntRect& _rect) +{ + /* no need to */ + if (GTK_WIDGET_NO_WINDOW(platformWidget())) + return; + + GdkWindow* window = platformWidget()->window; + if (!window) + return; + + GdkRectangle rect = _rect; + gdk_window_invalidate_rect(window, &rect, FALSE); +} + +void GtkPluginWidget::frameRectsChanged() +{ + IntRect rect = frameRect(); + IntPoint loc = parent()->contentsToWindow(rect.location()); + GtkAllocation allocation = { loc.x(), loc.y(), rect.width(), rect.height() }; + + gtk_widget_set_size_request(platformWidget(), rect.width(), rect.height()); + gtk_widget_size_allocate(platformWidget(), &allocation); + gtk_widget_show(platformWidget()); +} + +void GtkPluginWidget::paint(GraphicsContext* context, const IntRect& rect) +{ + if (!context->gdkExposeEvent()) + return; + + /* only paint widgets with NO_WINDOW this way */ + if (!GTK_WIDGET_NO_WINDOW(platformWidget())) + return; + + GtkWidget* widget = platformWidget(); + ASSERT(GTK_WIDGET_NO_WINDOW(widget)); + + GdkEvent* event = gdk_event_new(GDK_EXPOSE); + event->expose = *context->gdkExposeEvent(); + event->expose.area = static_cast<GdkRectangle>(rect); + + IntPoint loc = parent()->contentsToWindow(rect.location()); + + event->expose.area.x = loc.x(); + event->expose.area.y = loc.y(); + + event->expose.region = gdk_region_rectangle(&event->expose.area); + + /* + * This will be unref'ed by gdk_event_free. + */ + g_object_ref(event->expose.window); + + /* + * If we are going to paint do the translation and GtkAllocation manipulation. + */ + if (!gdk_region_empty(event->expose.region)) + gtk_widget_send_expose(widget, event); + + gdk_event_free(event); +} + +} diff --git a/WebCore/platform/network/cf/ResourceResponseCFNet.h b/WebCore/platform/gtk/GtkPluginWidget.h index 27144c6..cad3462 100644 --- a/WebCore/platform/network/cf/ResourceResponseCFNet.h +++ b/WebCore/platform/gtk/GtkPluginWidget.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2009 Holger Hans Peter Freyther + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -20,20 +21,22 @@ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ResourceResponseCFNet_h -#define ResourceResponseCFNet_h +#ifndef GtkPluginWidget_h +#define GtkPluginWidget_h -typedef struct _CFURLResponse* CFURLResponseRef; +#include "Widget.h" namespace WebCore { - - class ResourceResponse; - - void getResourceResponse(ResourceResponse& response, CFURLResponseRef cfResponse); - + class GtkPluginWidget : public Widget { + public: + GtkPluginWidget(GtkWidget*); + void invalidateRect(const IntRect&); + void frameRectsChanged(); + void paint(GraphicsContext*, const IntRect&); + }; } -#endif // ResourceResponseCFNet_h +#endif diff --git a/WebCore/platform/gtk/KeyEventGtk.cpp b/WebCore/platform/gtk/KeyEventGtk.cpp index e0742f4..5875547 100644 --- a/WebCore/platform/gtk/KeyEventGtk.cpp +++ b/WebCore/platform/gtk/KeyEventGtk.cpp @@ -37,9 +37,6 @@ #include <gdk/gdk.h> #include <gdk/gdkkeysyms.h> -// GTK_CHECK_VERSION is defined in gtk/gtkversion.h -#include <gtk/gtk.h> - namespace WebCore { // FIXME: This is incomplete. We should change this to mirror @@ -260,9 +257,10 @@ static int windowsKeyCodeForKeyEvent(unsigned int keycode) case GDK_Help: return VK_HELP; // (2F) HELP key case GDK_0: - case GDK_parenleft: + case GDK_parenright: return VK_0; // (30) 0) key case GDK_1: + case GDK_exclam: return VK_1; // (31) 1 ! key case GDK_2: case GDK_at: @@ -286,7 +284,7 @@ static int windowsKeyCodeForKeyEvent(unsigned int keycode) case GDK_asterisk: return VK_8; // (38) 8 key '*' case GDK_9: - case GDK_parenright: + case GDK_parenleft: return VK_9; // (39) 9 key '(' case GDK_a: case GDK_A: @@ -536,12 +534,7 @@ PlatformKeyboardEvent::PlatformKeyboardEvent(GdkEventKey* event) , m_shiftKey((event->state & GDK_SHIFT_MASK) || (event->keyval == GDK_3270_BackTab)) , m_ctrlKey(event->state & GDK_CONTROL_MASK) , m_altKey(event->state & GDK_MOD1_MASK) -#if GTK_CHECK_VERSION(2,10,0) , m_metaKey(event->state & GDK_META_MASK) -#else - // GDK_MOD2_MASK doesn't always mean meta so we can't use it - , m_metaKey(false) -#endif , m_gdkEventKey(event) { } diff --git a/WebCore/platform/gtk/KeyboardCodes.h b/WebCore/platform/gtk/KeyboardCodes.h deleted file mode 100644 index 3ad1243..0000000 --- a/WebCore/platform/gtk/KeyboardCodes.h +++ /dev/null @@ -1,543 +0,0 @@ -/* - * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com - * 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. - */ - -#ifndef KeyboardCodes_h -#define KeyboardCodes_h - -namespace WebCore { - -// VK_LBUTTON (01) Left mouse button -// VK_RBUTTON (02) Right mouse button -// VK_CANCEL (03) Control-break processing -// VK_MBUTTON (04) Middle mouse button (three-button mouse) -// VK_XBUTTON1 (05) -// VK_XBUTTON2 (06) - -// VK_BACK (08) BACKSPACE key -const int VK_BACK = 0x08; - -// VK_TAB (09) TAB key -const int VK_TAB = 0x09; - -// VK_CLEAR (0C) CLEAR key -const int VK_CLEAR = 0x0C; - -// VK_RETURN (0D) -const int VK_RETURN = 0x0D; - -// VK_SHIFT (10) SHIFT key -const int VK_SHIFT = 0x10; - -// VK_CONTROL (11) CTRL key -const int VK_CONTROL = 0x11; - -// VK_MENU (12) ALT key -const int VK_MENU = 0x12; - -// VK_PAUSE (13) PAUSE key -const int VK_PAUSE = 0x13; - -// VK_CAPITAL (14) CAPS LOCK key -const int VK_CAPITAL = 0x14; - -// VK_KANA (15) Input Method Editor (IME) Kana mode -const int VK_KANA = 0x15; - -// VK_HANGUEL (15) IME Hanguel mode (maintained for compatibility; use VK_HANGUL) -// VK_HANGUL (15) IME Hangul mode -const int VK_HANGUL = 0x15; - -// VK_JUNJA (17) IME Junja mode -const int VK_JUNJA = 0x17; - -// VK_FINAL (18) IME final mode -const int VK_FINAL = 0x18; - -// VK_HANJA (19) IME Hanja mode -const int VK_HANJA = 0x19; - -// VK_KANJI (19) IME Kanji mode -const int VK_KANJI = 0x19; - -// VK_ESCAPE (1B) ESC key -const int VK_ESCAPE = 0x1B; - -// VK_CONVERT (1C) IME convert -const int VK_CONVERT = 0x1C; - -// VK_NONCONVERT (1D) IME nonconvert -const int VK_NONCONVERT = 0x1D; - -// VK_ACCEPT (1E) IME accept -const int VK_ACCEPT = 0x1E; - -// VK_MODECHANGE (1F) IME mode change request -const int VK_MODECHANGE = 0x1F; - -// VK_SPACE (20) SPACEBAR -const int VK_SPACE = 0x20; - -// VK_PRIOR (21) PAGE UP key -const int VK_PRIOR = 0x21; - -// VK_NEXT (22) PAGE DOWN key -const int VK_NEXT = 0x22; - -// VK_END (23) END key -const int VK_END = 0x23; - -// VK_HOME (24) HOME key -const int VK_HOME = 0x24; - -// VK_LEFT (25) LEFT ARROW key -const int VK_LEFT = 0x25; - -// VK_UP (26) UP ARROW key -const int VK_UP = 0x26; - -// VK_RIGHT (27) RIGHT ARROW key -const int VK_RIGHT = 0x27; - -// VK_DOWN (28) DOWN ARROW key -const int VK_DOWN = 0x28; - -// VK_SELECT (29) SELECT key -const int VK_SELECT = 0x29; - -// VK_PRINT (2A) PRINT key -const int VK_PRINT = 0x2A; - -// VK_EXECUTE (2B) EXECUTE key -const int VK_EXECUTE = 0x2B; - -// VK_SNAPSHOT (2C) PRINT SCREEN key -const int VK_SNAPSHOT = 0x2C; - -// VK_INSERT (2D) INS key -const int VK_INSERT = 0x2D; - -// VK_DELETE (2E) DEL key -const int VK_DELETE = 0x2E; - -// VK_HELP (2F) HELP key -const int VK_HELP = 0x2F; - -// (30) 0 key -const int VK_0 = 0x30; - -// (31) 1 key -const int VK_1 = 0x31; - -// (32) 2 key -const int VK_2 = 0x32; - -// (33) 3 key -const int VK_3 = 0x33; - -// (34) 4 key -const int VK_4 = 0x34; - -// (35) 5 key; - -const int VK_5 = 0x35; - -// (36) 6 key -const int VK_6 = 0x36; - -// (37) 7 key -const int VK_7 = 0x37; - -// (38) 8 key -const int VK_8 = 0x38; - -// (39) 9 key -const int VK_9 = 0x39; - -// (41) A key -const int VK_A = 0x41; - -// (42) B key -const int VK_B = 0x42; - -// (43) C key -const int VK_C = 0x43; - -// (44) D key -const int VK_D = 0x44; - -// (45) E key -const int VK_E = 0x45; - -// (46) F key -const int VK_F = 0x46; - -// (47) G key -const int VK_G = 0x47; - -// (48) H key -const int VK_H = 0x48; - -// (49) I key -const int VK_I = 0x49; - -// (4A) J key -const int VK_J = 0x4A; - -// (4B) K key -const int VK_K = 0x4B; - -// (4C) L key -const int VK_L = 0x4C; - -// (4D) M key -const int VK_M = 0x4D; - -// (4E) N key -const int VK_N = 0x4E; - -// (4F) O key -const int VK_O = 0x4F; - -// (50) P key -const int VK_P = 0x50; - -// (51) Q key -const int VK_Q = 0x51; - -// (52) R key -const int VK_R = 0x52; - -// (53) S key -const int VK_S = 0x53; - -// (54) T key -const int VK_T = 0x54; - -// (55) U key -const int VK_U = 0x55; - -// (56) V key -const int VK_V = 0x56; - -// (57) W key -const int VK_W = 0x57; - -// (58) X key -const int VK_X = 0x58; - -// (59) Y key -const int VK_Y = 0x59; - -// (5A) Z key -const int VK_Z = 0x5A; - -// VK_LWIN (5B) Left Windows key (Microsoft Natural keyboard) -const int VK_LWIN = 0x5B; - -// VK_RWIN (5C) Right Windows key (Natural keyboard) -const int VK_RWIN = 0x5C; - -// VK_APPS (5D) Applications key (Natural keyboard) -const int VK_APPS = 0x5D; - -// VK_SLEEP (5F) Computer Sleep key -const int VK_SLEEP = 0x5F; - -// VK_NUMPAD0 (60) Numeric keypad 0 key -const int VK_NUMPAD0 = 0x60; - -// VK_NUMPAD1 (61) Numeric keypad 1 key -const int VK_NUMPAD1 = 0x61; - -// VK_NUMPAD2 (62) Numeric keypad 2 key -const int VK_NUMPAD2 = 0x62; - -// VK_NUMPAD3 (63) Numeric keypad 3 key -const int VK_NUMPAD3 = 0x63; - -// VK_NUMPAD4 (64) Numeric keypad 4 key -const int VK_NUMPAD4 = 0x64; - -// VK_NUMPAD5 (65) Numeric keypad 5 key -const int VK_NUMPAD5 = 0x65; - -// VK_NUMPAD6 (66) Numeric keypad 6 key -const int VK_NUMPAD6 = 0x66; - -// VK_NUMPAD7 (67) Numeric keypad 7 key -const int VK_NUMPAD7 = 0x67; - -// VK_NUMPAD8 (68) Numeric keypad 8 key -const int VK_NUMPAD8 = 0x68; - -// VK_NUMPAD9 (69) Numeric keypad 9 key -const int VK_NUMPAD9 = 0x69; - -// VK_MULTIPLY (6A) Multiply key -const int VK_MULTIPLY = 0x6A; - -// VK_ADD (6B) Add key -const int VK_ADD = 0x6B; - -// VK_SEPARATOR (6C) Separator key -const int VK_SEPARATOR = 0x6C; - -// VK_SUBTRACT (6D) Subtract key -const int VK_SUBTRACT = 0x6D; - -// VK_DECIMAL (6E) Decimal key -const int VK_DECIMAL = 0x6E; - -// VK_DIVIDE (6F) Divide key -const int VK_DIVIDE = 0x6F; - -// VK_F1 (70) F1 key -const int VK_F1 = 0x70; - -// VK_F2 (71) F2 key -const int VK_F2 = 0x71; - -// VK_F3 (72) F3 key -const int VK_F3 = 0x72; - -// VK_F4 (73) F4 key -const int VK_F4 = 0x73; - -// VK_F5 (74) F5 key -const int VK_F5 = 0x74; - -// VK_F6 (75) F6 key -const int VK_F6 = 0x75; - -// VK_F7 (76) F7 key -const int VK_F7 = 0x76; - -// VK_F8 (77) F8 key -const int VK_F8 = 0x77; - -// VK_F9 (78) F9 key -const int VK_F9 = 0x78; - -// VK_F10 (79) F10 key -const int VK_F10 = 0x79; - -// VK_F11 (7A) F11 key -const int VK_F11 = 0x7A; - -// VK_F12 (7B) F12 key -const int VK_F12 = 0x7B; - -// VK_F13 (7C) F13 key -const int VK_F13 = 0x7C; - -// VK_F14 (7D) F14 key -const int VK_F14 = 0x7D; - -// VK_F15 (7E) F15 key -const int VK_F15 = 0x7E; - -// VK_F16 (7F) F16 key -const int VK_F16 = 0x7F; - -// VK_F17 (80H) F17 key -const int VK_F17 = 0x80; - -// VK_F18 (81H) F18 key -const int VK_F18 = 0x81; - -// VK_F19 (82H) F19 key -const int VK_F19 = 0x82; - -// VK_F20 (83H) F20 key -const int VK_F20 = 0x83; - -// VK_F21 (84H) F21 key -const int VK_F21 = 0x84; - -// VK_F22 (85H) F22 key -const int VK_F22 = 0x85; - -// VK_F23 (86H) F23 key -const int VK_F23 = 0x86; - -// VK_F24 (87H) F24 key -const int VK_F24 = 0x87; - -// VK_NUMLOCK (90) NUM LOCK key -const int VK_NUMLOCK = 0x90; - -// VK_SCROLL (91) SCROLL LOCK key -const int VK_SCROLL = 0x91; - -// VK_LSHIFT (A0) Left SHIFT key -const int VK_LSHIFT = 0xA0; - -// VK_RSHIFT (A1) Right SHIFT key -const int VK_RSHIFT = 0xA1; - -// VK_LCONTROL (A2) Left CONTROL key -const int VK_LCONTROL = 0xA2; - -// VK_RCONTROL (A3) Right CONTROL key -const int VK_RCONTROL = 0xA3; - -// VK_LMENU (A4) Left MENU key -const int VK_LMENU = 0xA4; - -// VK_RMENU (A5) Right MENU key -const int VK_RMENU = 0xA5; - -// VK_BROWSER_BACK (A6) Windows 2000/XP: Browser Back key -const int VK_BROWSER_BACK = 0xA6; - -// VK_BROWSER_FORWARD (A7) Windows 2000/XP: Browser Forward key -const int VK_BROWSER_FORWARD = 0xA7; - -// VK_BROWSER_REFRESH (A8) Windows 2000/XP: Browser Refresh key -const int VK_BROWSER_REFRESH = 0xA8; - -// VK_BROWSER_STOP (A9) Windows 2000/XP: Browser Stop key -const int VK_BROWSER_STOP = 0xA9; - -// VK_BROWSER_SEARCH (AA) Windows 2000/XP: Browser Search key -const int VK_BROWSER_SEARCH = 0xAA; - -// VK_BROWSER_FAVORITES (AB) Windows 2000/XP: Browser Favorites key -const int VK_BROWSER_FAVORITES = 0xAB; - -// VK_BROWSER_HOME (AC) Windows 2000/XP: Browser Start and Home key -const int VK_BROWSER_HOME = 0xAC; - -// VK_VOLUME_MUTE (AD) Windows 2000/XP: Volume Mute key -const int VK_VOLUME_MUTE = 0xAD; - -// VK_VOLUME_DOWN (AE) Windows 2000/XP: Volume Down key -const int VK_VOLUME_DOWN = 0xAE; - -// VK_VOLUME_UP (AF) Windows 2000/XP: Volume Up key -const int VK_VOLUME_UP = 0xAF; - -// VK_MEDIA_NEXT_TRACK (B0) Windows 2000/XP: Next Track key -const int VK_MEDIA_NEXT_TRACK = 0xB0; - -// VK_MEDIA_PREV_TRACK (B1) Windows 2000/XP: Previous Track key -const int VK_MEDIA_PREV_TRACK = 0xB1; - -// VK_MEDIA_STOP (B2) Windows 2000/XP: Stop Media key -const int VK_MEDIA_STOP = 0xB2; - -// VK_MEDIA_PLAY_PAUSE (B3) Windows 2000/XP: Play/Pause Media key -const int VK_MEDIA_PLAY_PAUSE = 0xB3; - -// VK_LAUNCH_MAIL (B4) Windows 2000/XP: Start Mail key -const int VK_MEDIA_LAUNCH_MAIL = 0xB4; - -// VK_LAUNCH_MEDIA_SELECT (B5) Windows 2000/XP: Select Media key -const int VK_MEDIA_LAUNCH_MEDIA_SELECT = 0xB5; - -// VK_LAUNCH_APP1 (B6) Windows 2000/XP: Start Application 1 key -const int VK_MEDIA_LAUNCH_APP1 = 0xB6; - -// VK_LAUNCH_APP2 (B7) Windows 2000/XP: Start Application 2 key -const int VK_MEDIA_LAUNCH_APP2 = 0xB7; - -// VK_OEM_1 (BA) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ';:' key -const int VK_OEM_1 = 0xBA; - -// VK_OEM_PLUS (BB) Windows 2000/XP: For any country/region, the '+' key -const int VK_OEM_PLUS = 0xBB; - -// VK_OEM_COMMA (BC) Windows 2000/XP: For any country/region, the ',' key -const int VK_OEM_COMMA = 0xBC; - -// VK_OEM_MINUS (BD) Windows 2000/XP: For any country/region, the '-' key -const int VK_OEM_MINUS = 0xBD; - -// VK_OEM_PERIOD (BE) Windows 2000/XP: For any country/region, the '.' key -const int VK_OEM_PERIOD = 0xBE; - -// VK_OEM_2 (BF) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '/?' key -const int VK_OEM_2 = 0xBF; - -// VK_OEM_3 (C0) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '`~' key -const int VK_OEM_3 = 0xC0; - -// VK_OEM_4 (DB) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '[{' key -const int VK_OEM_4 = 0xDB; - -// VK_OEM_5 (DC) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '\|' key -const int VK_OEM_5 = 0xDC; - -// VK_OEM_6 (DD) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ']}' key -const int VK_OEM_6 = 0xDD; - -// VK_OEM_7 (DE) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the 'single-quote/double-quote' key -const int VK_OEM_7 = 0xDE; - -// VK_OEM_8 (DF) Used for miscellaneous characters; it can vary by keyboard. -const int VK_OEM_8 = 0xDF; - -// VK_OEM_102 (E2) Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard -const int VK_OEM_102 = 0xE2; - -// VK_PROCESSKEY (E5) Windows 95/98/Me, Windows NT 4.0, Windows 2000/XP: IME PROCESS key -const int VK_PROCESSKEY = 0xE5; - -// VK_PACKET (E7) Windows 2000/XP: Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT,SendInput, WM_KEYDOWN, and WM_KEYUP -const int VK_PACKET = 0xE7; - -// VK_ATTN (F6) Attn key -const int VK_ATTN = 0xF6; - -// VK_CRSEL (F7) CrSel key -const int VK_CRSEL = 0xF7; - -// VK_EXSEL (F8) ExSel key -const int VK_EXSEL = 0xF8; - -// VK_EREOF (F9) Erase EOF key -const int VK_EREOF = 0xF9; - -// VK_PLAY (FA) Play key -const int VK_PLAY = 0xFA; - -// VK_ZOOM (FB) Zoom key -const int VK_ZOOM = 0xFB; - -// VK_NONAME (FC) Reserved for future use -const int VK_NONAME = 0xFC; - -// VK_PA1 (FD) PA1 key -const int VK_PA1 = 0xFD; - -// VK_OEM_CLEAR (FE) Clear key -const int VK_OEM_CLEAR = 0xFE; - -const int VK_UNKNOWN = 0; - -} - -#endif diff --git a/WebCore/platform/gtk/LocalizedStringsGtk.cpp b/WebCore/platform/gtk/LocalizedStringsGtk.cpp index 52d4f5f..70e3aff 100644 --- a/WebCore/platform/gtk/LocalizedStringsGtk.cpp +++ b/WebCore/platform/gtk/LocalizedStringsGtk.cpp @@ -30,11 +30,14 @@ #include "config.h" #include "LocalizedStrings.h" +#include "CString.h" +#include "GOwnPtr.h" +#include "IntSize.h" #include "NotImplemented.h" #include "PlatformString.h" +#include <glib/gi18n-lib.h> #include <gtk/gtk.h> -#include <glib/gi18n.h> namespace WebCore { @@ -125,11 +128,7 @@ String contextMenuItemTagDelete() String contextMenuItemTagSelectAll() { -#if GTK_CHECK_VERSION(2,10,0) static String stockLabel = String::fromUTF8(gtkStockLabel(GTK_STOCK_SELECT_ALL)); -#else - static String stockLabel = String::fromUTF8(_("Select _All")); -#endif return stockLabel; } @@ -339,8 +338,11 @@ String unknownFileSizeText() String imageTitle(const String& filename, const IntSize& size) { - notImplemented(); - return String(); + GOwnPtr<gchar> string(g_strdup_printf(C_("Title string for images", "%s (%dx%d pixels)"), + filename.utf8().data(), + size.width(), size.height())); + + return String::fromUTF8(string.get()); } } diff --git a/WebCore/platform/gtk/MouseEventGtk.cpp b/WebCore/platform/gtk/MouseEventGtk.cpp index 2400ebf..69f938f 100644 --- a/WebCore/platform/gtk/MouseEventGtk.cpp +++ b/WebCore/platform/gtk/MouseEventGtk.cpp @@ -31,9 +31,6 @@ #include <gdk/gdk.h> -// GTK_CHECK_VERSION is defined in gtk/gtkversion.h -#include <gtk/gtk.h> - namespace WebCore { // FIXME: Would be even better to figure out which modifier is Alt instead of always using GDK_MOD1_MASK. @@ -47,12 +44,7 @@ PlatformMouseEvent::PlatformMouseEvent(GdkEventButton* event) m_shiftKey = event->state & GDK_SHIFT_MASK; m_ctrlKey = event->state & GDK_CONTROL_MASK; m_altKey = event->state & GDK_MOD1_MASK; -#if GTK_CHECK_VERSION(2,10,0) m_metaKey = event->state & GDK_META_MASK; -#else - // GDK_MOD2_MASK doesn't always mean meta so we can't use it - m_metaKey = false; -#endif switch (event->type) { case GDK_BUTTON_PRESS: diff --git a/WebCore/platform/gtk/PasteboardGtk.cpp b/WebCore/platform/gtk/PasteboardGtk.cpp index 15a7e64..062ecb8 100644 --- a/WebCore/platform/gtk/PasteboardGtk.cpp +++ b/WebCore/platform/gtk/PasteboardGtk.cpp @@ -103,7 +103,6 @@ void Pasteboard::setHelper(PasteboardHelper* helper) void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame) { GtkClipboard* clipboard = m_helper->getClipboard(frame); -#if GTK_CHECK_VERSION(2,10,0) gchar* text = g_strdup(frame->selectedText().utf8().data()); gchar* markup = g_strdup(createMarkup(selectedRange, 0, AnnotateForInterchange).utf8().data()); PasteboardSelectionData* data = new PasteboardSelectionData(text, markup); @@ -113,9 +112,6 @@ void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, 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); -#else - gtk_clipboard_set_text(clipboard, frame->selectedText().utf8().data(), frame->selectedText().utf8().length()); -#endif } void Pasteboard::writeURL(const KURL& url, const String&, Frame* frame) @@ -124,14 +120,13 @@ void Pasteboard::writeURL(const KURL& url, const String&, Frame* frame) return; GtkClipboard* clipboard = m_helper->getClipboard(frame); + GtkClipboard* primary = m_helper->getPrimary(frame); gtk_clipboard_set_text(clipboard, url.string().utf8().data(), url.string().utf8().length()); + gtk_clipboard_set_text(primary, url.string().utf8().data(), url.string().utf8().length()); } void Pasteboard::writeImage(Node* node, const KURL&, const String&) { - // TODO: Enable this when Image gets GdkPixbuf support - - /* GtkClipboard* clipboard = gtk_clipboard_get_for_display(gdk_display_get_default(), GDK_SELECTION_CLIPBOARD); ASSERT(node && node->renderer() && node->renderer()->isImage()); @@ -141,10 +136,9 @@ void Pasteboard::writeImage(Node* node, const KURL&, const String&) Image* image = cachedImage->image(); ASSERT(image); - gtk_clipboard_set_image(clipboard, image->pixbuf()); - */ - - notImplemented(); + GdkPixbuf* pixbuf = image->getGdkPixbuf(); + gtk_clipboard_set_image(clipboard, pixbuf); + g_object_unref(pixbuf); } void Pasteboard::clear() @@ -163,12 +157,8 @@ bool Pasteboard::canSmartReplace() PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefPtr<Range> context, bool allowPlainText, bool& chosePlainText) { -#if GTK_CHECK_VERSION(2,10,0) GdkAtom textHtml = gdk_atom_intern_static_string("text/html"); -#else - GdkAtom textHtml = gdk_atom_intern("text/html", false); -#endif - GtkClipboard* clipboard = m_helper->getClipboard(frame); + GtkClipboard* clipboard = m_helper->getCurrentTarget(frame); chosePlainText = false; if (GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard, textHtml)) { @@ -201,7 +191,7 @@ PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefP String Pasteboard::plainText(Frame* frame) { - GtkClipboard* clipboard = m_helper->getClipboard(frame); + GtkClipboard* clipboard = m_helper->getCurrentTarget(frame); gchar* utf8 = gtk_clipboard_wait_for_text(clipboard); diff --git a/WebCore/platform/gtk/PasteboardHelper.h b/WebCore/platform/gtk/PasteboardHelper.h index 6bdc05e..9943a2d 100644 --- a/WebCore/platform/gtk/PasteboardHelper.h +++ b/WebCore/platform/gtk/PasteboardHelper.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2007 Luca Bruno <lethalman88@gmail.com> + * Copyright (C) 2009 Holger Hans Peter Freyther * All rights reserved. * * This library is free software; you can redistribute it and/or @@ -37,7 +38,9 @@ class PasteboardHelper { public: virtual ~PasteboardHelper() {}; + 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; }; diff --git a/WebCore/platform/gtk/PlatformScreenGtk.cpp b/WebCore/platform/gtk/PlatformScreenGtk.cpp index 3512be1..27985ef 100644 --- a/WebCore/platform/gtk/PlatformScreenGtk.cpp +++ b/WebCore/platform/gtk/PlatformScreenGtk.cpp @@ -31,7 +31,6 @@ #include "PlatformScreen.h" #include "HostWindow.h" -#include "NotImplemented.h" #include "ScrollView.h" #include "Widget.h" diff --git a/WebCore/platform/gtk/PopupMenuGtk.cpp b/WebCore/platform/gtk/PopupMenuGtk.cpp index 54b41ab..121d7b0 100644 --- a/WebCore/platform/gtk/PopupMenuGtk.cpp +++ b/WebCore/platform/gtk/PopupMenuGtk.cpp @@ -28,7 +28,6 @@ #include "CString.h" #include "FrameView.h" #include "HostWindow.h" -#include "NotImplemented.h" #include "PlatformString.h" #include <gtk/gtk.h> @@ -42,8 +41,11 @@ PopupMenu::PopupMenu(PopupMenuClient* client) PopupMenu::~PopupMenu() { - if (m_popup) + if (m_popup) { + g_signal_handlers_disconnect_matched(m_popup, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this); + hide(); g_object_unref(m_popup); + } } void PopupMenu::show(const IntRect& rect, FrameView* view, int index) diff --git a/WebCore/platform/gtk/RenderThemeGtk.cpp b/WebCore/platform/gtk/RenderThemeGtk.cpp index ee462e0..a95f557 100644 --- a/WebCore/platform/gtk/RenderThemeGtk.cpp +++ b/WebCore/platform/gtk/RenderThemeGtk.cpp @@ -54,6 +54,14 @@ RenderThemeGtk::RenderThemeGtk() } } +RenderThemeGtk::~RenderThemeGtk() +{ + if (mozGtkInitialized) { + moz_gtk_shutdown(); + mozGtkInitialized = false; + } +} + static bool supportsFocus(ControlPart appearance) { switch (appearance) { diff --git a/WebCore/platform/gtk/RenderThemeGtk.h b/WebCore/platform/gtk/RenderThemeGtk.h index 76f7a0a..82a87cb 100644 --- a/WebCore/platform/gtk/RenderThemeGtk.h +++ b/WebCore/platform/gtk/RenderThemeGtk.h @@ -36,6 +36,7 @@ namespace WebCore { class RenderThemeGtk : public RenderTheme { public: RenderThemeGtk(); + virtual ~RenderThemeGtk(); // A method asking if the theme's controls actually care about redrawing when hovered. virtual bool supportsHover(const RenderStyle* style) const { return true; } diff --git a/WebCore/platform/gtk/ScrollViewGtk.cpp b/WebCore/platform/gtk/ScrollViewGtk.cpp index b3b6dd9..0f066fc 100644 --- a/WebCore/platform/gtk/ScrollViewGtk.cpp +++ b/WebCore/platform/gtk/ScrollViewGtk.cpp @@ -1,7 +1,7 @@ /* * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved. * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com - * Copyright (C) 2007 Holger Hans Peter Freyther + * Copyright (C) 2007, 2009 Holger Hans Peter Freyther * Copyright (C) 2008 Collabora Ltd. * * All rights reserved. @@ -35,7 +35,6 @@ #include "GraphicsContext.h" #include "HostWindow.h" #include "IntRect.h" -#include "NotImplemented.h" #include "PlatformMouseEvent.h" #include "PlatformWheelEvent.h" #include "ScrollbarGtk.h" @@ -47,28 +46,6 @@ using namespace std; namespace WebCore { -static void adjustmentChanged(GtkAdjustment* adjustment, gpointer _that) -{ - ScrollView* that = reinterpret_cast<ScrollView*>(_that); - - // Figure out if we really moved. - IntSize newOffset = that->scrollOffset(); - if (adjustment == that->m_horizontalAdjustment) - newOffset.setWidth(static_cast<int>(gtk_adjustment_get_value(adjustment))); - else if (adjustment == that->m_verticalAdjustment) - newOffset.setHeight(static_cast<int>(gtk_adjustment_get_value(adjustment))); - - IntSize scrollDelta = newOffset - that->scrollOffset(); - if (scrollDelta == IntSize()) - return; - that->setScrollOffset(newOffset); - - if (that->scrollbarsSuppressed()) - return; - - that->scrollContents(scrollDelta); -} - void ScrollView::platformInit() { m_horizontalAdjustment = 0; @@ -77,15 +54,18 @@ void ScrollView::platformInit() void ScrollView::platformDestroy() { - if (m_horizontalAdjustment) { - g_signal_handlers_disconnect_by_func(G_OBJECT(m_horizontalAdjustment), (gpointer)adjustmentChanged, this); - g_object_unref(m_horizontalAdjustment); - } + m_horizontalAdjustment = 0; + m_verticalAdjustment = 0; +} - if (m_verticalAdjustment) { - g_signal_handlers_disconnect_by_func(G_OBJECT(m_verticalAdjustment), (gpointer)adjustmentChanged, this); - g_object_unref(m_verticalAdjustment); - } +PassRefPtr<Scrollbar> ScrollView::createScrollbar(ScrollbarOrientation orientation) +{ + if (orientation == HorizontalScrollbar && m_horizontalAdjustment) + return ScrollbarGtk::createScrollbar(this, orientation, m_horizontalAdjustment); + else if (orientation == VerticalScrollbar && m_verticalAdjustment) + return ScrollbarGtk::createScrollbar(this, orientation, m_verticalAdjustment); + else + return Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar); } /* @@ -96,30 +76,27 @@ void ScrollView::setGtkAdjustments(GtkAdjustment* hadj, GtkAdjustment* vadj) { ASSERT(!hadj == !vadj); - if (m_horizontalAdjustment) { - g_signal_handlers_disconnect_by_func(G_OBJECT(m_horizontalAdjustment), (gpointer)adjustmentChanged, this); - g_signal_handlers_disconnect_by_func(G_OBJECT(m_verticalAdjustment), (gpointer)adjustmentChanged, this); - g_object_unref(m_horizontalAdjustment); - g_object_unref(m_verticalAdjustment); - } - m_horizontalAdjustment = hadj; m_verticalAdjustment = vadj; + // Reset the adjustments to a sane default if (m_horizontalAdjustment) { - g_signal_connect(m_horizontalAdjustment, "value-changed", G_CALLBACK(adjustmentChanged), this); - g_signal_connect(m_verticalAdjustment, "value-changed", G_CALLBACK(adjustmentChanged), this); - - /* - * disable the scrollbars (if we have any) as the GtkAdjustment over - */ - setHasVerticalScrollbar(false); - setHasHorizontalScrollbar(false); + m_horizontalAdjustment->lower = 0; + m_horizontalAdjustment->upper = 0; + m_horizontalAdjustment->value = 0; + gtk_adjustment_changed(m_horizontalAdjustment); + gtk_adjustment_value_changed(m_horizontalAdjustment); - g_object_ref(m_horizontalAdjustment); - g_object_ref(m_verticalAdjustment); + m_verticalAdjustment->lower = 0; + m_verticalAdjustment->upper = 0; + m_verticalAdjustment->value = 0; + gtk_adjustment_changed(m_verticalAdjustment); + gtk_adjustment_value_changed(m_verticalAdjustment); } + /* reconsider having a scrollbar */ + setHasVerticalScrollbar(false); + setHasHorizontalScrollbar(false); updateScrollbars(m_scrollOffset); } @@ -144,52 +121,4 @@ void ScrollView::platformRemoveChild(Widget* child) gtk_container_remove(GTK_CONTAINER(parent), child->platformWidget()); } -bool ScrollView::platformHandleHorizontalAdjustment(const IntSize& scroll) -{ - if (m_horizontalAdjustment) { - m_horizontalAdjustment->page_size = visibleWidth(); - m_horizontalAdjustment->step_increment = visibleWidth() / 10.0; - m_horizontalAdjustment->page_increment = visibleWidth() * 0.9; - m_horizontalAdjustment->lower = 0; - m_horizontalAdjustment->upper = contentsWidth(); - gtk_adjustment_changed(m_horizontalAdjustment); - - if (m_horizontalAdjustment->value != scroll.width()) { - m_horizontalAdjustment->value = scroll.width(); - gtk_adjustment_value_changed(m_horizontalAdjustment); - } - return true; - } - return false; -} - -bool ScrollView::platformHandleVerticalAdjustment(const IntSize& scroll) -{ - if (m_verticalAdjustment) { - m_verticalAdjustment->page_size = visibleHeight(); - m_verticalAdjustment->step_increment = visibleHeight() / 10.0; - m_verticalAdjustment->page_increment = visibleHeight() * 0.9; - m_verticalAdjustment->lower = 0; - m_verticalAdjustment->upper = contentsHeight(); - gtk_adjustment_changed(m_verticalAdjustment); - - if (m_verticalAdjustment->value != scroll.height()) { - m_verticalAdjustment->value = scroll.height(); - gtk_adjustment_value_changed(m_verticalAdjustment); - } - return true; - } - return false; -} - -bool ScrollView::platformHasHorizontalAdjustment() const -{ - return m_horizontalAdjustment != 0; -} - -bool ScrollView::platformHasVerticalAdjustment() const -{ - return m_verticalAdjustment != 0; -} - } diff --git a/WebCore/platform/gtk/ScrollbarGtk.cpp b/WebCore/platform/gtk/ScrollbarGtk.cpp index 7543e23..d7f6d26 100644 --- a/WebCore/platform/gtk/ScrollbarGtk.cpp +++ b/WebCore/platform/gtk/ScrollbarGtk.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Holger Hans Peter Freyther zecke@selfish.org + * Copyright (C) 2007, 2009 Holger Hans Peter Freyther zecke@selfish.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,7 +22,6 @@ #include "IntRect.h" #include "GraphicsContext.h" #include "FrameView.h" -#include "NotImplemented.h" #include "ScrollbarTheme.h" #include "gtkdrawing.h" @@ -35,6 +34,11 @@ PassRefPtr<Scrollbar> Scrollbar::createNativeScrollbar(ScrollbarClient* client, return adoptRef(new ScrollbarGtk(client, orientation, size)); } +PassRefPtr<ScrollbarGtk> ScrollbarGtk::createScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, GtkAdjustment* adj) +{ + return adoptRef(new ScrollbarGtk(client, orientation, adj)); +} + static gboolean gtkScrollEventCallback(GtkWidget* widget, GdkEventScroll* event, ScrollbarGtk*) { /* Scroll only if our parent rejects the scroll event. The rationale for @@ -52,7 +56,8 @@ ScrollbarGtk::ScrollbarGtk(ScrollbarClient* client, ScrollbarOrientation orienta gtk_hscrollbar_new(m_adjustment): gtk_vscrollbar_new(m_adjustment); gtk_widget_show(scrollBar); - g_signal_connect(scrollBar, "value-changed", G_CALLBACK(ScrollbarGtk::gtkValueChanged), this); + g_object_ref(m_adjustment); + g_signal_connect(m_adjustment, "value-changed", G_CALLBACK(ScrollbarGtk::gtkValueChanged), this); g_signal_connect(scrollBar, "scroll-event", G_CALLBACK(gtkScrollEventCallback), this); setPlatformWidget(scrollBar); @@ -65,6 +70,37 @@ ScrollbarGtk::ScrollbarGtk(ScrollbarClient* client, ScrollbarOrientation orienta ScrollbarTheme::nativeTheme()->scrollbarThickness()); } +// Create a ScrollbarGtk on top of an existing GtkAdjustment but do not create a +// GtkScrollbar on top of this adjustment. The goal is to have a WebCore::Scrollbar +// that will manipulate the GtkAdjustment properties, will react to the changed +// value but will not consume any space on the screen and will not be painted +// at all. It is achieved by not calling setPlatformWidget. +ScrollbarGtk::ScrollbarGtk(ScrollbarClient* client, ScrollbarOrientation orientation, GtkAdjustment* adjustment) + : Scrollbar(client, orientation, RegularScrollbar) + , m_adjustment(adjustment) +{ + g_object_ref(m_adjustment); + g_signal_connect(m_adjustment, "value-changed", G_CALLBACK(ScrollbarGtk::gtkValueChanged), this); + + // We have nothing to show as we are solely operating on the GtkAdjustment + resize(0, 0); +} + +ScrollbarGtk::~ScrollbarGtk() +{ + g_signal_handlers_disconnect_by_func(G_OBJECT(m_adjustment), (gpointer)ScrollbarGtk::gtkValueChanged, this); + + // For the case where we only operate on the GtkAdjustment it is best to + // reset the values so that the surrounding scrollbar gets updated, or + // e.g. for a GtkScrolledWindow the scrollbar gets hidden. + m_adjustment->lower = 0; + m_adjustment->upper = 0; + m_adjustment->value = 0; + gtk_adjustment_changed(m_adjustment); + gtk_adjustment_value_changed(m_adjustment); + g_object_unref(m_adjustment); +} + IntPoint ScrollbarGtk::getLocationInParentWindow(const IntRect& rect) { IntPoint loc; @@ -79,7 +115,7 @@ IntPoint ScrollbarGtk::getLocationInParentWindow(const IntRect& rect) void ScrollbarGtk::frameRectsChanged() { - if (!parent()) + if (!parent() || !platformWidget()) return; IntPoint loc = getLocationInParentWindow(frameRect()); diff --git a/WebCore/platform/gtk/ScrollbarGtk.h b/WebCore/platform/gtk/ScrollbarGtk.h index 1ef4c49..b4b5989 100644 --- a/WebCore/platform/gtk/ScrollbarGtk.h +++ b/WebCore/platform/gtk/ScrollbarGtk.h @@ -36,6 +36,8 @@ namespace WebCore { class ScrollbarGtk : public Scrollbar { public: friend class Scrollbar; + friend class ScrollView; + ~ScrollbarGtk(); virtual void setFrameRect(const IntRect&); virtual void paint(GraphicsContext*, const IntRect&); @@ -50,7 +52,10 @@ public: virtual void frameRectsChanged(); protected: + static PassRefPtr<ScrollbarGtk> createScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, GtkAdjustment*); + ScrollbarGtk(ScrollbarClient*, ScrollbarOrientation, ScrollbarControlSize); + ScrollbarGtk(ScrollbarClient*, ScrollbarOrientation, GtkAdjustment*); virtual void updateThumbPosition(); virtual void updateThumbProportion(); diff --git a/WebCore/platform/gtk/TemporaryLinkStubs.cpp b/WebCore/platform/gtk/TemporaryLinkStubs.cpp index edabd10..8c12fcb 100644 --- a/WebCore/platform/gtk/TemporaryLinkStubs.cpp +++ b/WebCore/platform/gtk/TemporaryLinkStubs.cpp @@ -38,26 +38,10 @@ using namespace WebCore; -// This function loads resources from WebKit -// This does not belong here and I'm not sure where -// it should go -// I don't know what the plans or design is -// for none code resources -Vector<char> loadResourceIntoArray(const char* resourceName) -{ - Vector<char> resource; - //if (strcmp(resourceName,"missingImage") == 0) { - //} - return resource; -} - - /********************************************************/ /* Completely empty stubs (mostly to allow DRT to run): */ /********************************************************/ -void PluginView::invalidateRegion(NPRegion) { notImplemented(); } - namespace WebCore { void getSupportedKeySizes(Vector<String>&) { notImplemented(); } String signedPublicKeyAndChallengeString(unsigned keySizeIndex, const String &challengeString, const KURL &url) { return String(); } diff --git a/WebCore/platform/gtk/WheelEventGtk.cpp b/WebCore/platform/gtk/WheelEventGtk.cpp index 075bed2..404bf29 100644 --- a/WebCore/platform/gtk/WheelEventGtk.cpp +++ b/WebCore/platform/gtk/WheelEventGtk.cpp @@ -31,9 +31,6 @@ #include <gdk/gdk.h> -// GTK_CHECK_VERSION is defined in gtk/gtkversion.h -#include <gtk/gtk.h> - namespace WebCore { // Keep this in sync with the other platform event constructors @@ -69,12 +66,7 @@ PlatformWheelEvent::PlatformWheelEvent(GdkEventScroll* event) m_shiftKey = event->state & GDK_SHIFT_MASK; m_ctrlKey = event->state & GDK_CONTROL_MASK; m_altKey = event->state & GDK_MOD1_MASK; -#if GTK_CHECK_VERSION(2,10,0) m_metaKey = event->state & GDK_META_MASK; -#else - // GDK_MOD2_MASK doesn't always mean meta so we can't use it - m_metaKey = false; -#endif // FIXME: retrieve the user setting for the number of lines to scroll on each wheel event m_deltaX *= static_cast<float>(cScrollbarPixelsPerLineStep); diff --git a/WebCore/platform/gtk/WidgetGtk.cpp b/WebCore/platform/gtk/WidgetGtk.cpp index 4f09e77..007f2ee 100644 --- a/WebCore/platform/gtk/WidgetGtk.cpp +++ b/WebCore/platform/gtk/WidgetGtk.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com - * Copyright (C) 2007 Holger Hans Peter Freyther + * Copyright (C) 2007, 2009 Holger Hans Peter Freyther * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,7 +33,6 @@ #include "GraphicsContext.h" #include "HostWindow.h" #include "IntRect.h" -#include "NotImplemented.h" #include "RenderObject.h" #include <gdk/gdk.h> @@ -99,9 +98,19 @@ void Widget::paint(GraphicsContext* context, const IntRect& rect) { } -void Widget::setIsSelected(bool) +void Widget::setIsSelected(bool isSelected) { - notImplemented(); + if (!platformWidget()) + return; + + // See if the platformWidget has a webkit-widget-is-selected property + // and set it afterwards. + GParamSpec* spec = g_object_class_find_property(G_OBJECT_GET_CLASS(platformWidget()), + "webkit-widget-is-selected"); + if (!spec) + return; + + g_object_set(platformWidget(), "webkit-widget-is-selected", isSelected, NULL); } IntRect Widget::frameRect() const diff --git a/WebCore/platform/gtk/gtk2drawing.c b/WebCore/platform/gtk/gtk2drawing.c index dd46e74..1f62c96 100644 --- a/WebCore/platform/gtk/gtk2drawing.c +++ b/WebCore/platform/gtk/gtk2drawing.c @@ -49,6 +49,8 @@ #include <string.h> #include "gtkdrawing.h" +#include "Assertions.h" + #include <math.h> #define XTHICKNESS(style) (style->xthickness) @@ -56,6 +58,7 @@ #define WINDOW_IS_MAPPED(window) ((window) && GDK_IS_WINDOW(window) && gdk_window_is_visible(window)) static GtkWidget* gProtoWindow; +static GtkWidget* gProtoLayout; static GtkWidget* gButtonWidget; static GtkWidget* gToggleButtonWidget; static GtkWidget* gButtonArrowWidget; @@ -101,7 +104,6 @@ static GtkWidget* gScrolledWindowWidget; static style_prop_t style_prop_func; static gboolean have_arrow_scaling; -static gboolean have_2_10; static gboolean is_initialized; /* Because we have such an unconventional way of drawing widgets, signal to the GTK theme engine @@ -134,14 +136,13 @@ ensure_window_widget() static gint setup_widget_prototype(GtkWidget* widget) { - static GtkWidget* protoLayout; ensure_window_widget(); - if (!protoLayout) { - protoLayout = gtk_fixed_new(); - gtk_container_add(GTK_CONTAINER(gProtoWindow), protoLayout); + if (!gProtoLayout) { + gProtoLayout = gtk_fixed_new(); + gtk_container_add(GTK_CONTAINER(gProtoWindow), gProtoLayout); } - gtk_container_add(GTK_CONTAINER(protoLayout), widget); + gtk_container_add(GTK_CONTAINER(gProtoLayout), widget); gtk_widget_realize(widget); g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); return MOZ_GTK_SUCCESS; @@ -409,8 +410,7 @@ moz_gtk_get_combo_box_entry_arrow(GtkWidget *widget, gpointer client_data) g_object_add_weak_pointer(G_OBJECT(widget), (gpointer) &gComboBoxEntryArrowWidget); gtk_widget_realize(widget); - g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", - GINT_TO_POINTER(TRUE)); + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); } } @@ -502,8 +502,7 @@ ensure_toolbar_widget() gToolbarWidget = gtk_toolbar_new(); gtk_container_add(GTK_CONTAINER(gHandleBoxWidget), gToolbarWidget); gtk_widget_realize(gToolbarWidget); - g_object_set_data(G_OBJECT(gToolbarWidget), "transparent-bg-hint", - GINT_TO_POINTER(TRUE)); + g_object_set_data(G_OBJECT(gToolbarWidget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); } return MOZ_GTK_SUCCESS; } @@ -710,17 +709,17 @@ ensure_tree_header_cell_widget() gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), firstTreeViewColumn); gMiddleTreeViewColumn = gtk_tree_view_column_new(); - gtk_tree_view_column_set_title(GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn), "M"); + gtk_tree_view_column_set_title(gMiddleTreeViewColumn, "M"); gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), - GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn)); + gMiddleTreeViewColumn); lastTreeViewColumn = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(lastTreeViewColumn, "M"); gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), lastTreeViewColumn); /* Use the middle column's header for our button */ - gTreeHeaderCellWidget = GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn)->button; - gTreeHeaderSortArrowWidget = GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn)->arrow; + gTreeHeaderCellWidget = gMiddleTreeViewColumn->button; + gTreeHeaderSortArrowWidget = gMiddleTreeViewColumn->arrow; g_object_set_data(G_OBJECT(gTreeHeaderCellWidget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); g_object_set_data(G_OBJECT(gTreeHeaderSortArrowWidget), @@ -880,9 +879,6 @@ moz_gtk_init() have_arrow_scaling = (gtk_major_version > 2 || (gtk_major_version == 2 && gtk_minor_version >= 12)); - have_2_10 = (gtk_major_version > 2 || - (gtk_major_version == 2 && gtk_minor_version >= 10)); - /* Add style property to GtkEntry. * Adding the style property to the normal GtkEntry class means that it * will work without issues inside GtkComboBox and for Spinbuttons. */ @@ -953,10 +949,9 @@ gint moz_gtk_button_get_inner_border(GtkWidget* widget, GtkBorder* inner_border) { static const GtkBorder default_inner_border = { 1, 1, 1, 1 }; - GtkBorder *tmp_border = NULL; + GtkBorder *tmp_border; - if (have_2_10) - gtk_widget_style_get (widget, "inner-border", &tmp_border, NULL); + gtk_widget_style_get (widget, "inner-border", &tmp_border, NULL); if (tmp_border) { *inner_border = *tmp_border; @@ -971,8 +966,8 @@ moz_gtk_button_get_inner_border(GtkWidget* widget, GtkBorder* inner_border) static gint moz_gtk_toggle_paint(GdkDrawable* drawable, GdkRectangle* rect, GdkRectangle* cliprect, GtkWidgetState* state, - gboolean selected, gboolean isradio, - GtkTextDirection direction) + gboolean selected, gboolean inconsistent, + gboolean isradio, GtkTextDirection direction) { GtkStateType state_type = ConvertGtkState(state); GtkShadowType shadow_type = (selected)?GTK_SHADOW_IN:GTK_SHADOW_OUT; @@ -990,6 +985,12 @@ moz_gtk_toggle_paint(GdkDrawable* drawable, GdkRectangle* rect, w = gCheckboxWidget; } + // "GetMinimumWidgetSize was ignored" + // FIXME: This assert causes a build failure in WebKitGTK+ debug + // builds, because it uses 'false' in its definition. We may want + // to force this file to be built with g++, by renaming it. + // ASSERT(rect->width == indicator_size); + /* * vertically center in the box, since XUL sometimes ignores our * GetMinimumWidgetSize in the vertical dimension @@ -1022,6 +1023,17 @@ moz_gtk_toggle_paint(GdkDrawable* drawable, GdkRectangle* rect, } } else { + /* + * 'indeterminate' type on checkboxes. In GTK, the shadow type + * must also be changed for the state to be drawn. + */ + if (inconsistent) { + gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gCheckboxWidget), TRUE); + shadow_type = GTK_SHADOW_ETCHED_IN; + } else { + gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gCheckboxWidget), FALSE); + } + gtk_paint_check(style, drawable, state_type, shadow_type, cliprect, gCheckboxWidget, "checkbutton", x, y, width, height); if (state->focused) { @@ -1490,9 +1502,15 @@ static gint moz_gtk_caret_paint(GdkDrawable* drawable, GdkRectangle* rect, GdkRectangle* cliprect, GtkTextDirection direction) { + GdkRectangle location = *rect; + if (direction == GTK_TEXT_DIR_RTL) { + /* gtk_draw_insertion_cursor ignores location.width */ + location.x = rect->x + rect->width; + } + ensure_entry_widget(); gtk_draw_insertion_cursor(gEntryWidget, drawable, cliprect, - rect, TRUE, direction, FALSE); + &location, TRUE, direction, FALSE); return MOZ_GTK_SUCCESS; } @@ -1538,8 +1556,7 @@ moz_gtk_entry_paint(GdkDrawable* drawable, GdkRectangle* rect, * If the theme is able to cope with transparency, then we can skip pre-filling * and notify the theme it will paint directly on the canvas. */ if (theme_honors_transparency) { - g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", - GINT_TO_POINTER(TRUE)); + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); } else { gdk_draw_rectangle(drawable, style->base_gc[bg_state], TRUE, cliprect->x, cliprect->y, cliprect->width, cliprect->height); @@ -1650,7 +1667,7 @@ moz_gtk_tree_header_cell_paint(GdkDrawable* drawable, GdkRectangle* rect, GdkRectangle* cliprect, GtkWidgetState* state, gboolean isSorted, GtkTextDirection direction) { - gtk_tree_view_column_set_sort_indicator(GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn), + gtk_tree_view_column_set_sort_indicator(gMiddleTreeViewColumn, isSorted); moz_gtk_button_paint(drawable, rect, cliprect, state, GTK_RELIEF_NORMAL, @@ -1742,8 +1759,8 @@ moz_gtk_combo_box_paint(GdkDrawable* drawable, GdkRectangle* rect, gboolean ishtml, GtkTextDirection direction) { GdkRectangle arrow_rect, real_arrow_rect; - gint arrow_size, separator_width = 0; - gboolean wide_separators = FALSE; + gint arrow_size, separator_width; + gboolean wide_separators; GtkStateType state_type = ConvertGtkState(state); GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT; GtkStyle* style; @@ -1786,11 +1803,10 @@ moz_gtk_combo_box_paint(GdkDrawable* drawable, GdkRectangle* rect, style = gComboBoxSeparatorWidget->style; TSOffsetStyleGCs(style, rect->x, rect->y); - if (have_2_10) - gtk_widget_style_get(gComboBoxSeparatorWidget, - "wide-separators", &wide_separators, - "separator-width", &separator_width, - NULL); + gtk_widget_style_get(gComboBoxSeparatorWidget, + "wide-separators", &wide_separators, + "separator-width", &separator_width, + NULL); if (wide_separators) { if (direction == GTK_TEXT_DIR_LTR) @@ -2015,9 +2031,9 @@ moz_gtk_toolbar_separator_paint(GdkDrawable* drawable, GdkRectangle* rect, GtkTextDirection direction) { GtkStyle* style; - gint separator_width = 0; + gint separator_width; gint paint_width; - gboolean wide_separators = FALSE; + gboolean wide_separators; /* Defined as constants in GTK+ 2.10.14 */ const double start_fraction = 0.2; @@ -2028,11 +2044,10 @@ moz_gtk_toolbar_separator_paint(GdkDrawable* drawable, GdkRectangle* rect, style = gToolbarSeparatorWidget->style; - if (have_2_10) - gtk_widget_style_get(gToolbarWidget, - "wide-separators", &wide_separators, - "separator-width", &separator_width, - NULL); + gtk_widget_style_get(gToolbarWidget, + "wide-separators", &wide_separators, + "separator-width", &separator_width, + NULL); TSOffsetStyleGCs(style, rect->x, rect->y); @@ -2423,9 +2438,9 @@ moz_gtk_menu_separator_paint(GdkDrawable* drawable, GdkRectangle* rect, GdkRectangle* cliprect, GtkTextDirection direction) { GtkStyle* style; - gboolean wide_separators = FALSE; - gint separator_height = 0; - guint horizontal_padding = 0; + gboolean wide_separators; + gint separator_height; + guint horizontal_padding; gint paint_height; ensure_menu_separator_widget(); @@ -2433,13 +2448,9 @@ moz_gtk_menu_separator_paint(GdkDrawable* drawable, GdkRectangle* rect, style = gMenuSeparatorWidget->style; - if (have_2_10) - gtk_widget_style_get(gMenuSeparatorWidget, - "wide-separators", &wide_separators, - "separator-height", &separator_height, - NULL); - gtk_widget_style_get(gMenuSeparatorWidget, + "wide-separators", &wide_separators, + "separator-height", &separator_height, "horizontal-padding", &horizontal_padding, NULL); @@ -2687,7 +2698,7 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, /* We need to account for the arrow on the dropdown, so text * doesn't come too close to the arrow, or in some cases spill * into the arrow. */ - gboolean ignored_interior_focus, wide_separators = FALSE; + gboolean ignored_interior_focus, wide_separators; gint focus_width, focus_pad, separator_width; GtkRequisition arrow_req; @@ -2710,11 +2721,10 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, /* If there is no separator, don't try to count its width. */ separator_width = 0; if (gComboBoxSeparatorWidget) { - if (have_2_10) - gtk_widget_style_get(gComboBoxSeparatorWidget, - "wide-separators", &wide_separators, - "separator-width", &separator_width, - NULL); + gtk_widget_style_get(gComboBoxSeparatorWidget, + "wide-separators", &wide_separators, + "separator-width", &separator_width, + NULL); if (!wide_separators) separator_width = @@ -2895,13 +2905,12 @@ moz_gtk_get_combo_box_entry_button_size(gint* width, gint* height) gint moz_gtk_get_tab_scroll_arrow_size(gint* width, gint* height) { - gint arrow_size = 16; + gint arrow_size; ensure_tab_widget(); - if (have_2_10) - gtk_widget_style_get(gTabWidget, - "scroll-arrow-hlength", &arrow_size, - NULL); + gtk_widget_style_get(gTabWidget, + "scroll-arrow-hlength", &arrow_size, + NULL); *height = *width = arrow_size; @@ -2924,22 +2933,18 @@ moz_gtk_get_downarrow_size(gint* width, gint* height) gint moz_gtk_get_toolbar_separator_width(gint* size) { - gboolean wide_separators = FALSE; - gint separator_width = 0; + gboolean wide_separators; + gint separator_width; GtkStyle* style; ensure_toolbar_widget(); style = gToolbarWidget->style; - if (have_2_10) - gtk_widget_style_get(gToolbarWidget, - "wide-separators", &wide_separators, - "separator-width", &separator_width, - NULL); - gtk_widget_style_get(gToolbarWidget, "space-size", size, + "wide-separators", &wide_separators, + "separator-width", &separator_width, NULL); /* Just in case... */ @@ -2973,16 +2978,15 @@ moz_gtk_get_treeview_expander_size(gint* size) gint moz_gtk_get_menu_separator_height(gint *size) { - gboolean wide_separators = FALSE; - gint separator_height = 0; + gboolean wide_separators; + gint separator_height; ensure_menu_separator_widget(); - if (have_2_10) - gtk_widget_style_get(gMenuSeparatorWidget, - "wide-separators", &wide_separators, - "separator-height", &separator_height, - NULL); + gtk_widget_style_get(gMenuSeparatorWidget, + "wide-separators", &wide_separators, + "separator-height", &separator_height, + NULL); if (wide_separators) *size = separator_height + gMenuSeparatorWidget->style->ythickness; @@ -3061,7 +3065,8 @@ moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable, case MOZ_GTK_CHECKBUTTON: case MOZ_GTK_RADIOBUTTON: return moz_gtk_toggle_paint(drawable, rect, cliprect, state, - (gboolean) flags, + !!(flags & MOZ_GTK_WIDGET_CHECKED), + !!(flags & MOZ_GTK_WIDGET_INCONSISTENT), (widget == MOZ_GTK_RADIOBUTTON), direction); break; @@ -3262,6 +3267,7 @@ moz_gtk_shutdown() gtk_widget_destroy(gProtoWindow); gProtoWindow = NULL; + gProtoLayout = NULL; gButtonWidget = NULL; gToggleButtonWidget = NULL; gButtonArrowWidget = NULL; diff --git a/WebCore/platform/gtk/gtkdrawing.h b/WebCore/platform/gtk/gtkdrawing.h index eb6995a..1a33bfb 100644 --- a/WebCore/platform/gtk/gtkdrawing.h +++ b/WebCore/platform/gtk/gtkdrawing.h @@ -110,6 +110,10 @@ typedef gint (*style_prop_t)(GtkStyle*, const gchar*, gint); #define MOZ_GTK_UNKNOWN_WIDGET -1 #define MOZ_GTK_UNSAFE_THEME -2 +/*** checkbox/radio flags ***/ +#define MOZ_GTK_WIDGET_CHECKED 1 +#define MOZ_GTK_WIDGET_INCONSISTENT (1 << 1) + /*** widget type constants ***/ typedef enum { /* Paints a GtkButton. flags is a GtkReliefStyle. */ diff --git a/WebCore/platform/gtk/guriescape.c b/WebCore/platform/gtk/guriescape.c deleted file mode 100644 index 0792587..0000000 --- a/WebCore/platform/gtk/guriescape.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (C) 2008 Collabora, Ltd. - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * Copyright (C) 1997-2000 The GLib Team - * Copyright (C) 2006-2007 Red Hat, 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. - */ - -#include "config.h" -#include "guriescape.h" - -#include <string.h> - -#if !PLATFORM(WIN_OS) && !GLIB_CHECK_VERSION(2,16,0) - -/* is_valid, gunichar_ok and g_string_append_uri_escaped were copied for glib/gstring.c - * in the glib package. - * - * Original copyright: - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * - * Modified by the GLib Team and others 1997-2000. See the AUTHORS - * file for a list of people on the GLib Team. See the ChangeLog - * files for a list of changes. These files are distributed with - * GLib at ftp://ftp.gtk.org/pub/gtk/. - * - * Please don't change the indentation so it's easier to update these functions - * if they are changed in glib. - */ -static gboolean -is_valid (char c, const char *reserved_chars_allowed) -{ - if (g_ascii_isalnum (c) || - c == '-' || - c == '.' || - c == '_' || - c == '~') - return TRUE; - - if (reserved_chars_allowed && - strchr (reserved_chars_allowed, c) != NULL) - return TRUE; - - return FALSE; -} - -static gboolean -gunichar_ok (gunichar c) -{ - return - (c != (gunichar) -2) && - (c != (gunichar) -1); -} - -static GString * -_webcore_g_string_append_uri_escaped (GString *string, - const char *unescaped, - const char *reserved_chars_allowed, - gboolean allow_utf8) -{ - unsigned char c; - const char *end; - static const gchar hex[16] = "0123456789ABCDEF"; - - g_return_val_if_fail (string != NULL, NULL); - g_return_val_if_fail (unescaped != NULL, NULL); - - end = unescaped + strlen (unescaped); - - while ((c = *unescaped) != 0) - { - if (c >= 0x80 && allow_utf8 && - gunichar_ok (g_utf8_get_char_validated (unescaped, end - unescaped))) - { - int len = g_utf8_skip [c]; - g_string_append_len (string, unescaped, len); - unescaped += len; - } - else if (is_valid (c, reserved_chars_allowed)) - { - g_string_append_c (string, c); - unescaped++; - } - else - { - g_string_append_c (string, '%'); - g_string_append_c (string, hex[((guchar)c) >> 4]); - g_string_append_c (string, hex[((guchar)c) & 0xf]); - unescaped++; - } - } - - return string; -} - -/* g_uri_escape_string, unescape_character, g_uri_unescape_segment and - * g_uri_unescape_string were copied for glib/gurifuncs.c in the glib package - * and prefixed with _webcore (if necessary) to avoid exporting a symbol with - * the "g_" prefix. - * - * Original copyright: - * Copyright (C) 2006-2007 Red Hat, Inc. - * Author: Alexander Larsson <alexl@redhat.com> - * - * Please don't change the indentation so it's easier to update this function - * if it's changed in glib. - */ -char * -_webcore_g_uri_escape_string (const char *unescaped, - const char *reserved_chars_allowed, - gboolean allow_utf8) -{ - GString *s; - - g_return_val_if_fail (unescaped != NULL, NULL); - - s = g_string_sized_new (strlen (unescaped) + 10); - - _webcore_g_string_append_uri_escaped (s, unescaped, reserved_chars_allowed, allow_utf8); - - return g_string_free (s, FALSE); -} - -static int -unescape_character (const char *scanner) -{ - int first_digit; - int second_digit; - - first_digit = g_ascii_xdigit_value (*scanner++); - if (first_digit < 0) - return -1; - - second_digit = g_ascii_xdigit_value (*scanner++); - if (second_digit < 0) - return -1; - - return (first_digit << 4) | second_digit; -} - - - -static char * -_webcore_g_uri_unescape_segment (const char *escaped_string, - const char *escaped_string_end, - const char *illegal_characters) -{ - const char *in; - char *out, *result; - gint character; - - if (escaped_string == NULL) - return NULL; - - if (escaped_string_end == NULL) - escaped_string_end = escaped_string + strlen (escaped_string); - - result = g_malloc (escaped_string_end - escaped_string + 1); - - out = result; - for (in = escaped_string; in < escaped_string_end; in++) - { - character = *in; - - if (*in == '%') - { - in++; - - if (escaped_string_end - in < 2) - { - /* Invalid escaped char (to short) */ - g_free (result); - return NULL; - } - - character = unescape_character (in); - - /* Check for an illegal character. We consider '\0' illegal here. */ - if (character <= 0 || - (illegal_characters != NULL && - strchr (illegal_characters, (char)character) != NULL)) - { - g_free (result); - return NULL; - } - - in++; /* The other char will be eaten in the loop header */ - } - *out++ = (char)character; - } - - *out = '\0'; - - return result; -} - - -char * -_webcore_g_uri_unescape_string (const char *escaped_string, - const char *illegal_characters) -{ - return _webcore_g_uri_unescape_segment (escaped_string, NULL, illegal_characters); -} - -#endif /* #if !PLATFORM(WIN_OS) && !GLIB_CHECK_VERSION(2,16,0) */ diff --git a/WebCore/platform/gtk/guriescape.h b/WebCore/platform/gtk/guriescape.h deleted file mode 100644 index 8c6662a..0000000 --- a/WebCore/platform/gtk/guriescape.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2008 Collabora, Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef guriescape_h -#define guriescape_h - -#include <glib.h> -#include <wtf/Platform.h> - -G_BEGIN_DECLS - -#if !PLATFORM(WIN_OS) && !GLIB_CHECK_VERSION(2,16,0) - -#define g_uri_escape_string _webcore_g_uri_escape_string -#define g_uri_unescape_string _webcore_g_uri_unescape_string - -char *_webcore_g_uri_escape_string (const char *unescaped, - const char *reserved_chars_allowed, - gboolean allow_utf8); - -char *_webcore_g_uri_unescape_string (const char *escaped_string, - const char *illegal_characters); - -#endif - -G_END_DECLS - -#endif /* guriescape_h */ diff --git a/WebCore/platform/image-decoders/ImageDecoder.h b/WebCore/platform/image-decoders/ImageDecoder.h index 17756ac..ca27b37 100644 --- a/WebCore/platform/image-decoders/ImageDecoder.h +++ b/WebCore/platform/image-decoders/ImageDecoder.h @@ -23,8 +23,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef IMAGE_DECODER_H_ -#define IMAGE_DECODER_H_ +#ifndef ImageDecoder_h +#define ImageDecoder_h #include "IntRect.h" #include "ImageSource.h" @@ -34,136 +34,145 @@ namespace WebCore { -typedef Vector<unsigned> RGBA32Array; - -// The RGBA32Buffer object represents the decoded image data in RGBA32 format. This buffer is what all -// decoders write a single frame into. Frames are then instantiated for drawing by being handed this buffer. -class RGBA32Buffer -{ -public: - enum FrameStatus { FrameEmpty, FramePartial, FrameComplete }; - enum FrameDisposalMethod { - // If you change the numeric values of these, make sure you audit all - // users, as some users may cast raw values to/from these constants. - DisposeNotSpecified = 0, // Leave frame in framebuffer - DisposeKeep = 1, // Leave frame in framebuffer - DisposeOverwriteBgcolor = 2, // Clear frame to transparent - DisposeOverwritePrevious = 3, // Clear frame to previous framebuffer contents - }; + typedef Vector<unsigned> RGBA32Array; + + // The RGBA32Buffer object represents the decoded image data in RGBA32 format. This buffer is what all + // decoders write a single frame into. Frames are then instantiated for drawing by being handed this buffer. + class RGBA32Buffer { + public: + enum FrameStatus { FrameEmpty, FramePartial, FrameComplete }; + + enum FrameDisposalMethod { + // If you change the numeric values of these, make sure you audit all + // users, as some users may cast raw values to/from these constants. + DisposeNotSpecified, // Leave frame in framebuffer + DisposeKeep, // Leave frame in framebuffer + DisposeOverwriteBgcolor, // Clear frame to transparent + DisposeOverwritePrevious, // Clear frame to previous framebuffer contents + }; + + RGBA32Buffer() + : m_height(0) + , m_status(FrameEmpty) + , m_duration(0) + , m_disposalMethod(DisposeNotSpecified) + , m_hasAlpha(false) + { + } + + void clear() { + m_bytes.clear(); + m_status = FrameEmpty; + // NOTE: Do not reset other members here; clearFrameBufferCache() calls + // this to free the bitmap data, but other functions like + // initFrameBuffer() and frameComplete() may still need to read other + // metadata out of this frame later. + } - RGBA32Buffer() : m_height(0), m_status(FrameEmpty), m_duration(0), - m_disposalMethod(DisposeNotSpecified), m_hasAlpha(false) - {} - - void clear() { - m_bytes.clear(); - m_status = FrameEmpty; - // NOTE: Do not reset other members here; clearFrameBufferCache() calls - // this to free the bitmap data, but other functions like - // initFrameBuffer() and frameComplete() may still need to read other - // metadata out of this frame later. - } - - const RGBA32Array& bytes() const { return m_bytes; } - RGBA32Array& bytes() { return m_bytes; } - const IntRect& rect() const { return m_rect; } - unsigned height() const { return m_height; } - FrameStatus status() const { return m_status; } - unsigned duration() const { return m_duration; } - FrameDisposalMethod disposalMethod() const { return m_disposalMethod; } - bool hasAlpha() const { return m_hasAlpha; } - - void setRect(const IntRect& r) { m_rect = r; } - void ensureHeight(unsigned rowIndex) { if (rowIndex > m_height) m_height = rowIndex; } - void setStatus(FrameStatus s) { m_status = s; } - void setDuration(unsigned duration) { m_duration = duration; } - void setDisposalMethod(FrameDisposalMethod method) { m_disposalMethod = method; } - void setHasAlpha(bool alpha) { m_hasAlpha = alpha; } - - static void setRGBA(unsigned& pos, unsigned r, unsigned g, unsigned b, unsigned a) - { - // We store this data pre-multiplied. - if (a == 0) - pos = 0; - else { - if (a < 255) { - float alphaPercent = a / 255.0f; - r = static_cast<unsigned>(r * alphaPercent); - g = static_cast<unsigned>(g * alphaPercent); - b = static_cast<unsigned>(b * alphaPercent); + const RGBA32Array& bytes() const { return m_bytes; } + RGBA32Array& bytes() { return m_bytes; } + const IntRect& rect() const { return m_rect; } + unsigned height() const { return m_height; } + FrameStatus status() const { return m_status; } + unsigned duration() const { return m_duration; } + FrameDisposalMethod disposalMethod() const { return m_disposalMethod; } + bool hasAlpha() const { return m_hasAlpha; } + + void setRect(const IntRect& r) { m_rect = r; } + void ensureHeight(unsigned rowIndex) { if (rowIndex > m_height) m_height = rowIndex; } + void setStatus(FrameStatus s) { m_status = s; } + void setDuration(unsigned duration) { m_duration = duration; } + void setDisposalMethod(FrameDisposalMethod method) { m_disposalMethod = method; } + void setHasAlpha(bool alpha) { m_hasAlpha = alpha; } + + static void setRGBA(unsigned& pos, unsigned r, unsigned g, unsigned b, unsigned a) + { + // We store this data pre-multiplied. + if (a == 0) + pos = 0; + else { + if (a < 255) { + float alphaPercent = a / 255.0f; + r = static_cast<unsigned>(r * alphaPercent); + g = static_cast<unsigned>(g * alphaPercent); + b = static_cast<unsigned>(b * alphaPercent); + } + pos = (a << 24 | r << 16 | g << 8 | b); } - pos = (a << 24 | r << 16 | g << 8 | b); } - } - -private: - RGBA32Array m_bytes; - IntRect m_rect; // The rect of the original specified frame within the overall buffer. - // This will always just be the entire buffer except for GIF frames - // whose original rect was smaller than the overall image size. - unsigned m_height; // The height (the number of rows we've fully decoded). - FrameStatus m_status; // Whether or not this frame is completely finished decoding. - unsigned m_duration; // The animation delay. - FrameDisposalMethod m_disposalMethod; // What to do with this frame's data when initializing the next frame. - bool m_hasAlpha; // Whether or not any of the pixels in the buffer have transparency. -}; - -// 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 -{ -public: - ImageDecoder() :m_sizeAvailable(false), m_failed(false) {} - virtual ~ImageDecoder() {} - - // The the filename extension usually associated with an undecoded image of this type. - virtual String filenameExtension() const = 0; - - // All specific decoder plugins must do something with the data they are given. - virtual void setData(SharedBuffer* data, bool allDataReceived) { m_data = data; } - - // Whether or not the size information has been decoded yet. - virtual bool isSizeAvailable() const = 0; - - // Requests the size. - virtual IntSize size() const { return m_size; } - - // The total number of frames for the image. Classes that support multiple frames - // will scan the image data for the answer if they need to (without necessarily - // decoding all of the individual frames). - virtual int frameCount() { return 1; } - - // The number of repetitions to perform for an animation loop. - virtual int repetitionCount() const { return cAnimationNone; } - - // Called to obtain the RGBA32Buffer full of decoded data for rendering. The - // decoder plugin will decode as much of the frame as it can before handing - // back the buffer. - virtual RGBA32Buffer* frameBufferAtIndex(size_t index) = 0; - - // Whether or not the underlying image format even supports alpha transparency. - virtual bool supportsAlpha() const { return true; } - - bool failed() const { return m_failed; } - void setFailed() { m_failed = true; } - - // Wipe out frames in the frame buffer cache before |clearBeforeFrame|, - // assuming this can be done without breaking decoding. Different decoders - // place different restrictions on what frames are safe to destroy, so this - // is left to them to implement. - // For convenience's sake, we provide a default (empty) implementation, - // since in practice only GIFs will ever use this. - virtual void clearFrameBufferCache(size_t clearBeforeFrame) { } - -protected: - RefPtr<SharedBuffer> m_data; // The encoded data. - Vector<RGBA32Buffer> m_frameBufferCache; - bool m_sizeAvailable; - mutable bool m_failed; - IntSize m_size; -}; - -} + + private: + RGBA32Array m_bytes; + IntRect m_rect; // The rect of the original specified frame within the overall buffer. + // This will always just be the entire buffer except for GIF frames + // whose original rect was smaller than the overall image size. + unsigned m_height; // The height (the number of rows we've fully decoded). + FrameStatus m_status; // Whether or not this frame is completely finished decoding. + unsigned m_duration; // The animation delay. + FrameDisposalMethod m_disposalMethod; // What to do with this frame's data when initializing the next frame. + bool m_hasAlpha; // Whether or not any of the pixels in the buffer have transparency. + }; + + // 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 { + public: + ImageDecoder() + : m_sizeAvailable(false) + , m_failed(false) + { + } + + virtual ~ImageDecoder() {} + + // The the filename extension usually associated with an undecoded image of this type. + virtual String filenameExtension() const = 0; + + // All specific decoder plugins must do something with the data they are given. + virtual void setData(SharedBuffer* data, bool allDataReceived) { m_data = data; } + + // Whether or not the size information has been decoded yet. + virtual bool isSizeAvailable() const = 0; + + // Requests the size. + virtual IntSize size() const { return m_size; } + + // The total number of frames for the image. Classes that support multiple frames + // will scan the image data for the answer if they need to (without necessarily + // decoding all of the individual frames). + virtual int frameCount() { return 1; } + + // The number of repetitions to perform for an animation loop. + virtual int repetitionCount() const { return cAnimationNone; } + + // Called to obtain the RGBA32Buffer full of decoded data for rendering. The + // decoder plugin will decode as much of the frame as it can before handing + // back the buffer. + virtual RGBA32Buffer* frameBufferAtIndex(size_t index) = 0; + + // Whether or not the underlying image format even supports alpha transparency. + virtual bool supportsAlpha() const { return true; } + + bool failed() const { return m_failed; } + void setFailed() { m_failed = true; } + + // Wipe out frames in the frame buffer cache before |clearBeforeFrame|, + // assuming this can be done without breaking decoding. Different decoders + // place different restrictions on what frames are safe to destroy, so this + // is left to them to implement. + // For convenience's sake, we provide a default (empty) implementation, + // since in practice only GIFs will ever use this. + virtual void clearFrameBufferCache(size_t clearBeforeFrame) { } + + protected: + RefPtr<SharedBuffer> m_data; // The encoded data. + Vector<RGBA32Buffer> m_frameBufferCache; + bool m_sizeAvailable; + mutable bool m_failed; + IntSize m_size; + }; + +} // namespace WebCore #endif diff --git a/WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp b/WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp index cfc141c..3b90bdc 100644 --- a/WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp +++ b/WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp @@ -26,8 +26,6 @@ #include "config.h" #include "BMPImageDecoder.h" -#if PLATFORM(CAIRO) || PLATFORM(QT) || PLATFORM(WX) - namespace WebCore { @@ -41,6 +39,4 @@ RGBA32Buffer* BMPImageDecoder::frameBufferAtIndex(size_t index) return 0; } -} - -#endif // PLATFORM(CAIRO) +} // namespace WebCore diff --git a/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h b/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h index d850cc7..a2d4b25 100644 --- a/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h +++ b/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h @@ -23,27 +23,26 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef BMP_DECODER_H_ -#define BMP_DECODER_H_ +#ifndef BMPImageDecoder_h +#define BMPImageDecoder_h #include "ImageDecoder.h" namespace WebCore { -class BMPImageReader; + class BMPImageReader; -// This class decodes the BMP image format. -class BMPImageDecoder : public ImageDecoder -{ -public: - virtual String filenameExtension() const { return "bmp"; } + // This class decodes the BMP image format. + class BMPImageDecoder : public ImageDecoder { + public: + virtual String filenameExtension() const { return "bmp"; } - // Whether or not the size information has been decoded yet. - virtual bool isSizeAvailable() const; + // Whether or not the size information has been decoded yet. + virtual bool isSizeAvailable() const; - virtual RGBA32Buffer* frameBufferAtIndex(size_t index); -}; + virtual RGBA32Buffer* frameBufferAtIndex(size_t index); + }; -} +} // namespace WebCore #endif diff --git a/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp b/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp index 5b4b675..62d8b5b 100644 --- a/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp +++ b/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp @@ -27,17 +27,14 @@ #include "GIFImageDecoder.h" #include "GIFImageReader.h" -#if PLATFORM(CAIRO) || PLATFORM(QT) || PLATFORM(WX) - namespace WebCore { -class GIFImageDecoderPrivate -{ +class GIFImageDecoderPrivate { public: GIFImageDecoderPrivate(GIFImageDecoder* decoder = 0) : m_reader(decoder) + , m_readOffset(0) { - m_readOffset = 0; } ~GIFImageDecoderPrivate() @@ -45,11 +42,11 @@ public: m_reader.close(); } - bool decode(const Vector<char>& data, + bool decode(SharedBuffer* data, GIFImageDecoder::GIFQuery query = GIFImageDecoder::GIFFullQuery, unsigned int haltFrame = -1) { - return m_reader.read((const unsigned char*)data.data() + m_readOffset, data.size() - m_readOffset, + return m_reader.read((const unsigned char*)data->data() + m_readOffset, data->size() - m_readOffset, query, haltFrame); } @@ -61,7 +58,8 @@ public: bool isTransparent() const { return m_reader.frame_reader->is_transparent; } - void getColorMap(unsigned char*& map, unsigned& size) const { + void getColorMap(unsigned char*& map, unsigned& size) const + { if (m_reader.frame_reader->is_local_colormap_defined) { map = m_reader.frame_reader->local_colormap; size = (unsigned)m_reader.frame_reader->local_colormap_size; @@ -86,8 +84,11 @@ private: }; GIFImageDecoder::GIFImageDecoder() -: m_frameCountValid(true), m_repetitionCount(cAnimationLoopOnce), m_reader(0) -{} + : m_frameCountValid(true) + , m_repetitionCount(cAnimationLoopOnce) + , m_reader(0) +{ +} GIFImageDecoder::~GIFImageDecoder() { @@ -139,7 +140,10 @@ int GIFImageDecoder::frameCount() // state, but for now we just crawl all the data. Note that this is no worse than what // ImageIO does on Mac right now (it also crawls all the data again). GIFImageDecoderPrivate reader; - reader.decode(m_data->buffer(), GIFFrameCountQuery); + // This function may fail, but we want to keep any partial data it may + // have decoded, so don't mark it is invalid. If there is an overflow + // or some serious error, m_failed will have gotten set for us. + reader.decode(m_data.get(), GIFFrameCountQuery); m_frameCountValid = true; m_frameBufferCache.resize(reader.frameCount()); } @@ -173,13 +177,12 @@ int GIFImageDecoder::repetitionCount() const RGBA32Buffer* GIFImageDecoder::frameBufferAtIndex(size_t index) { - if (index >= frameCount()) + if (index >= static_cast<size_t>(frameCount())) return 0; RGBA32Buffer& frame = m_frameBufferCache[index]; if (frame.status() != RGBA32Buffer::FrameComplete && m_reader) - // Decode this frame. - decode(GIFFullQuery, index+1); + decode(GIFFullQuery, index + 1); // Decode this frame. return &frame; } @@ -239,7 +242,7 @@ void GIFImageDecoder::decode(GIFQuery query, unsigned haltAtFrame) const if (m_failed) return; - m_failed = !m_reader->decode(m_data->buffer(), query, haltAtFrame); + m_failed = !m_reader->decode(m_data.get(), query, haltAtFrame); if (m_failed) { delete m_reader; @@ -266,10 +269,10 @@ void GIFImageDecoder::initFrameBuffer(unsigned frameIndex) m_reader->frameWidth(), m_reader->frameHeight()); // Make sure the frameRect doesn't extend past the bottom-right of the buffer. - if (frameRect.right() > m_size.width()) - frameRect.setWidth(m_size.width() - m_reader->frameXOffset()); - if (frameRect.bottom() > m_size.height()) - frameRect.setHeight(m_size.height() - m_reader->frameYOffset()); + if (frameRect.right() > size().width()) + frameRect.setWidth(size().width() - m_reader->frameXOffset()); + if (frameRect.bottom() > size().height()) + frameRect.setHeight(size().height() - m_reader->frameYOffset()); RGBA32Buffer* const buffer = &m_frameBufferCache[frameIndex]; buffer->setRect(frameRect); @@ -287,14 +290,14 @@ void GIFImageDecoder::initFrameBuffer(unsigned frameIndex) // first frame specifies this method, it will get treated like // DisposeOverwriteBgcolor below and reset to a completely empty image.) const RGBA32Buffer* prevBuffer = &m_frameBufferCache[--frameIndex]; - ASSERT(prevBuffer->status() == RGBA32Buffer::FrameComplete); RGBA32Buffer::FrameDisposalMethod prevMethod = prevBuffer->disposalMethod(); - while ((frameIndex > 0) && - (prevMethod == RGBA32Buffer::DisposeOverwritePrevious)) { + while ((frameIndex > 0) + && (prevMethod == RGBA32Buffer::DisposeOverwritePrevious)) { prevBuffer = &m_frameBufferCache[--frameIndex]; prevMethod = prevBuffer->disposalMethod(); } + ASSERT(prevBuffer->status() == RGBA32Buffer::FrameComplete); if ((prevMethod == RGBA32Buffer::DisposeNotSpecified) || (prevMethod == RGBA32Buffer::DisposeKeep)) { @@ -305,8 +308,8 @@ void GIFImageDecoder::initFrameBuffer(unsigned frameIndex) // We want to clear the previous frame to transparent, without // affecting pixels in the image outside of the frame. const IntRect& prevRect = prevBuffer->rect(); - if ((frameIndex == 0) || - prevRect.contains(IntRect(IntPoint(0, 0), m_size))) { + if ((frameIndex == 0) + || prevRect.contains(IntRect(IntPoint(0, 0), size()))) { // Clearing the first frame, or a frame the size of the whole // image, results in a completely empty image. prepEmptyFrameBuffer(buffer); @@ -321,7 +324,7 @@ void GIFImageDecoder::initFrameBuffer(unsigned frameIndex) buffer->setRGBA(*(currentRow + x), 0, 0, 0, 0); } if ((prevRect.width() > 0) && (prevRect.height() > 0)) - buffer->setHasAlpha(true); + buffer->setHasAlpha(true); } } } @@ -335,7 +338,7 @@ void GIFImageDecoder::initFrameBuffer(unsigned frameIndex) void GIFImageDecoder::prepEmptyFrameBuffer(RGBA32Buffer* buffer) const { - buffer->bytes().resize(m_size.width() * m_size.height()); + buffer->bytes().resize(size().width() * size().height()); buffer->bytes().fill(0); buffer->setHasAlpha(true); } @@ -353,8 +356,8 @@ void GIFImageDecoder::haveDecodedRow(unsigned frameIndex, initFrameBuffer(frameIndex); // Do nothing for bogus data. - if (rowBuffer == 0 || static_cast<int>(m_reader->frameYOffset() + rowNumber) >= m_size.height()) - return; + if (rowBuffer == 0 || static_cast<int>(m_reader->frameYOffset() + rowNumber) >= size().height()) + return; unsigned colorMapSize; unsigned char* colorMap; @@ -369,12 +372,12 @@ void GIFImageDecoder::haveDecodedRow(unsigned frameIndex, // within the overall image. The rows we are decoding are within this // sub-rectangle. This means that if the GIF frame's sub-rectangle is (x,y,w,h) then row 0 is really row // y, and each row goes from x to x+w. - unsigned dstPos = (m_reader->frameYOffset() + rowNumber) * m_size.width() + m_reader->frameXOffset(); + unsigned dstPos = (m_reader->frameYOffset() + rowNumber) * size().width() + m_reader->frameXOffset(); unsigned* dst = buffer.bytes().data() + dstPos; - unsigned* dstEnd = dst + m_size.width() - m_reader->frameXOffset(); + unsigned* dstEnd = dst + size().width() - m_reader->frameXOffset(); unsigned* currDst = dst; unsigned char* currentRowByte = rowBuffer; - + while (currentRowByte != rowEnd && currDst < dstEnd) { if ((!m_reader->isTransparent() || *currentRowByte != m_reader->transparentPixel()) && *currentRowByte < colorMapSize) { unsigned colorIndex = *currentRowByte * 3; @@ -401,14 +404,14 @@ void GIFImageDecoder::haveDecodedRow(unsigned frameIndex, if (repeatCount > 1) { // Copy the row |repeatCount|-1 times. unsigned num = currDst - dst; - unsigned size = num * sizeof(unsigned); - unsigned width = m_size.width(); - unsigned* end = buffer.bytes().data() + width * m_size.height(); + unsigned data_size = num * sizeof(unsigned); + unsigned width = size().width(); + unsigned* end = buffer.bytes().data() + width * size().height(); currDst = dst + width; for (unsigned i = 1; i < repeatCount; i++) { if (currDst + num > end) // Protect against a buffer overrun from a bogus repeatCount. break; - memcpy(currDst, dst, size); + memcpy(currDst, dst, data_size); currDst += width; } } @@ -434,9 +437,9 @@ void GIFImageDecoder::frameComplete(unsigned frameIndex, unsigned frameDuration, if (!m_currentBufferSawAlpha) { // The whole frame was non-transparent, so it's possible that the entire // resulting buffer was non-transparent, and we can setHasAlpha(false). - if (buffer.rect().contains(IntRect(IntPoint(0, 0), m_size))) { + if (buffer.rect().contains(IntRect(IntPoint(0, 0), size()))) buffer.setHasAlpha(false); - } else if (frameIndex > 0) { + else if (frameIndex > 0) { // Tricky case. This frame does not have alpha only if everywhere // outside its rect doesn't have alpha. To know whether this is // true, we check the start state of the frame -- if it doesn't have @@ -446,9 +449,8 @@ void GIFImageDecoder::frameComplete(unsigned frameIndex, unsigned frameDuration, // don't affect the start state of this frame) the same way we do in // initFrameBuffer(). const RGBA32Buffer* prevBuffer = &m_frameBufferCache[--frameIndex]; - while ((frameIndex > 0) && - (prevBuffer->disposalMethod() == - RGBA32Buffer::DisposeOverwritePrevious)) + while ((frameIndex > 0) + && (prevBuffer->disposalMethod() == RGBA32Buffer::DisposeOverwritePrevious)) prevBuffer = &m_frameBufferCache[--frameIndex]; // Now, if we're at a DisposeNotSpecified or DisposeKeep frame, then @@ -459,10 +461,8 @@ void GIFImageDecoder::frameComplete(unsigned frameIndex, unsigned frameDuration, // The only remaining case is a DisposeOverwriteBgcolor frame. If // it had no alpha, and its rect is contained in the current frame's // rect, we know the current frame has no alpha. - if ((prevBuffer->disposalMethod() == - RGBA32Buffer::DisposeOverwriteBgcolor) && - !prevBuffer->hasAlpha() && - buffer.rect().contains(prevBuffer->rect())) + if ((prevBuffer->disposalMethod() == RGBA32Buffer::DisposeOverwriteBgcolor) + && !prevBuffer->hasAlpha() && buffer.rect().contains(prevBuffer->rect())) buffer.setHasAlpha(false); } } @@ -476,6 +476,4 @@ void GIFImageDecoder::gifComplete() m_reader = 0; } -} - -#endif // PLATFORM(CAIRO) +} // namespace WebCore diff --git a/WebCore/platform/image-decoders/gif/GIFImageDecoder.h b/WebCore/platform/image-decoders/gif/GIFImageDecoder.h index 02b43a2..abb55a4 100644 --- a/WebCore/platform/image-decoders/gif/GIFImageDecoder.h +++ b/WebCore/platform/image-decoders/gif/GIFImageDecoder.h @@ -23,70 +23,69 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef GIF_DECODER_H_ -#define GIF_DECODER_H_ +#ifndef GIFImageDecoder_h +#define GIFImageDecoder_h #include "ImageDecoder.h" namespace WebCore { -class GIFImageDecoderPrivate; + class GIFImageDecoderPrivate; -// This class decodes the GIF image format. -class GIFImageDecoder : public ImageDecoder -{ -public: - GIFImageDecoder(); - ~GIFImageDecoder(); + // This class decodes the GIF image format. + class GIFImageDecoder : public ImageDecoder { + public: + GIFImageDecoder(); + ~GIFImageDecoder(); - virtual String filenameExtension() const { return "gif"; } + virtual String filenameExtension() const { return "gif"; } - // Take the data and store it. - virtual void setData(SharedBuffer* data, bool allDataReceived); + // Take the data and store it. + virtual void setData(SharedBuffer* data, bool allDataReceived); - // Whether or not the size information has been decoded yet. - virtual bool isSizeAvailable() const; + // Whether or not the size information has been decoded yet. + virtual bool isSizeAvailable() const; - // The total number of frames for the image. Will scan the image data for the answer - // (without necessarily decoding all of the individual frames). - virtual int frameCount(); + // The total number of frames for the image. Will scan the image data for the answer + // (without necessarily decoding all of the individual frames). + virtual int frameCount(); - // The number of repetitions to perform for an animation loop. - virtual int repetitionCount() const; + // The number of repetitions to perform for an animation loop. + virtual int repetitionCount() const; - virtual RGBA32Buffer* frameBufferAtIndex(size_t index); + virtual RGBA32Buffer* frameBufferAtIndex(size_t index); - virtual void clearFrameBufferCache(size_t clearBeforeFrame); + virtual void clearFrameBufferCache(size_t clearBeforeFrame); - virtual unsigned frameDurationAtIndex(size_t index) { return 0; } + virtual unsigned frameDurationAtIndex(size_t index) { return 0; } - enum GIFQuery { GIFFullQuery, GIFSizeQuery, GIFFrameCountQuery }; + enum GIFQuery { GIFFullQuery, GIFSizeQuery, GIFFrameCountQuery }; - void decode(GIFQuery query, unsigned haltAtFrame) const; + void decode(GIFQuery, unsigned haltAtFrame) const; - // Callbacks from the GIF reader. - void sizeNowAvailable(unsigned width, unsigned height); - void decodingHalted(unsigned bytesLeft); - void haveDecodedRow(unsigned frameIndex, unsigned char* rowBuffer, unsigned char* rowEnd, unsigned rowNumber, - unsigned repeatCount, bool writeTransparentPixels); - void frameComplete(unsigned frameIndex, unsigned frameDuration, RGBA32Buffer::FrameDisposalMethod disposalMethod); - void gifComplete(); + // Callbacks from the GIF reader. + void sizeNowAvailable(unsigned width, unsigned height); + void decodingHalted(unsigned bytesLeft); + void haveDecodedRow(unsigned frameIndex, unsigned char* rowBuffer, unsigned char* rowEnd, unsigned rowNumber, + unsigned repeatCount, bool writeTransparentPixels); + void frameComplete(unsigned frameIndex, unsigned frameDuration, RGBA32Buffer::FrameDisposalMethod disposalMethod); + void gifComplete(); -private: - // Called to initialize the frame buffer with the given index, based on the - // previous frame's disposal method. - void initFrameBuffer(unsigned frameIndex); + private: + // Called to initialize the frame buffer with the given index, based on the + // previous frame's disposal method. + void initFrameBuffer(unsigned frameIndex); - // A helper for initFrameBuffer(), this sets the size of the buffer, and - // fills it with transparent pixels. - void prepEmptyFrameBuffer(RGBA32Buffer* buffer) const; + // A helper for initFrameBuffer(), this sets the size of the buffer, and + // fills it with transparent pixels. + void prepEmptyFrameBuffer(RGBA32Buffer*) const; - bool m_frameCountValid; - bool m_currentBufferSawAlpha; - mutable int m_repetitionCount; - mutable GIFImageDecoderPrivate* m_reader; -}; + bool m_frameCountValid; + bool m_currentBufferSawAlpha; + mutable int m_repetitionCount; + mutable GIFImageDecoderPrivate* m_reader; + }; -} +} // namespace WebCore #endif diff --git a/WebCore/platform/image-decoders/gif/GIFImageReader.cpp b/WebCore/platform/image-decoders/gif/GIFImageReader.cpp index 04347af..95ab40d 100644 --- a/WebCore/platform/image-decoders/gif/GIFImageReader.cpp +++ b/WebCore/platform/image-decoders/gif/GIFImageReader.cpp @@ -78,8 +78,6 @@ mailing address. #include <string.h> #include "GIFImageDecoder.h" -#if PLATFORM(CAIRO) || PLATFORM(QT) || PLATFORM(WX) - using WebCore::GIFImageDecoder; // Define the Mozilla macro setup so that we can leave the macros alone. @@ -939,5 +937,3 @@ bool GIFImageReader::read(const unsigned char *buf, unsigned len, clientptr->decodingHalted(0); return true; } - -#endif // PLATFORM(CAIRO) diff --git a/WebCore/platform/image-decoders/gif/GIFImageReader.h b/WebCore/platform/image-decoders/gif/GIFImageReader.h index 855e6be..f0d127f 100644 --- a/WebCore/platform/image-decoders/gif/GIFImageReader.h +++ b/WebCore/platform/image-decoders/gif/GIFImageReader.h @@ -35,8 +35,8 @@ * * ***** END LICENSE BLOCK ***** */ -#ifndef _GIF_H_ -#define _GIF_H_ +#ifndef GIFImageReader_h +#define GIFImageReader_h // Define ourselves as the clientPtr. Mozilla just hacked their C++ callback class into this old C decoder, // so we will too. @@ -168,7 +168,7 @@ struct GIFImageReader { unsigned screen_width; /* Logical screen width & height */ unsigned screen_height; int global_colormap_size; /* Size of global colormap array. */ - int images_decoded; /* Counts completed frames for animated GIFs */ + unsigned images_decoded; /* Counts completed frames for animated GIFs */ int images_count; /* Counted all frames seen so far (including incomplete frames) */ int loop_count; /* Netscape specific extension block to control the number of animation loops a GIF renders. */ @@ -213,4 +213,3 @@ private: }; #endif - diff --git a/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp b/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp index 019340d..5b1a88f 100644 --- a/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp +++ b/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp @@ -26,8 +26,6 @@ #include "config.h" #include "ICOImageDecoder.h" -#if PLATFORM(CAIRO) || PLATFORM(QT) || PLATFORM(WX) - namespace WebCore { @@ -41,6 +39,4 @@ RGBA32Buffer* ICOImageDecoder::frameBufferAtIndex(size_t index) return 0; } -} - -#endif // PLATFORM(CAIRO) +} // namespace WebCore diff --git a/WebCore/platform/image-decoders/ico/ICOImageDecoder.h b/WebCore/platform/image-decoders/ico/ICOImageDecoder.h index a4f3dbd..56a74c3 100644 --- a/WebCore/platform/image-decoders/ico/ICOImageDecoder.h +++ b/WebCore/platform/image-decoders/ico/ICOImageDecoder.h @@ -23,27 +23,26 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ICO_DECODER_H_ -#define ICO_DECODER_H_ +#ifndef ICOImageDecoder_h +#define ICOImageDecoder_h #include "ImageDecoder.h" namespace WebCore { -class ICOImageReader; + class ICOImageReader; -// This class decodes the ICO and CUR image formats. -class ICOImageDecoder : public ImageDecoder -{ -public: - virtual String filenameExtension() const { return "ico"; } + // This class decodes the ICO and CUR image formats. + class ICOImageDecoder : public ImageDecoder { + public: + virtual String filenameExtension() const { return "ico"; } - // Whether or not the size information has been decoded yet. - virtual bool isSizeAvailable() const; + // Whether or not the size information has been decoded yet. + virtual bool isSizeAvailable() const; - virtual RGBA32Buffer* frameBufferAtIndex(size_t index); -}; + virtual RGBA32Buffer* frameBufferAtIndex(size_t index); + }; -} +} // namespace WebCore #endif diff --git a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp index 44e0e4c..38d90bd 100644 --- a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp +++ b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp @@ -40,30 +40,13 @@ #include <assert.h> #include <stdio.h> -#if PLATFORM(CAIRO) || PLATFORM(QT) || PLATFORM(WX) - -#if COMPILER(MSVC) -// Remove warnings from warning level 4. -#pragma warning(disable : 4611) // warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable - -// if ADDRESS_TAG_BIT is dfined, INT32 has been declared as a typedef in the PlatformSDK (BaseTsd.h), -// so we need to stop jpeglib.h from trying to #define it -// see here for more info: http://www.cygwin.com/ml/cygwin/2004-07/msg01051.html -# if defined(ADDRESS_TAG_BIT) && !defined(XMD_H) -# define XMD_H -# define VTK_JPEG_XMD_H -# endif -#endif // COMPILER(MSVC) - extern "C" { #include "jpeglib.h" } #if COMPILER(MSVC) -# if defined(VTK_JPEG_XMD_H) -# undef VTK_JPEG_XMD_H -# undef XMD_H -# endif +// Remove warnings from warning level 4. +#pragma warning(disable : 4611) // warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable #endif // COMPILER(MSVC) #include <setjmp.h> @@ -482,7 +465,7 @@ bool JPEGImageDecoder::outputScanlines() if (buffer.status() == RGBA32Buffer::FrameEmpty) { // Let's resize our buffer now to the correct width/height. RGBA32Array& bytes = buffer.bytes(); - bytes.resize(m_size.width() * m_size.height()); + bytes.resize(size().width() * size().height()); // Update our status to be partially complete. buffer.setStatus(RGBA32Buffer::FramePartial); @@ -503,7 +486,7 @@ bool JPEGImageDecoder::outputScanlines() if (jpeg_read_scanlines(info, samples, 1) != 1) return false; JSAMPLE *j1 = samples[0]; - for (unsigned i = 0; i < info->output_width; ++i) { + for (unsigned x = 0; x < info->output_width; ++x) { unsigned r = *j1++; unsigned g = *j1++; unsigned b = *j1++; @@ -527,5 +510,3 @@ void JPEGImageDecoder::jpegComplete() } } - -#endif // PLATFORM(CAIRO) diff --git a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h index b4d7b2a..c01bb5e 100644 --- a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h +++ b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h @@ -23,52 +23,51 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JPEG_DECODER_H_ -#define JPEG_DECODER_H_ +#ifndef JPEGImageDecoder_h +#define JPEGImageDecoder_h #include "ImageDecoder.h" namespace WebCore { -class JPEGImageReader; + class JPEGImageReader; -// This class decodes the JPEG image format. -class JPEGImageDecoder : public ImageDecoder -{ -public: - JPEGImageDecoder(); - ~JPEGImageDecoder(); + // This class decodes the JPEG image format. + class JPEGImageDecoder : public ImageDecoder { + public: + JPEGImageDecoder(); + ~JPEGImageDecoder(); - virtual String filenameExtension() const { return "jpg"; } + virtual String filenameExtension() const { return "jpg"; } - // Take the data and store it. - virtual void setData(SharedBuffer* data, bool allDataReceived); + // Take the data and store it. + virtual void setData(SharedBuffer* data, bool allDataReceived); - // Whether or not the size information has been decoded yet. - virtual bool isSizeAvailable() const; + // Whether or not the size information has been decoded yet. + virtual bool isSizeAvailable() const; - virtual RGBA32Buffer* frameBufferAtIndex(size_t index); - - virtual bool supportsAlpha() const { return false; } + virtual RGBA32Buffer* frameBufferAtIndex(size_t index); + + virtual bool supportsAlpha() const { return false; } - void decode(bool sizeOnly = false) const; + void decode(bool sizeOnly = false) const; - JPEGImageReader* reader() { return m_reader; } + JPEGImageReader* reader() { return m_reader; } - void setSize(int width, int height) { - if (!m_sizeAvailable) { - m_sizeAvailable = true; - m_size = IntSize(width, height); + void setSize(int width, int height) { + if (!m_sizeAvailable) { + m_sizeAvailable = true; + m_size = IntSize(width, height); + } } - } - bool outputScanlines(); - void jpegComplete(); + bool outputScanlines(); + void jpegComplete(); -private: - mutable JPEGImageReader* m_reader; -}; + private: + mutable JPEGImageReader* m_reader; + }; -} +} // namespace WebCore #endif diff --git a/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp b/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp index 17143b1..dead8ca 100644 --- a/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp +++ b/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp @@ -40,12 +40,10 @@ #include "png.h" #include "assert.h" -#if PLATFORM(CAIRO) || PLATFORM(QT) || PLATFORM(WX) - #if COMPILER(MSVC) // Remove warnings from warning level 4. #pragma warning(disable : 4611) // warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable -#endif +#endif // COMPILER(MSVC) namespace WebCore { @@ -55,7 +53,7 @@ const double cDefaultGamma = 2.2; const double cInverseGamma = 0.45455; // Protect against large PNGs. See Mozilla's bug #251381 for more info. -const long cMaxPNGSize = 1000000L; +const unsigned long cMaxPNGSize = 1000000UL; // Called if the decoding of the image fails. static void PNGAPI decodingFailed(png_structp png_ptr, png_const_charp error_msg); @@ -78,9 +76,12 @@ class PNGImageReader { public: PNGImageReader(PNGImageDecoder* decoder) - : m_readOffset(0), m_decodingSizeOnly(false), m_interlaceBuffer(0), m_hasAlpha(0) + : m_readOffset(0) + , m_decodingSizeOnly(false) + , m_interlaceBuffer(0) + , m_hasAlpha(0) { - m_png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, decodingFailed, decodingWarning); + m_png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, decodingFailed, decodingWarning); m_info = png_create_info_struct(m_png); png_set_progressive_read_fn(m_png, decoder, headerAvailable, rowAvailable, pngComplete); } @@ -92,8 +93,9 @@ public: void close() { if (m_png && m_info) - png_destroy_read_struct(&m_png, &m_info, 0); + png_destroy_read_struct(&m_png, &m_info, 0); // Will zero the pointers. delete []m_interlaceBuffer; + m_interlaceBuffer = 0; m_readOffset = 0; } @@ -139,7 +141,7 @@ private: }; PNGImageDecoder::PNGImageDecoder() -: m_reader(0) + : m_reader(0) { m_frameBufferCache.resize(1); } @@ -224,6 +226,10 @@ void headerAvailable(png_structp png, png_infop info) static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->headerAvailable(); } +void PNGImageDecoder::decodingFailed() { + m_failed = true; +} + void PNGImageDecoder::headerAvailable() { png_structp png = reader()->pngPtr(); @@ -312,16 +318,16 @@ void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex, if (buffer.status() == RGBA32Buffer::FrameEmpty) { // Let's resize our buffer now to the correct width/height. RGBA32Array& bytes = buffer.bytes(); - bytes.resize(m_size.width() * m_size.height()); + bytes.resize(size().width() * size().height()); // Update our status to be partially complete. buffer.setStatus(RGBA32Buffer::FramePartial); // For PNGs, the frame always fills the entire image. - buffer.setRect(IntRect(0, 0, m_size.width(), m_size.height())); + buffer.setRect(IntRect(0, 0, size().width(), size().height())); if (reader()->pngPtr()->interlaced) - reader()->createInterlaceBuffer((reader()->hasAlpha() ? 4 : 3) * m_size.width() * m_size.height()); + reader()->createInterlaceBuffer((reader()->hasAlpha() ? 4 : 3) * size().width() * size().height()); } if (rowBuffer == 0) @@ -361,17 +367,17 @@ void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex, png_bytep row; png_bytep interlaceBuffer = reader()->interlaceBuffer(); if (interlaceBuffer) { - row = interlaceBuffer + (rowIndex * colorChannels * m_size.width()); + row = interlaceBuffer + (rowIndex * colorChannels * size().width()); png_progressive_combine_row(png, row, rowBuffer); } else row = rowBuffer; // Copy the data into our buffer. - int width = m_size.width(); + int width = size().width(); unsigned* dst = buffer.bytes().data() + rowIndex * width; bool sawAlpha = false; - for (int i = 0; i < width; i++) { + for (int x = 0; x < width; x++) { unsigned red = *row++; unsigned green = *row++; unsigned blue = *row++; @@ -398,6 +404,4 @@ void PNGImageDecoder::pngComplete() buffer.setStatus(RGBA32Buffer::FrameComplete); } -} - -#endif // PLATFORM(CAIRO) +} // namespace WebCore diff --git a/WebCore/platform/image-decoders/png/PNGImageDecoder.h b/WebCore/platform/image-decoders/png/PNGImageDecoder.h index 8c73785..c5264fd 100644 --- a/WebCore/platform/image-decoders/png/PNGImageDecoder.h +++ b/WebCore/platform/image-decoders/png/PNGImageDecoder.h @@ -23,46 +23,45 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef PNG_DECODER_H_ -#define PNG_DECODER_H_ +#ifndef PNGImageDecoder_h +#define PNGImageDecoder_h #include "ImageDecoder.h" namespace WebCore { -class PNGImageReader; + class PNGImageReader; -// This class decodes the PNG image format. -class PNGImageDecoder : public ImageDecoder -{ -public: - PNGImageDecoder(); - ~PNGImageDecoder(); + // This class decodes the PNG image format. + class PNGImageDecoder : public ImageDecoder { + public: + PNGImageDecoder(); + ~PNGImageDecoder(); - virtual String filenameExtension() const { return "png"; } + virtual String filenameExtension() const { return "png"; } - // Take the data and store it. - virtual void setData(SharedBuffer* data, bool allDataReceived); + // Take the data and store it. + virtual void setData(SharedBuffer* data, bool allDataReceived); - // Whether or not the size information has been decoded yet. - virtual bool isSizeAvailable() const; + // Whether or not the size information has been decoded yet. + virtual bool isSizeAvailable() const; - virtual RGBA32Buffer* frameBufferAtIndex(size_t index); + virtual RGBA32Buffer* frameBufferAtIndex(size_t index); - void decode(bool sizeOnly = false) const; + void decode(bool sizeOnly = false) const; - PNGImageReader* reader() { return m_reader; } + PNGImageReader* reader() { return m_reader; } - // Callbacks from libpng - void decodingFailed() { m_failed = true; } - void headerAvailable(); - void rowAvailable(unsigned char* rowBuffer, unsigned rowIndex, int interlacePass); - void pngComplete(); + // Callbacks from libpng + void decodingFailed(); + void headerAvailable(); + void rowAvailable(unsigned char* rowBuffer, unsigned rowIndex, int interlacePass); + void pngComplete(); -private: - mutable PNGImageReader* m_reader; -}; + private: + mutable PNGImageReader* m_reader; + }; -} +} // namespace WebCore #endif diff --git a/WebCore/platform/image-decoders/skia/GIFImageDecoder.cpp b/WebCore/platform/image-decoders/skia/GIFImageDecoder.cpp index 2d77943..c03452a 100644 --- a/WebCore/platform/image-decoders/skia/GIFImageDecoder.cpp +++ b/WebCore/platform/image-decoders/skia/GIFImageDecoder.cpp @@ -126,7 +126,7 @@ bool GIFImageDecoder::isSizeAvailable() const decode(GIFSizeQuery, 0); } - return !m_failed && ImageDecoder::isSizeAvailable(); + return ImageDecoder::isSizeAvailable(); } // The total number of frames for the image. Will scan the image data for the answer @@ -183,7 +183,7 @@ RGBA32Buffer* GIFImageDecoder::frameBufferAtIndex(size_t index) RGBA32Buffer& frame = m_frameBufferCache[index]; if (frame.status() != RGBA32Buffer::FrameComplete && m_reader) - decode(GIFFullQuery, index+1); // Decode this frame. + decode(GIFFullQuery, index + 1); // Decode this frame. return &frame; } diff --git a/WebCore/platform/image-decoders/skia/GIFImageReader.h b/WebCore/platform/image-decoders/skia/GIFImageReader.h index aa3d717..f0d127f 100644 --- a/WebCore/platform/image-decoders/skia/GIFImageReader.h +++ b/WebCore/platform/image-decoders/skia/GIFImageReader.h @@ -167,11 +167,11 @@ struct GIFImageReader { int version; /* Either 89 for GIF89 or 87 for GIF87 */ unsigned screen_width; /* Logical screen width & height */ unsigned screen_height; - int global_colormap_size; /* Size of global colormap array. */ - unsigned int images_decoded; /* Counts completed frames for animated GIFs */ - int images_count; /* Counted all frames seen so far (including incomplete frames) */ - int loop_count; /* Netscape specific extension block to control - the number of animation loops a GIF renders. */ + int global_colormap_size; /* Size of global colormap array. */ + unsigned images_decoded; /* Counts completed frames for animated GIFs */ + int images_count; /* Counted all frames seen so far (including incomplete frames) */ + int loop_count; /* Netscape specific extension block to control + the number of animation loops a GIF renders. */ // Not really global, but convenient to locate here. int count; /* Remaining # bytes in sub-block */ diff --git a/WebCore/platform/image-decoders/skia/ImageDecoder.h b/WebCore/platform/image-decoders/skia/ImageDecoder.h index cddb69b..c198420 100644 --- a/WebCore/platform/image-decoders/skia/ImageDecoder.h +++ b/WebCore/platform/image-decoders/skia/ImageDecoder.h @@ -33,8 +33,6 @@ #include "PlatformString.h" #include "SharedBuffer.h" #include <wtf/Assertions.h> -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> #include <wtf/RefPtr.h> #include <wtf/Vector.h> @@ -45,37 +43,8 @@ namespace WebCore { - class RefCountedNativeImageSkia : public RefCounted<RefCountedNativeImageSkia> { - public: - static PassRefPtr<RefCountedNativeImageSkia> create() - { - return adoptRef(new RefCountedNativeImageSkia); - } - - const NativeImageSkia& bitmap() const { return m_bitmap; } - NativeImageSkia& bitmap() { return m_bitmap; } - - private: - RefCountedNativeImageSkia() {} - NativeImageSkia m_bitmap; - }; - - // The RGBA32Buffer object represents the decoded image data in RGBA32 format. - // This buffer is what all decoders write a single frame into. Frames are then - // instantiated for drawing by being handed this buffer. - // - // The image data of an RGBA32Buffer is kept in an SkBitmapRef, a refcounting - // container for an SkBitmap. In all normal cases, the refcount should be - // exactly one. The exception happens when resizing the vector<RGBA32Buffer> in - // ImageDecoder::m_frameBufferCache, which copies all the buffers to the new - // vector, thus transiently incrementing the refcount to two. - // - // The choice to use an SkBitmapRef instead of an SkBitmap is not because of - // performance concerns -- SkBitmap refcounts its internal data anyway. Rather, - // we need the aforementioned vector resize to preserve the exact underlying - // SkBitmap object, since we may have already given its address to - // BitmapImage::m_frames. Using an SkBitmap would mean that after ImageDecoder - // resizes its vector, BitmapImage would be holding a pointer to garbage. + // The RGBA32Buffer object represents the decoded image data in RGBA32 format. This buffer is what all + // decoders write a single frame into. Frames are then instantiated for drawing by being handed this buffer. class RGBA32Buffer { public: enum FrameStatus { FrameEmpty, FramePartial, FrameComplete }; @@ -94,14 +63,12 @@ namespace WebCore { , m_duration(0) , m_disposalMethod(DisposeNotSpecified) { - m_bitmapRef = RefCountedNativeImageSkia::create(); } // This constructor doesn't create a new copy of the image data, it only // increases the ref count of the existing bitmap. RGBA32Buffer(const RGBA32Buffer& other) { - m_bitmapRef = RefCountedNativeImageSkia::create(); operator=(other); } @@ -120,18 +87,20 @@ namespace WebCore { if (this == &other) return *this; - m_bitmapRef = other.m_bitmapRef; + m_bitmap = other.m_bitmap; + // Keep the pixels locked since we will be writing directly into the + // bitmap throughout this object's lifetime. + m_bitmap.lockPixels(); setRect(other.rect()); setStatus(other.status()); setDuration(other.duration()); setDisposalMethod(other.disposalMethod()); - setHasAlpha(other.hasAlpha()); return *this; } void clear() { - m_bitmapRef = RefCountedNativeImageSkia::create(); + m_bitmap.reset(); m_status = FrameEmpty; // NOTE: Do not reset other members here; clearFrameBufferCache() // calls this to free the bitmap data, but other functions like @@ -146,21 +115,13 @@ namespace WebCore { if (this == &other) return; - m_bitmapRef = RefCountedNativeImageSkia::create(); - SkBitmap& bmp = bitmap(); - const SkBitmap& otherBmp = other.bitmap(); - bmp.setConfig(SkBitmap::kARGB_8888_Config, other.width(), - other.height(), otherBmp.rowBytes()); - bmp.allocPixels(); - if (width() > 0 && height() > 0) { - memcpy(bmp.getAddr32(0, 0), - otherBmp.getAddr32(0, 0), - otherBmp.rowBytes() * height()); - } + m_bitmap.reset(); + const NativeImageSkia& otherBitmap = other.bitmap(); + otherBitmap.copyTo(&m_bitmap, otherBitmap.config()); } - NativeImageSkia& bitmap() { return m_bitmapRef->bitmap(); } - const NativeImageSkia& bitmap() const { return m_bitmapRef->bitmap(); } + NativeImageSkia& bitmap() { return m_bitmap; } + const NativeImageSkia& bitmap() const { return m_bitmap; } // Must be called before any pixels are written. Will return true on // success, false if the memory allocation fails. @@ -168,37 +129,36 @@ namespace WebCore { { // This function should only be called once, it will leak memory // otherwise. - SkBitmap& bmp = bitmap(); - ASSERT(bmp.width() == 0 && bmp.height() == 0); - bmp.setConfig(SkBitmap::kARGB_8888_Config, width, height); - if (!bmp.allocPixels()) + ASSERT(m_bitmap.width() == 0 && m_bitmap.height() == 0); + m_bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); + if (!m_bitmap.allocPixels()) return false; // Allocation failure, maybe the bitmap was too big. // Clear the image. - bmp.eraseARGB(0, 0, 0, 0); + m_bitmap.eraseARGB(0, 0, 0, 0); return true; } - int width() const { return bitmap().width(); } - int height() const { return bitmap().height(); } + int width() const { return m_bitmap.width(); } + int height() const { return m_bitmap.height(); } const IntRect& rect() const { return m_rect; } FrameStatus status() const { return m_status; } unsigned duration() const { return m_duration; } FrameDisposalMethod disposalMethod() const { return m_disposalMethod; } - bool hasAlpha() const { return !bitmap().isOpaque(); } + bool hasAlpha() const { return !m_bitmap.isOpaque(); } void setRect(const IntRect& r) { m_rect = r; } void setStatus(FrameStatus s) { if (s == FrameComplete) - m_bitmapRef->bitmap().setDataComplete(); // Tell the bitmap it's done. + m_bitmap.setDataComplete(); // Tell the bitmap it's done. m_status = s; } void setDuration(unsigned duration) { m_duration = duration; } void setDisposalMethod(FrameDisposalMethod method) { m_disposalMethod = method; } - void setHasAlpha(bool alpha) { bitmap().setIsOpaque(!alpha); } + void setHasAlpha(bool alpha) { m_bitmap.setIsOpaque(!alpha); } static void setRGBA(uint32_t* dest, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { @@ -223,11 +183,11 @@ namespace WebCore { void setRGBA(int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - setRGBA(bitmap().getAddr32(x, y), r, g, b, a); + setRGBA(m_bitmap.getAddr32(x, y), r, g, b, a); } private: - RefPtr<RefCountedNativeImageSkia> m_bitmapRef; + NativeImageSkia m_bitmap; IntRect m_rect; // The rect of the original specified frame within the overall buffer. // This will always just be the entire buffer except for GIF frames // whose original rect was smaller than the overall image size. @@ -241,7 +201,12 @@ namespace WebCore { // and the base class manages the RGBA32 frame cache. class ImageDecoder { public: - ImageDecoder() : m_failed(false), m_sizeAvailable(false) {} + ImageDecoder() + : m_failed(false) + , m_sizeAvailable(false) + { + } + virtual ~ImageDecoder() {} // The the filename extension usually associated with an undecoded image of this type. diff --git a/WebCore/platform/image-decoders/skia/JPEGImageDecoder.cpp b/WebCore/platform/image-decoders/skia/JPEGImageDecoder.cpp index 98f622e..ab74012 100644 --- a/WebCore/platform/image-decoders/skia/JPEGImageDecoder.cpp +++ b/WebCore/platform/image-decoders/skia/JPEGImageDecoder.cpp @@ -99,7 +99,7 @@ public: /* Allocate and initialize JPEG decompression object */ jpeg_create_decompress(&m_info); - decoder_source_mgr* src = NULL; + decoder_source_mgr* src = 0; if (!m_info.src) { src = (decoder_source_mgr*)fastCalloc(sizeof(decoder_source_mgr), 1); if (!src) { @@ -421,7 +421,7 @@ bool JPEGImageDecoder::isSizeAvailable() const decode(true); } - return !m_failed && ImageDecoder::isSizeAvailable(); + return ImageDecoder::isSizeAvailable(); } RGBA32Buffer* JPEGImageDecoder::frameBufferAtIndex(size_t index) diff --git a/WebCore/platform/image-decoders/skia/PNGImageDecoder.cpp b/WebCore/platform/image-decoders/skia/PNGImageDecoder.cpp index ec1ebbe..ad12b86 100644 --- a/WebCore/platform/image-decoders/skia/PNGImageDecoder.cpp +++ b/WebCore/platform/image-decoders/skia/PNGImageDecoder.cpp @@ -72,9 +72,12 @@ class PNGImageReader { public: PNGImageReader(PNGImageDecoder* decoder) - : m_readOffset(0), m_decodingSizeOnly(false), m_interlaceBuffer(0), m_hasAlpha(0) + : m_readOffset(0) + , m_decodingSizeOnly(false) + , m_interlaceBuffer(0) + , m_hasAlpha(0) { - m_png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, decodingFailed, decodingWarning); + m_png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, decodingFailed, decodingWarning); m_info = png_create_info_struct(m_png); png_set_progressive_read_fn(m_png, decoder, headerAvailable, rowAvailable, pngComplete); } @@ -134,8 +137,9 @@ private: }; PNGImageDecoder::PNGImageDecoder() -: m_reader(0) -{} + : m_reader(0) +{ +} PNGImageDecoder::~PNGImageDecoder() { @@ -169,7 +173,7 @@ bool PNGImageDecoder::isSizeAvailable() const decode(true); } - return !m_failed && ImageDecoder::isSizeAvailable(); + return ImageDecoder::isSizeAvailable(); } RGBA32Buffer* PNGImageDecoder::frameBufferAtIndex(size_t index) @@ -305,8 +309,7 @@ void PNGImageDecoder::headerAvailable() void rowAvailable(png_structp png, png_bytep rowBuffer, png_uint_32 rowIndex, int interlacePass) { - static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->rowAvailable( - rowBuffer, rowIndex, interlacePass); + static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->rowAvailable(rowBuffer, rowIndex, interlacePass); } void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex, int interlacePass) diff --git a/WebCore/platform/image-decoders/skia/XBMImageDecoder.h b/WebCore/platform/image-decoders/skia/XBMImageDecoder.h index 44c6be2..cdcf8e6 100644 --- a/WebCore/platform/image-decoders/skia/XBMImageDecoder.h +++ b/WebCore/platform/image-decoders/skia/XBMImageDecoder.h @@ -31,7 +31,6 @@ #ifndef XBMImageDecoder_h #define XBMImageDecoder_h -#include "config.h" #include <string> #include "ImageDecoder.h" diff --git a/WebCore/platform/image-decoders/xbm/XBMImageDecoder.cpp b/WebCore/platform/image-decoders/xbm/XBMImageDecoder.cpp index 30c5589..3e8ae57 100644 --- a/WebCore/platform/image-decoders/xbm/XBMImageDecoder.cpp +++ b/WebCore/platform/image-decoders/xbm/XBMImageDecoder.cpp @@ -26,8 +26,6 @@ #include "config.h" #include "XBMImageDecoder.h" -#if PLATFORM(CAIRO) || PLATFORM(QT) || PLATFORM(WX) - namespace WebCore { @@ -41,6 +39,4 @@ RGBA32Buffer* XBMImageDecoder::frameBufferAtIndex(size_t index) return 0; } -} - -#endif // PLATFORM(CAIRO) +} // namespace WebCore diff --git a/WebCore/platform/image-decoders/xbm/XBMImageDecoder.h b/WebCore/platform/image-decoders/xbm/XBMImageDecoder.h index dc6d8d4..80cfb3f 100644 --- a/WebCore/platform/image-decoders/xbm/XBMImageDecoder.h +++ b/WebCore/platform/image-decoders/xbm/XBMImageDecoder.h @@ -23,27 +23,26 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef XBM_DECODER_H_ -#define XBM_DECODER_H_ +#ifndef XBMImageDecoder_h +#define XBMImageDecoder_h #include "ImageDecoder.h" namespace WebCore { -class XBMImageReader; + class XBMImageReader; -// This class decodes the XBM image format. -class XBMImageDecoder : public ImageDecoder -{ -public: - virtual String filenameExtension() const { return "xbm"; } + // This class decodes the XBM image format. + class XBMImageDecoder : public ImageDecoder { + public: + virtual String filenameExtension() const { return "xbm"; } - // Whether or not the size information has been decoded yet. - virtual bool isSizeAvailable() const; + // Whether or not the size information has been decoded yet. + virtual bool isSizeAvailable() const; - virtual RGBA32Buffer* frameBufferAtIndex(size_t index); -}; + virtual RGBA32Buffer* frameBufferAtIndex(size_t index); + }; -} +} // namespace WebCore #endif diff --git a/WebCore/platform/mac/ClipboardMac.mm b/WebCore/platform/mac/ClipboardMac.mm index cfa334b..d1b66a7 100644 --- a/WebCore/platform/mac/ClipboardMac.mm +++ b/WebCore/platform/mac/ClipboardMac.mm @@ -39,6 +39,10 @@ #import "SecurityOrigin.h" #import "WebCoreSystemInterface.h" +#ifdef BUILDING_ON_TIGER +typedef unsigned NSUInteger; +#endif + namespace WebCore { ClipboardMac::ClipboardMac(bool forDragging, NSPasteboard *pasteboard, ClipboardAccessPolicy policy, Frame *frame) @@ -121,9 +125,8 @@ void ClipboardMac::clearData(const String& type) // note NSPasteboard enforces changeCount itself on writing - can't write if not the owner NSString *cocoaType = cocoaTypeFromMIMEType(type); - if (cocoaType) { + if (cocoaType) [m_pasteboard.get() setString:@"" forType:cocoaType]; - } } void ClipboardMac::clearAllData() @@ -136,57 +139,71 @@ void ClipboardMac::clearAllData() [m_pasteboard.get() declareTypes:[NSArray array] owner:nil]; } +static NSArray *absoluteURLsFromPasteboardFilenames(NSPasteboard* pasteboard, bool onlyFirstURL) +{ + NSArray *fileList = [pasteboard propertyListForType:NSFilenamesPboardType]; + + // FIXME: Why does this code need to guard against bad values on the pasteboard? + ASSERT(!fileList || [fileList isKindOfClass:[NSArray class]]); + if (!fileList || ![fileList isKindOfClass:[NSArray class]] || ![fileList count]) + return nil; + + NSUInteger count = onlyFirstURL ? 1 : [fileList count]; + NSMutableArray *urls = [NSMutableArray array]; + for (NSUInteger i = 0; i < count; i++) { + NSString *string = [fileList objectAtIndex:i]; + + ASSERT([string isKindOfClass:[NSString class]]); // Added to understand why this if code is here + if (![string isKindOfClass:[NSString class]]) + return nil; // Non-string object in the list, bail out! FIXME: When can this happen? + + NSURL *url = [NSURL fileURLWithPath:string]; + [urls addObject:[url absoluteString]]; + } + return urls; +} + +static NSArray *absoluteURLsFromPasteboard(NSPasteboard* pasteboard, bool onlyFirstURL) +{ + // NOTE: We must always check [availableTypes containsObject:] before accessing pasteboard data + // or CoreFoundation will printf when there is not data of the corresponding type. + NSArray *availableTypes = [pasteboard types]; + + // Try NSFilenamesPboardType because it contains a list + if ([availableTypes containsObject:NSFilenamesPboardType]) { + if (NSArray* absoluteURLs = absoluteURLsFromPasteboardFilenames(pasteboard, onlyFirstURL)) + return absoluteURLs; + } + + // Fallback to NSURLPboardType (which is a single URL) + if ([availableTypes containsObject:NSURLPboardType]) { + if (NSURL *url = [NSURL URLFromPasteboard:pasteboard]) + return [NSArray arrayWithObject:[url absoluteString]]; + } + + // No file paths on the pasteboard, return nil + return nil; +} + String ClipboardMac::getData(const String& type, bool& success) const { success = false; if (policy() != ClipboardReadable) return String(); - + NSString *cocoaType = cocoaTypeFromMIMEType(type); NSString *cocoaValue = nil; - NSArray *availableTypes = [m_pasteboard.get() types]; - - // Fetch the data in different ways for the different Cocoa types + // Grab the value off the pasteboard corresponding to the cocoaType if ([cocoaType isEqualToString:NSURLPboardType]) { - // When both URL and filenames are present, filenames is superior since it can contain a list. - // must check this or we get a printf from CF when there's no data of this type - if ([availableTypes containsObject:NSFilenamesPboardType]) { - NSArray *fileList = [m_pasteboard.get() propertyListForType:NSFilenamesPboardType]; - if (fileList && [fileList isKindOfClass:[NSArray class]]) { - unsigned count = [fileList count]; - if (count > 0) { - if (type != "text/uri-list") - count = 1; - NSMutableString *urls = [NSMutableString string]; - unsigned i; - for (i = 0; i < count; i++) { - if (i > 0) { - [urls appendString:@"\n"]; - } - NSString *string = [fileList objectAtIndex:i]; - if (![string isKindOfClass:[NSString class]]) - break; - NSURL *url = [NSURL fileURLWithPath:string]; - [urls appendString:[url absoluteString]]; - } - if (i == count) - cocoaValue = urls; - } - } - } - if (!cocoaValue) { - // must check this or we get a printf from CF when there's no data of this type - if ([availableTypes containsObject:NSURLPboardType]) { - NSURL *url = [NSURL URLFromPasteboard:m_pasteboard.get()]; - if (url) { - cocoaValue = [url absoluteString]; - } - } - } - } else if (cocoaType) { + // "URL" and "text/url-list" both map to NSURLPboardType in cocoaTypeFromMIMEType(), "URL" only wants the first URL + bool onlyFirstURL = (type == "URL"); + NSArray *absoluteURLs = absoluteURLsFromPasteboard(m_pasteboard.get(), onlyFirstURL); + cocoaValue = [absoluteURLs componentsJoinedByString:@"\n"]; + } else if ([cocoaType isEqualToString:NSStringPboardType]) { + cocoaValue = [[m_pasteboard.get() stringForType:cocoaType] precomposedStringWithCanonicalMapping]; + } else if (cocoaType) cocoaValue = [m_pasteboard.get() stringForType:cocoaType]; - } // Enforce changeCount ourselves for security. We check after reading instead of before to be // sure it doesn't change between our testing the change count and accessing the data. @@ -244,18 +261,15 @@ HashSet<String> ClipboardMac::types() const return HashSet<String>(); HashSet<String> result; - if (types) { - unsigned count = [types count]; - unsigned i; - for (i = 0; i < count; i++) { - NSString *pbType = [types objectAtIndex:i]; - if ([pbType isEqualToString:@"NeXT plain ascii pasteboard type"]) - continue; // skip this ancient type that gets auto-supplied by some system conversion - - String str = MIMETypeFromCocoaType(pbType); - if (!result.contains(str)) - result.add(str); - } + NSUInteger count = [types count]; + for (NSUInteger i = 0; i < count; i++) { + NSString *pbType = [types objectAtIndex:i]; + if ([pbType isEqualToString:@"NeXT plain ascii pasteboard type"]) + continue; // skip this ancient type that gets auto-supplied by some system conversion + + String str = MIMETypeFromCocoaType(pbType); + if (!result.contains(str)) + result.add(str); } return result; } @@ -324,7 +338,7 @@ void ClipboardMac::declareAndWriteDragImage(Element* element, const KURL& url, c { ASSERT(frame); if (Page* page = frame->page()) - page->dragController()->client()->declareAndWriteDragImage(m_pasteboard.get(), [DOMElement _wrapElement:element], url, title, frame); + page->dragController()->client()->declareAndWriteDragImage(m_pasteboard.get(), kit(element), url, title, frame); } DragImageRef ClipboardMac::createDragImage(IntPoint& loc) const diff --git a/WebCore/platform/mac/CookieJar.mm b/WebCore/platform/mac/CookieJar.mm index 94b7d77..d8df601 100644 --- a/WebCore/platform/mac/CookieJar.mm +++ b/WebCore/platform/mac/CookieJar.mm @@ -27,6 +27,7 @@ #import "CookieJar.h" #import "BlockExceptions.h" +#import "Document.h" #import "KURL.h" #import <wtf/RetainPtr.h> @@ -84,7 +85,7 @@ String cookies(const Document*, const KURL& url) return String(); } -void setCookies(Document*, const KURL& url, const KURL& policyBaseURL, const String& cookieStr) +void setCookies(Document* document, const KURL& url, const String& cookieStr) { BEGIN_BLOCK_OBJC_EXCEPTIONS; @@ -99,7 +100,7 @@ void setCookies(Document*, const KURL& url, const KURL& policyBaseURL, const Str NSURL *cookieURL = url; NSArray *cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:[NSDictionary dictionaryWithObject:cookieString forKey:@"Set-Cookie"] forURL:cookieURL]; - [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:filterCookies(cookies).get() forURL:cookieURL mainDocumentURL:policyBaseURL]; + [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:filterCookies(cookies).get() forURL:cookieURL mainDocumentURL:document->firstPartyForCookies()]; END_BLOCK_OBJC_EXCEPTIONS; } diff --git a/WebCore/platform/mac/DragDataMac.mm b/WebCore/platform/mac/DragDataMac.mm index 5cf2e14..a7b751c 100644 --- a/WebCore/platform/mac/DragDataMac.mm +++ b/WebCore/platform/mac/DragDataMac.mm @@ -124,7 +124,7 @@ String DragData::asURL(String* title) const PassRefPtr<DocumentFragment> DragData::asFragment(Document*) const { - return [m_pasteboardHelper->fragmentFromPasteboard([m_platformDragData draggingPasteboard]) _documentFragment]; + return core(m_pasteboardHelper->fragmentFromPasteboard([m_platformDragData draggingPasteboard])); } } diff --git a/WebCore/platform/mac/GeolocationServiceMac.mm b/WebCore/platform/mac/GeolocationServiceMac.mm index c21b02c..01eca4a 100644 --- a/WebCore/platform/mac/GeolocationServiceMac.mm +++ b/WebCore/platform/mac/GeolocationServiceMac.mm @@ -153,26 +153,36 @@ void GeolocationServiceMac::errorOccurred(PassRefPtr<PositionError> error) UNUSED_PARAM(oldLocation); // Normalize + bool canProvideAltitude = true; + bool canProvideAltitudeAccuracy = true; double altitude = newLocation.altitude; double altitudeAccuracy = newLocation.verticalAccuracy; if (altitudeAccuracy < 0.0) { - altitudeAccuracy = 0.0; - altitude = 0.0; + canProvideAltitude = false; + canProvideAltitudeAccuracy = false; } + + bool canProvideSpeed = true; double speed = newLocation.speed; if (speed < 0.0) - speed = 0.0; + canProvideSpeed = false; + + bool canProvideHeading = true; double heading = newLocation.course; if (heading < 0.0) - heading = 0.0; + canProvideHeading = false; WTF::RefPtr<WebCore::Coordinates> newCoordinates = WebCore::Coordinates::create( newLocation.coordinate.latitude, newLocation.coordinate.longitude, + canProvideAltitude, altitude, newLocation.horizontalAccuracy, + canProvideAltitudeAccuracy, altitudeAccuracy, + canProvideHeading, heading, + canProvideSpeed, speed); WTF::RefPtr<WebCore::Geoposition> newPosition = WebCore::Geoposition::create( newCoordinates.release(), diff --git a/WebCore/platform/mac/LocalizedStringsMac.mm b/WebCore/platform/mac/LocalizedStringsMac.mm index d465758..ebb6d93 100644 --- a/WebCore/platform/mac/LocalizedStringsMac.mm +++ b/WebCore/platform/mac/LocalizedStringsMac.mm @@ -433,6 +433,110 @@ String contextMenuItemTagRightToLeft() return String(); } +String contextMenuItemTagCorrectSpellingAutomatically() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] contextMenuItemTagCorrectSpellingAutomatically]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} + +String contextMenuItemTagSubstitutionsMenu() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] contextMenuItemTagSubstitutionsMenu]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} + +String contextMenuItemTagShowSubstitutions(bool show) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] contextMenuItemTagShowSubstitutions:show]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} + +String contextMenuItemTagSmartCopyPaste() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] contextMenuItemTagSmartCopyPaste]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} + +String contextMenuItemTagSmartQuotes() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] contextMenuItemTagSmartQuotes]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} + +String contextMenuItemTagSmartDashes() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] contextMenuItemTagSmartDashes]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} + +String contextMenuItemTagSmartLinks() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] contextMenuItemTagSmartLinks]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} + +String contextMenuItemTagTextReplacement() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] contextMenuItemTagTextReplacement]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} + +String contextMenuItemTagTransformationsMenu() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] contextMenuItemTagTransformationsMenu]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} + +String contextMenuItemTagMakeUpperCase() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] contextMenuItemTagMakeUpperCase]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} + +String contextMenuItemTagMakeLowerCase() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] contextMenuItemTagMakeLowerCase]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} + +String contextMenuItemTagCapitalize() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] contextMenuItemTagCapitalize]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} + +String contextMenuItemTagChangeBack(const String& replacedString) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] contextMenuItemTagChangeBack:replacedString]; + END_BLOCK_OBJC_EXCEPTIONS; + return replacedString; +} + String contextMenuItemTagInspectElement() { BEGIN_BLOCK_OBJC_EXCEPTIONS; diff --git a/WebCore/platform/mac/PasteboardMac.mm b/WebCore/platform/mac/PasteboardMac.mm index 36b00f6..c0e43b3 100644 --- a/WebCore/platform/mac/PasteboardMac.mm +++ b/WebCore/platform/mac/PasteboardMac.mm @@ -139,7 +139,7 @@ void Pasteboard::writeSelection(NSPasteboard* pasteboard, Range* selectedRange, Pasteboard::generalPasteboard(); //Initialises pasteboard types ASSERT(selectedRange); - NSAttributedString *attributedString = [[[NSAttributedString alloc] _initWithDOMRange:[DOMRange _wrapRange:selectedRange]] autorelease]; + NSAttributedString *attributedString = [[[NSAttributedString alloc] _initWithDOMRange:kit(selectedRange)] autorelease]; #ifdef BUILDING_ON_TIGER // 4930197: Mail overrides [WebHTMLView pasteboardTypesForSelection] in order to add another type to the pasteboard // after WebKit does. On Tiger we must call this function so that Mail code will be executed, meaning that @@ -368,7 +368,7 @@ PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefP if (allowPlainText && [types containsObject:NSStringPboardType]) { chosePlainText = true; - RefPtr<DocumentFragment> fragment = createFragmentFromText(context.get(), [m_pasteboard.get() stringForType:NSStringPboardType]); + RefPtr<DocumentFragment> fragment = createFragmentFromText(context.get(), [[m_pasteboard.get() stringForType:NSStringPboardType] precomposedStringWithCanonicalMapping]); if (fragment) return fragment.release(); } diff --git a/WebCore/platform/mac/PlatformMouseEventMac.mm b/WebCore/platform/mac/PlatformMouseEventMac.mm index 8979124..74f694e 100644 --- a/WebCore/platform/mac/PlatformMouseEventMac.mm +++ b/WebCore/platform/mac/PlatformMouseEventMac.mm @@ -68,12 +68,12 @@ static int clickCountForEvent(NSEvent *event) } } -IntPoint globalPoint(const NSPoint& windowPoint, NSWindow* window) +IntPoint globalPoint(const NSPoint& windowPoint, NSWindow *window) { return IntPoint(flipScreenPoint([window convertBaseToScreen:windowPoint], screenForWindow(window))); } -IntPoint pointForEvent(NSEvent *event) +IntPoint pointForEvent(NSEvent *event, NSView *windowView) { switch ([event type]) { case NSLeftMouseDown: @@ -86,11 +86,14 @@ IntPoint pointForEvent(NSEvent *event) case NSOtherMouseUp: case NSOtherMouseDragged: case NSMouseMoved: - case NSScrollWheel: - // Note: This has its origin at the bottom left of the window. - // The Y coordinate gets flipped by ScrollView::viewportToContents. - // We should probably change both this and that to not use "bottom left origin" coordinates at all. - return IntPoint([event locationInWindow]); + case NSScrollWheel: { + // Note: This will have its origin at the bottom left of the window unless windowView is flipped. + // In those cases, the Y coordinate gets flipped by Widget::convertFromContainingWindow. + NSPoint location = [event locationInWindow]; + if (windowView) + location = [windowView convertPoint:location fromView:nil]; + return IntPoint(location); + } default: return IntPoint(); } @@ -139,8 +142,8 @@ static MouseEventType mouseEventForNSEvent(NSEvent* event) } } -PlatformMouseEvent::PlatformMouseEvent(NSEvent* event) - : m_position(pointForEvent(event)) +PlatformMouseEvent::PlatformMouseEvent(NSEvent* event, NSView *windowView) + : m_position(pointForEvent(event, windowView)) , m_globalPosition(globalPointForEvent(event)) , m_button(mouseButtonForEvent(event)) , m_eventType(mouseEventForNSEvent(event)) diff --git a/WebCore/platform/mac/RuntimeApplicationChecks.h b/WebCore/platform/mac/RuntimeApplicationChecks.h new file mode 100644 index 0000000..44eedfa --- /dev/null +++ b/WebCore/platform/mac/RuntimeApplicationChecks.h @@ -0,0 +1,36 @@ +/* + * 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 AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RuntimeApplicationChecks_h +#define RuntimeApplicationChecks_h + +namespace WebCore { + +bool applicationIsAppleMail(); +bool applicationIsSafari(); + +} // namespace WebCore + +#endif // RuntimeApplicationChecks_h diff --git a/WebCore/platform/mac/RuntimeApplicationChecks.mm b/WebCore/platform/mac/RuntimeApplicationChecks.mm new file mode 100644 index 0000000..1670185 --- /dev/null +++ b/WebCore/platform/mac/RuntimeApplicationChecks.mm @@ -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 AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "RuntimeApplicationChecks.h" + + +namespace WebCore { + +bool applicationIsAppleMail() +{ + static const bool isAppleMail = [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.mail"]; + return isAppleMail; +} + +bool applicationIsSafari() +{ + static const bool isSafari = [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Safari"]; + return isSafari; +} + +} // namespace WebCore diff --git a/WebCore/platform/mac/ScrollbarThemeMac.mm b/WebCore/platform/mac/ScrollbarThemeMac.mm index 22bfe46..759a6e1 100644 --- a/WebCore/platform/mac/ScrollbarThemeMac.mm +++ b/WebCore/platform/mac/ScrollbarThemeMac.mm @@ -26,14 +26,9 @@ #include "config.h" #include "ScrollbarThemeMac.h" -#include "GraphicsContext.h" #include "ImageBuffer.h" -#include "IntRect.h" -#include "Page.h" #include "PlatformMouseEvent.h" -#include "Scrollbar.h" -#include "ScrollbarClient.h" -#include "Settings.h" +#include "ScrollView.h" #include <Carbon/Carbon.h> #include <wtf/StdLibExtras.h> #include <wtf/UnusedParam.h> @@ -371,9 +366,12 @@ bool ScrollbarThemeMac::paint(Scrollbar* scrollbar, GraphicsContext* context, co trackInfo.attributes = 0; if (scrollbar->orientation() == HorizontalScrollbar) trackInfo.attributes |= kThemeTrackHorizontal; - trackInfo.enableState = scrollbar->client()->isActive() ? kThemeTrackActive : kThemeTrackInactive; + if (!scrollbar->enabled()) trackInfo.enableState = kThemeTrackDisabled; + else + trackInfo.enableState = scrollbar->client()->isActive() ? kThemeTrackActive : kThemeTrackInactive; + if (hasThumb(scrollbar)) trackInfo.attributes |= kThemeTrackShowThumb; else if (!hasButtons(scrollbar)) @@ -393,8 +391,8 @@ bool ScrollbarThemeMac::paint(Scrollbar* scrollbar, GraphicsContext* context, co bufferRect.intersect(damageRect); bufferRect.move(-scrollbar->frameRect().x(), -scrollbar->frameRect().y()); - auto_ptr<ImageBuffer> imageBuffer = ImageBuffer::create(bufferRect.size(), false); - if (!imageBuffer.get()) + OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(bufferRect.size(), false); + if (!imageBuffer) return true; HIThemeDrawTrack(&trackInfo, 0, imageBuffer->context()->platformContext(), kHIThemeOrientationNormal); diff --git a/WebCore/platform/mac/WebCoreTextRenderer.h b/WebCore/platform/mac/SuddenTermination.mm index 73753bc..513d01b 100644 --- a/WebCore/platform/mac/WebCoreTextRenderer.h +++ b/WebCore/platform/mac/SuddenTermination.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * 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 @@ -10,40 +10,36 @@ * 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 + * 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 + * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#import <AppKit/NSFontManager.h> -#import <CoreFoundation/CFString.h> +#import "config.h" +#import "SuddenTermination.h" -#ifdef __OBJC__ -@class NSColor; -@class NSFont; -@class NSString; -#endif +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) -#ifdef __cplusplus -extern "C" { -#endif +namespace WebCore { -extern void WebCoreDrawTextAtPoint(const UniChar*, unsigned length, NSPoint, NSFont*, NSColor*); -extern float WebCoreTextFloatWidth(const UniChar*, unsigned length, NSFont*); -extern void WebCoreSetShouldUseFontSmoothing(bool); -extern bool WebCoreShouldUseFontSmoothing(); -extern void WebCoreSetAlwaysUsesComplexTextCodePath(bool); -extern bool WebCoreAlwaysUsesComplexTextCodePath(); -extern NSFont* WebCoreFindFont(NSString* familyName, NSFontTraitMask, int weight, int size); +void disableSuddenTermination() +{ + [[NSProcessInfo processInfo] disableSuddenTermination]; +} -#ifdef __cplusplus +void enableSuddenTermination() +{ + [[NSProcessInfo processInfo] enableSuddenTermination]; } + +} // namespace WebCore + #endif diff --git a/WebCore/platform/mac/WebCoreSystemInterface.h b/WebCore/platform/mac/WebCoreSystemInterface.h index 3feed69..cbe4aea 100644 --- a/WebCore/platform/mac/WebCoreSystemInterface.h +++ b/WebCore/platform/mac/WebCoreSystemInterface.h @@ -117,8 +117,11 @@ extern void (*wkGetWheelEventDeltas)(NSEvent*, float* deltaX, float* deltaY, BOO extern BOOL (*wkHitTestMediaUIPart)(int part, int themeStyle, CGRect bounds, CGPoint point); extern void (*wkMeasureMediaUIPart)(int part, int themeStyle, CGRect *bounds, CGSize *naturalSize); extern void (*wkPopupMenu)(NSMenu*, NSPoint location, float width, NSView*, int selectedItem, NSFont*); +extern unsigned (*wkQTIncludeOnlyModernMediaFileTypes)(void); extern int (*wkQTMovieDataRate)(QTMovie*); extern float (*wkQTMovieMaxTimeLoaded)(QTMovie*); +extern NSString *(*wkQTMovieMaxTimeLoadedChangeNotification)(void); +extern float (*wkQTMovieMaxTimeSeekable)(QTMovie*); extern void (*wkQTMovieViewSetDrawSynchronously)(QTMovieView*, BOOL); extern void (*wkSetCGFontRenderingMode)(CGContextRef, NSFont*); extern void (*wkSetDragImage)(NSImage*, NSPoint offset); @@ -130,6 +133,7 @@ extern void (*wkSetUpFontCache)(); extern void (*wkSignalCFReadStreamEnd)(CFReadStreamRef stream); extern void (*wkSignalCFReadStreamError)(CFReadStreamRef stream, CFStreamError *error); extern void (*wkSignalCFReadStreamHasBytes)(CFReadStreamRef stream); +extern unsigned (*wkInitializeMaximumHTTPConnectionCountPerHost)(unsigned preferredConnectionCount); #ifndef BUILDING_ON_TIGER extern void (*wkGetGlyphsForCharacters)(CGFontRef, const UniChar[], CGGlyph[], size_t); diff --git a/WebCore/platform/mac/WebCoreSystemInterface.mm b/WebCore/platform/mac/WebCoreSystemInterface.mm index edd9d50..05d1da6 100644 --- a/WebCore/platform/mac/WebCoreSystemInterface.mm +++ b/WebCore/platform/mac/WebCoreSystemInterface.mm @@ -51,8 +51,11 @@ NSDate *(*wkGetNSURLResponseLastModifiedDate)(NSURLResponse *response); BOOL (*wkGetNSURLResponseMustRevalidate)(NSURLResponse *response); void (*wkGetWheelEventDeltas)(NSEvent*, float* deltaX, float* deltaY, BOOL* continuous); void (*wkPopupMenu)(NSMenu*, NSPoint location, float width, NSView*, int selectedItem, NSFont*); +unsigned (*wkQTIncludeOnlyModernMediaFileTypes)(void); int (*wkQTMovieDataRate)(QTMovie*); float (*wkQTMovieMaxTimeLoaded)(QTMovie*); +NSString *(*wkQTMovieMaxTimeLoadedChangeNotification)(void); +float (*wkQTMovieMaxTimeSeekable)(QTMovie*); void (*wkQTMovieViewSetDrawSynchronously)(QTMovieView*, BOOL); void (*wkSetCGFontRenderingMode)(CGContextRef, NSFont*); void (*wkSetDragImage)(NSImage*, NSPoint offset); @@ -74,6 +77,7 @@ CFReadStreamRef (*wkCreateCustomCFReadStream)(void *(*formCreate)(CFReadStreamRe void (*wkSetNSURLConnectionDefersCallbacks)(NSURLConnection *, BOOL); void (*wkSetNSURLRequestShouldContentSniff)(NSMutableURLRequest *, BOOL); id (*wkCreateNSURLConnectionDelegateProxy)(void); +unsigned (*wkInitializeMaximumHTTPConnectionCountPerHost)(unsigned preferredConnectionCount); #ifndef BUILDING_ON_TIGER void (*wkGetGlyphsForCharacters)(CGFontRef, const UniChar[], CGGlyph[], size_t); diff --git a/WebCore/platform/mac/WebCoreTextRenderer.mm b/WebCore/platform/mac/WebCoreTextRenderer.mm deleted file mode 100644 index ab053ef..0000000 --- a/WebCore/platform/mac/WebCoreTextRenderer.mm +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2006 Apple Computer, 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. - */ - -#import "config.h" -#import "WebCoreTextRenderer.h" - -#import "Font.h" -#import "SimpleFontData.h" -#import "GraphicsContext.h" -#import "IntPoint.h" -#import "WebFontCache.h" -#import <AppKit/AppKit.h> - -using namespace WebCore; - -void WebCoreDrawTextAtPoint(const UniChar* buffer, unsigned length, NSPoint point, NSFont* font, NSColor* textColor) -{ - NSGraphicsContext *nsContext = [NSGraphicsContext currentContext]; - CGContextRef cgContext = (CGContextRef)[nsContext graphicsPort]; - GraphicsContext graphicsContext(cgContext); - // Safari doesn't flip the NSGraphicsContext before calling WebKit, yet WebCore requires a flipped graphics context. - BOOL flipped = [nsContext isFlipped]; - if (!flipped) - CGContextScaleCTM(cgContext, 1.0f, -1.0f); - - FontPlatformData f(font); - Font renderer(f, ![[NSGraphicsContext currentContext] isDrawingToScreen]); - TextRun run(buffer, length); - run.disableRoundingHacks(); - CGFloat red, green, blue, alpha; - [[textColor colorUsingColorSpaceName:NSDeviceRGBColorSpace] getRed:&red green:&green blue:&blue alpha:&alpha]; - graphicsContext.setFillColor(makeRGBA((int)(red * 255), (int)(green * 255), (int)(blue * 255), (int)(alpha * 255))); - renderer.drawText(&graphicsContext, run, FloatPoint(point.x, (flipped ? point.y : (-1.0f * point.y)))); - if (!flipped) - CGContextScaleCTM(cgContext, 1.0f, -1.0f); -} - -float WebCoreTextFloatWidth(const UniChar* buffer, unsigned length , NSFont* font) -{ - FontPlatformData f(font); - Font renderer(f, ![[NSGraphicsContext currentContext] isDrawingToScreen]); - TextRun run(buffer, length); - run.disableRoundingHacks(); - return renderer.floatWidth(run); -} - -static bool gShouldUseFontSmoothing = true; - -void WebCoreSetShouldUseFontSmoothing(bool smooth) -{ - gShouldUseFontSmoothing = smooth; -} - -bool WebCoreShouldUseFontSmoothing() -{ - return gShouldUseFontSmoothing; -} - -void WebCoreSetAlwaysUsesComplexTextCodePath(bool complex) -{ - Font::setCodePath(complex ? Font::Complex : Font::Auto); -} - -bool WebCoreAlwaysUsesComplexTextCodePath() -{ - return Font::codePath() == Font::Complex; -} - -NSFont* WebCoreFindFont(NSString* familyName, NSFontTraitMask traits, int weight, int size) -{ - return [WebFontCache fontWithFamily:familyName traits:traits weight:weight size:size]; -} diff --git a/WebCore/platform/mac/WebFontCache.h b/WebCore/platform/mac/WebFontCache.h index 8d3e4dd..380f271 100644 --- a/WebCore/platform/mac/WebFontCache.h +++ b/WebCore/platform/mac/WebFontCache.h @@ -32,4 +32,6 @@ + (NSFont *)fontWithFamily:(NSString *)desiredFamily traits:(NSFontTraitMask)desiredTraits weight:(int)desiredWeight size:(float)size; + (void)getTraits:(Vector<unsigned>&)traitsMasks inFamily:(NSString *)desiredFamily; +// This older version of the interface is relied upon by some clients. WebCore doesn't use it. ++ (NSFont *)fontWithFamily:(NSString *)desiredFamily traits:(NSFontTraitMask)desiredTraits size:(float)size; @end diff --git a/WebCore/platform/mac/WebFontCache.mm b/WebCore/platform/mac/WebFontCache.mm index ac70f06..22e6291 100644 --- a/WebCore/platform/mac/WebFontCache.mm +++ b/WebCore/platform/mac/WebFontCache.mm @@ -34,6 +34,7 @@ #import <AppKit/AppKit.h> #import <Foundation/Foundation.h> #import <math.h> +#import <wtf/UnusedParam.h> using namespace WebCore; @@ -106,8 +107,13 @@ static BOOL betterChoice(NSFontTraitMask desiredTraits, int desiredWeight, // Workaround for <rdar://problem/5781372>. static inline void fixUpWeight(NSInteger& weight, NSString *fontName) { +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + UNUSED_PARAM(weight); + UNUSED_PARAM(fontName); +#else if (weight == 3 && [fontName rangeOfString:@"ultralight" options:NSCaseInsensitiveSearch | NSBackwardsSearch | NSLiteralSearch].location != NSNotFound) weight = 2; +#endif } static inline FontTraitsMask toTraitsMask(NSFontTraitMask appKitTraits, NSInteger appKitWeight) @@ -300,4 +306,10 @@ static inline FontTraitsMask toTraitsMask(NSFontTraitMask appKitTraits, NSIntege return [self internalFontWithFamily:desiredFamily traits:desiredTraits weight:desiredWeight size:size]; } ++ (NSFont *)fontWithFamily:(NSString *)desiredFamily traits:(NSFontTraitMask)desiredTraits size:(float)size +{ + int desiredWeight = (desiredTraits & NSBoldFontMask) ? 9 : 5; + return [self fontWithFamily:desiredFamily traits:desiredTraits weight:desiredWeight size:size]; +} + @end diff --git a/WebCore/platform/mac/WheelEventMac.mm b/WebCore/platform/mac/WheelEventMac.mm index 5821139..f380e3e 100644 --- a/WebCore/platform/mac/WheelEventMac.mm +++ b/WebCore/platform/mac/WheelEventMac.mm @@ -32,8 +32,8 @@ namespace WebCore { -PlatformWheelEvent::PlatformWheelEvent(NSEvent* event) - : m_position(pointForEvent(event)) +PlatformWheelEvent::PlatformWheelEvent(NSEvent* event, NSView *windowView) + : m_position(pointForEvent(event, windowView)) , m_globalPosition(globalPointForEvent(event)) , m_granularity(ScrollByPixelWheelEvent) , m_isAccepted(false) diff --git a/WebCore/platform/mac/WidgetMac.mm b/WebCore/platform/mac/WidgetMac.mm index ecd4f30..1aaf4b2 100644 --- a/WebCore/platform/mac/WidgetMac.mm +++ b/WebCore/platform/mac/WidgetMac.mm @@ -285,7 +285,9 @@ void Widget::afterMouseDown(NSView *view, Widget* widget) IntPoint Widget::convertFromContainingWindow(const IntPoint& point) const { - if (!platformWidget() && parent()) { + if (!platformWidget()) { + if (!parent()) + return point; IntPoint result = parent()->convertFromContainingWindow(point); result.move(parent()->scrollX() - x(), parent()->scrollY() - y()); return result; @@ -300,7 +302,9 @@ IntPoint Widget::convertFromContainingWindow(const IntPoint& point) const IntRect Widget::convertFromContainingWindow(const IntRect& rect) const { - if (!platformWidget() && parent()) { + if (!platformWidget()) { + if (!parent()) + return rect; IntRect result = parent()->convertFromContainingWindow(rect); result.move(parent()->scrollX() - x(), parent()->scrollY() - y()); return result; diff --git a/WebCore/platform/network/HTTPParsers.cpp b/WebCore/platform/network/HTTPParsers.cpp index f36e9fb..e57401e 100644 --- a/WebCore/platform/network/HTTPParsers.cpp +++ b/WebCore/platform/network/HTTPParsers.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/ * * Redistribution and use in source and binary forms, with or without @@ -31,7 +31,11 @@ #include "config.h" #include "HTTPParsers.h" +#include "CString.h" #include "PlatformString.h" +#include <wtf/DateMath.h> + +using namespace WTF; namespace WebCore { @@ -40,12 +44,13 @@ static inline bool skipWhiteSpace(const String& str, int& pos, bool fromHttpEqui { int len = str.length(); - if (fromHttpEquivMeta) + if (fromHttpEquivMeta) { while (pos != len && str[pos] <= ' ') ++pos; - else + } else { while (pos != len && (str[pos] == '\t' || str[pos] == ' ')) ++pos; + } return pos != len; } @@ -102,6 +107,11 @@ bool parseHTTPRefresh(const String& refresh, bool fromHttpEquivMeta, double& del } } +double parseDate(const String& value) +{ + return parseDateFromNullTerminatedCharacters(value.utf8().data()); +} + String filenameFromHTTPContentDisposition(const String& value) { Vector<String> keyValuePairs; @@ -135,14 +145,33 @@ String extractMIMETypeFromMediaType(const String& mediaType) Vector<UChar, 64> mimeType; unsigned length = mediaType.length(); mimeType.reserveCapacity(length); - for (unsigned offset = 0; offset < length; offset++) { - UChar c = mediaType[offset]; + for (unsigned i = 0; i < length; i++) { + UChar c = mediaType[i]; + if (c == ';') break; - else if (isSpaceOrNewline(c)) // FIXME: This seems wrong, " " is an invalid MIME type character according to RFC 2045. bug 8644 + + // While RFC 2616 does not allow it, other browsers allow multiple values in the HTTP media + // type header field, Content-Type. In such cases, the media type string passed here may contain + // the multiple values separated by commas. For now, this code ignores text after the first comma, + // which prevents it from simply failing to parse such types altogether. Later for better + // compatibility we could consider using the first or last valid MIME type instead. + // See https://bugs.webkit.org/show_bug.cgi?id=25352 for more discussion. + if (c == ',') + break; + + // FIXME: The following is not correct. RFC 2616 allows linear white space before and + // after the MIME type, but not within the MIME type itself. And linear white space + // includes only a few specific ASCII characters; a small subset of isSpaceOrNewline. + // See https://bugs.webkit.org/show_bug.cgi?id=8644 for a bug tracking part of this. + if (isSpaceOrNewline(c)) continue; + mimeType.append(c); } + + if (mimeType.size() == length) + return mediaType; return String(mimeType.data(), mimeType.size()); } diff --git a/WebCore/platform/network/HTTPParsers.h b/WebCore/platform/network/HTTPParsers.h index 28a9ce9..0648aee 100644 --- a/WebCore/platform/network/HTTPParsers.h +++ b/WebCore/platform/network/HTTPParsers.h @@ -34,6 +34,7 @@ namespace WebCore { class String; bool parseHTTPRefresh(const String& refresh, bool fromHttpEquivMeta, double& delay, String& url); + double parseDate(const String&); String filenameFromHTTPContentDisposition(const String&); String extractMIMETypeFromMediaType(const String&); String extractCharsetFromMediaType(const String&); diff --git a/WebCore/platform/network/ResourceHandle.cpp b/WebCore/platform/network/ResourceHandle.cpp index 149411e..5a40b21 100644 --- a/WebCore/platform/network/ResourceHandle.cpp +++ b/WebCore/platform/network/ResourceHandle.cpp @@ -34,6 +34,8 @@ namespace WebCore { +static bool shouldForceContentSniffing; + static bool portAllowed(const ResourceRequest&); ResourceHandle::ResourceHandle(const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, @@ -45,6 +47,9 @@ ResourceHandle::ResourceHandle(const ResourceRequest& request, ResourceHandleCli PassRefPtr<ResourceHandle> ResourceHandle::create(const ResourceRequest& request, ResourceHandleClient* client, Frame* frame, bool defersLoading, bool shouldContentSniff, bool mightDownloadFromHandle) { + if (shouldContentSniff) + shouldContentSniff = shouldContentSniffURL(request.url()); + RefPtr<ResourceHandle> newHandle(adoptRef(new ResourceHandle(request, client, defersLoading, shouldContentSniff, mightDownloadFromHandle))); if (!request.url().isValid()) { @@ -178,6 +183,7 @@ static bool portAllowed(const ResourceRequest& request) 993, // IMAP+SSL 995, // POP3+SSL 2049, // NFS + 3659, // apple-sasl / PasswordServer [Apple addition] 4045, // lockd 6000, // X11 }; @@ -199,4 +205,24 @@ static bool portAllowed(const ResourceRequest& request) return false; } +bool ResourceHandle::shouldContentSniff() const +{ + return d->m_shouldContentSniff; +} + +bool ResourceHandle::shouldContentSniffURL(const KURL& url) +{ +#if PLATFORM(MAC) + if (shouldForceContentSniffing) + return true; +#endif + // We shouldn't content sniff file URLs as their MIME type should be established via their extension. + return !url.protocolIs("file"); +} + +void ResourceHandle::forceContentSniffing() +{ + shouldForceContentSniffing = true; +} + } // namespace WebCore diff --git a/WebCore/platform/network/ResourceHandle.h b/WebCore/platform/network/ResourceHandle.h index e3038ca..3b27b00 100644 --- a/WebCore/platform/network/ResourceHandle.h +++ b/WebCore/platform/network/ResourceHandle.h @@ -28,6 +28,7 @@ #include "AuthenticationChallenge.h" #include "HTTPHeaderMap.h" +#include "ThreadableLoader.h" #include <wtf/OwnPtr.h> #if USE(SOUP) @@ -103,7 +104,7 @@ public: // FIXME: should not need the Frame static PassRefPtr<ResourceHandle> create(const ResourceRequest&, ResourceHandleClient*, Frame*, bool defersLoading, bool shouldContentSniff, bool mightDownloadFromHandle = false); - static void loadResourceSynchronously(const ResourceRequest&, ResourceError&, ResourceResponse&, Vector<char>& data, Frame* frame); + static void loadResourceSynchronously(const ResourceRequest&, StoredCredentials, ResourceError&, ResourceResponse&, Vector<char>& data, Frame* frame); static bool willLoadFromCache(ResourceRequest&); #if PLATFORM(MAC) static bool didSendBodyDataDelegateExists(); @@ -112,6 +113,7 @@ public: ~ResourceHandle(); #if PLATFORM(MAC) || USE(CFNETWORK) + void willSendRequest(ResourceRequest&, const ResourceResponse& redirectResponse); bool shouldUseCredentialStorage(); #endif #if PLATFORM(MAC) || USE(CFNETWORK) || USE(CURL) @@ -148,6 +150,11 @@ public: PassRefPtr<SharedBuffer> bufferedData(); static bool supportsBufferedData(); + bool shouldContentSniff() const; + static bool shouldContentSniffURL(const KURL&); + + static void forceContentSniffing(); + #if USE(WININET) void setHasReceivedResponse(bool = true); bool hasReceivedResponse() const; diff --git a/WebCore/platform/network/ResourceHandleClient.h b/WebCore/platform/network/ResourceHandleClient.h index 54c27d2..c99be54 100644 --- a/WebCore/platform/network/ResourceHandleClient.h +++ b/WebCore/platform/network/ResourceHandleClient.h @@ -79,8 +79,6 @@ namespace WebCore { virtual bool shouldUseCredentialStorage(ResourceHandle*) { return false; } virtual void didReceiveAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge&) { } virtual void didCancelAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge&) { } - virtual void receivedCredential(ResourceHandle*, const AuthenticationChallenge&, const Credential&) { } - virtual void receivedRequestToContinueWithoutCredential(ResourceHandle*, const AuthenticationChallenge&) { } virtual void receivedCancellation(ResourceHandle*, const AuthenticationChallenge&) { } #if PLATFORM(MAC) diff --git a/WebCore/platform/network/ResourceHandleInternal.h b/WebCore/platform/network/ResourceHandleInternal.h index c592a1a..b10c658 100644 --- a/WebCore/platform/network/ResourceHandleInternal.h +++ b/WebCore/platform/network/ResourceHandleInternal.h @@ -133,6 +133,7 @@ namespace WebCore { #endif #if PLATFORM(MAC) , m_startWhenScheduled(false) + , m_needsSiteSpecificQuirks(false) , m_currentMacChallenge(nil) #elif USE(CFNETWORK) , m_currentCFChallenge(0) @@ -142,6 +143,10 @@ namespace WebCore { #endif , m_failureTimer(loader, &ResourceHandle::fireFailure) { + const KURL& url = m_request.url(); + m_user = url.user(); + m_pass = url.pass(); + m_request.removeCredentials(); } ~ResourceHandleInternal(); @@ -150,6 +155,10 @@ namespace WebCore { ResourceHandleClient* m_client; ResourceRequest m_request; + + // Suggested credentials for the current redirection step. + String m_user; + String m_pass; int status; @@ -163,6 +172,7 @@ namespace WebCore { RetainPtr<WebCoreResourceHandleAsDelegate> m_delegate; RetainPtr<id> m_proxy; bool m_startWhenScheduled; + bool m_needsSiteSpecificQuirks; #endif #if USE(WININET) HANDLE m_fileHandle; @@ -210,6 +220,8 @@ namespace WebCore { #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) NSURLAuthenticationChallenge *m_currentMacChallenge; #endif diff --git a/WebCore/platform/network/ResourceRequestBase.cpp b/WebCore/platform/network/ResourceRequestBase.cpp index fd27718..bfa3dc6 100644 --- a/WebCore/platform/network/ResourceRequestBase.cpp +++ b/WebCore/platform/network/ResourceRequestBase.cpp @@ -42,7 +42,7 @@ auto_ptr<ResourceRequest> ResourceRequestBase::adopt(auto_ptr<CrossThreadResourc request->setURL(data->m_url); request->setCachePolicy(data->m_cachePolicy); request->setTimeoutInterval(data->m_timeoutInterval); - request->setMainDocumentURL(data->m_mainDocumentURL); + request->setFirstPartyForCookies(data->m_firstPartyForCookies); request->setHTTPMethod(data->m_httpMethod); request->updateResourceRequest(); @@ -72,7 +72,7 @@ auto_ptr<CrossThreadResourceRequestData> ResourceRequestBase::copyData() const data->m_url = url().copy(); data->m_cachePolicy = cachePolicy(); data->m_timeoutInterval = timeoutInterval(); - data->m_mainDocumentURL = mainDocumentURL().copy(); + data->m_firstPartyForCookies = firstPartyForCookies().copy(); data->m_httpMethod = httpMethod().copy(); data->m_httpHeaders.adopt(httpHeaderFields().copyData()); @@ -117,6 +117,16 @@ void ResourceRequestBase::setURL(const KURL& url) m_platformRequestUpdated = false; } +void ResourceRequestBase::removeCredentials() +{ + updateResourceRequest(); + + m_url.setUser(String()); + m_url.setPass(String()); + + m_platformRequestUpdated = false; +} + ResourceRequestCachePolicy ResourceRequestBase::cachePolicy() const { updateResourceRequest(); @@ -151,18 +161,18 @@ void ResourceRequestBase::setTimeoutInterval(double timeoutInterval) m_platformRequestUpdated = false; } -const KURL& ResourceRequestBase::mainDocumentURL() const +const KURL& ResourceRequestBase::firstPartyForCookies() const { updateResourceRequest(); - return m_mainDocumentURL; + return m_firstPartyForCookies; } -void ResourceRequestBase::setMainDocumentURL(const KURL& mainDocumentURL) +void ResourceRequestBase::setFirstPartyForCookies(const KURL& firstPartyForCookies) { updateResourceRequest(); - m_mainDocumentURL = mainDocumentURL; + m_firstPartyForCookies = firstPartyForCookies; m_platformRequestUpdated = false; } @@ -284,7 +294,7 @@ bool equalIgnoringHeaderFields(const ResourceRequestBase& a, const ResourceReque if (a.timeoutInterval() != b.timeoutInterval()) return false; - if (a.mainDocumentURL() != b.mainDocumentURL()) + if (a.firstPartyForCookies() != b.firstPartyForCookies()) return false; if (a.httpMethod() != b.httpMethod()) @@ -345,4 +355,13 @@ void ResourceRequestBase::updateResourceRequest() const m_resourceRequestUpdated = true; } +#if !PLATFORM(MAC) && !USE(CFNETWORK) +unsigned initializeMaximumHTTPConnectionCountPerHost() +{ + // This is used by the loader to control the number of issued parallel load requests. + // Four seems to be a common default in HTTP frameworks. + return 4; +} +#endif + } diff --git a/WebCore/platform/network/ResourceRequestBase.h b/WebCore/platform/network/ResourceRequestBase.h index 4fd57e1..2d87d6e 100644 --- a/WebCore/platform/network/ResourceRequestBase.h +++ b/WebCore/platform/network/ResourceRequestBase.h @@ -63,14 +63,16 @@ namespace WebCore { const KURL& url() const; void setURL(const KURL& url); + void removeCredentials(); + ResourceRequestCachePolicy cachePolicy() const; void setCachePolicy(ResourceRequestCachePolicy cachePolicy); double timeoutInterval() const; void setTimeoutInterval(double timeoutInterval); - const KURL& mainDocumentURL() const; - void setMainDocumentURL(const KURL& mainDocumentURL); + const KURL& firstPartyForCookies() const; + void setFirstPartyForCookies(const KURL& firstPartyForCookies); const String& httpMethod() const; void setHTTPMethod(const String& httpMethod); @@ -141,7 +143,7 @@ namespace WebCore { ResourceRequestCachePolicy m_cachePolicy; double m_timeoutInterval; - KURL m_mainDocumentURL; + KURL m_firstPartyForCookies; String m_httpMethod; HTTPHeaderMap m_httpHeaderFields; Vector<String> m_responseContentDispositionEncodingFallbackArray; @@ -165,7 +167,7 @@ namespace WebCore { ResourceRequestCachePolicy m_cachePolicy; double m_timeoutInterval; - KURL m_mainDocumentURL; + KURL m_firstPartyForCookies; String m_httpMethod; OwnPtr<CrossThreadHTTPHeaderMapData> m_httpHeaders; @@ -173,6 +175,8 @@ namespace WebCore { RefPtr<FormData> m_httpBody; bool m_allowHTTPCookies; }; + + unsigned initializeMaximumHTTPConnectionCountPerHost(); } // namespace WebCore diff --git a/WebCore/platform/network/ResourceResponseBase.cpp b/WebCore/platform/network/ResourceResponseBase.cpp index 60c0097..965759e 100644 --- a/WebCore/platform/network/ResourceResponseBase.cpp +++ b/WebCore/platform/network/ResourceResponseBase.cpp @@ -27,14 +27,45 @@ #include "config.h" #include "ResourceResponseBase.h" +#include "HTTPParsers.h" #include "ResourceResponse.h" +#include <wtf/CurrentTime.h> +#include <wtf/MathExtras.h> +#include <wtf/StdLibExtras.h> using namespace std; namespace WebCore { static void parseCacheHeader(const String& header, Vector<pair<String, String> >& result); -static void parseCacheControlDirectiveValues(const String& directives, Vector<String>& result); + +ResourceResponseBase::ResourceResponseBase() + : m_expectedContentLength(0) + , m_httpStatusCode(0) + , m_isNull(true) + , m_haveParsedCacheControlHeader(false) + , m_haveParsedAgeHeader(false) + , m_haveParsedDateHeader(false) + , m_haveParsedExpiresHeader(false) + , m_haveParsedLastModifiedHeader(false) +{ +} + +ResourceResponseBase::ResourceResponseBase(const KURL& url, const String& mimeType, long long expectedLength, const String& textEncodingName, const String& filename) + : m_url(url) + , m_mimeType(mimeType) + , m_expectedContentLength(expectedLength) + , m_textEncodingName(textEncodingName) + , m_suggestedFilename(filename) + , m_httpStatusCode(0) + , m_isNull(false) + , m_haveParsedCacheControlHeader(false) + , m_haveParsedAgeHeader(false) + , m_haveParsedDateHeader(false) + , m_haveParsedExpiresHeader(false) + , m_haveParsedLastModifiedHeader(false) +{ +} auto_ptr<ResourceResponse> ResourceResponseBase::adopt(auto_ptr<CrossThreadResourceResponseData> data) { @@ -50,12 +81,8 @@ auto_ptr<ResourceResponse> ResourceResponseBase::adopt(auto_ptr<CrossThreadResou response->lazyInit(); response->m_httpHeaderFields.adopt(std::auto_ptr<CrossThreadHTTPHeaderMapData>(data->m_httpHeaders.release())); - - response->setExpirationDate(data->m_expirationDate); response->setLastModifiedDate(data->m_lastModifiedDate); - response->m_haveParsedCacheControl = data->m_haveParsedCacheControl; - response->m_cacheControlContainsMustRevalidate = data->m_cacheControlContainsMustRevalidate; - response->m_cacheControlContainsNoCache = data->m_cacheControlContainsNoCache; + return response; } @@ -70,11 +97,7 @@ auto_ptr<CrossThreadResourceResponseData> ResourceResponseBase::copyData() const data->m_httpStatusCode = httpStatusCode(); data->m_httpStatusText = httpStatusText().copy(); data->m_httpHeaders.adopt(httpHeaderFields().copyData()); - data->m_expirationDate = expirationDate(); data->m_lastModifiedDate = lastModifiedDate(); - data->m_haveParsedCacheControl = m_haveParsedCacheControl; - data->m_cacheControlContainsMustRevalidate = m_cacheControlContainsMustRevalidate; - data->m_cacheControlContainsNoCache = m_cacheControlContainsNoCache; return data; } @@ -201,9 +224,24 @@ String ResourceResponseBase::httpHeaderField(const AtomicString& name) const void ResourceResponseBase::setHTTPHeaderField(const AtomicString& name, const String& value) { lazyInit(); + + DEFINE_STATIC_LOCAL(const AtomicString, ageHeader, ("age")); + DEFINE_STATIC_LOCAL(const AtomicString, cacheControlHeader, ("cache-control")); + DEFINE_STATIC_LOCAL(const AtomicString, dateHeader, ("date")); + DEFINE_STATIC_LOCAL(const AtomicString, expiresHeader, ("expires")); + DEFINE_STATIC_LOCAL(const AtomicString, lastModifiedHeader, ("last-modified")); + DEFINE_STATIC_LOCAL(const AtomicString, pragmaHeader, ("pragma")); + if (equalIgnoringCase(name, ageHeader)) + m_haveParsedAgeHeader = false; + else if (equalIgnoringCase(name, cacheControlHeader) || equalIgnoringCase(name, pragmaHeader)) + m_haveParsedCacheControlHeader = false; + else if (equalIgnoringCase(name, dateHeader)) + m_haveParsedDateHeader = false; + else if (equalIgnoringCase(name, expiresHeader)) + m_haveParsedExpiresHeader = false; + else if (equalIgnoringCase(name, lastModifiedHeader)) + m_haveParsedLastModifiedHeader = false; - if (equalIgnoringCase(name, "cache-control")) - m_haveParsedCacheControl = false; m_httpHeaderFields.set(name, value); } @@ -216,66 +254,156 @@ const HTTPHeaderMap& ResourceResponseBase::httpHeaderFields() const void ResourceResponseBase::parseCacheControlDirectives() const { - ASSERT(!m_haveParsedCacheControl); + ASSERT(!m_haveParsedCacheControlHeader); lazyInit(); - m_haveParsedCacheControl = true; + m_haveParsedCacheControlHeader = true; + m_cacheControlContainsMustRevalidate = false; m_cacheControlContainsNoCache = false; - - String cacheControlValue = httpHeaderField("cache-control"); - if (cacheControlValue.isEmpty()) - return; - - // FIXME: It would probably be much more efficient to parse this without creating all these data structures. - - Vector<pair<String, String> > directives; - parseCacheHeader(cacheControlValue, directives); - - size_t directivesSize = directives.size(); - for (size_t i = 0; i < directivesSize; ++i) { - Vector<String> directiveValues; - if ((equalIgnoringCase(directives[i].first, "private") || equalIgnoringCase(directives[i].first, "no-cache")) && !directives[i].second.isEmpty()) - parseCacheControlDirectiveValues(directives[i].second, directiveValues); - else - directiveValues.append(directives[i].first); - for (size_t i = 0; i < directiveValues.size(); ++i) { - if (equalIgnoringCase(directiveValues[i], "no-cache")) + m_cacheControlMaxAge = numeric_limits<double>::quiet_NaN(); + + DEFINE_STATIC_LOCAL(const AtomicString, cacheControlString, ("cache-control")); + DEFINE_STATIC_LOCAL(const AtomicString, noCacheDirective, ("no-cache")); + DEFINE_STATIC_LOCAL(const AtomicString, mustRevalidateDirective, ("must-revalidate")); + DEFINE_STATIC_LOCAL(const AtomicString, maxAgeDirective, ("max-age")); + + String cacheControlValue = m_httpHeaderFields.get(cacheControlString); + if (!cacheControlValue.isEmpty()) { + Vector<pair<String, String> > directives; + parseCacheHeader(cacheControlValue, directives); + + size_t directivesSize = directives.size(); + for (size_t i = 0; i < directivesSize; ++i) { + // RFC2616 14.9.1: A no-cache directive with a value is only meaningful for proxy caches. + // It should be ignored by a browser level cache. + if (equalIgnoringCase(directives[i].first, noCacheDirective) && directives[i].second.isEmpty()) m_cacheControlContainsNoCache = true; - else if (equalIgnoringCase(directiveValues[i], "must-revalidate")) + else if (equalIgnoringCase(directives[i].first, mustRevalidateDirective)) m_cacheControlContainsMustRevalidate = true; + else if (equalIgnoringCase(directives[i].first, maxAgeDirective)) { + bool ok; + double maxAge = directives[i].second.toDouble(&ok); + if (ok) + m_cacheControlMaxAge = maxAge; + } } } + + if (!m_cacheControlContainsNoCache) { + // Handle Pragma: no-cache + // This is deprecated and equivalent to Cache-control: no-cache + // Don't bother tokenizing the value, it is not important + DEFINE_STATIC_LOCAL(const AtomicString, pragmaHeader, ("pragma")); + String pragmaValue = m_httpHeaderFields.get(pragmaHeader); + m_cacheControlContainsNoCache = pragmaValue.lower().contains(noCacheDirective); + } +} + +bool ResourceResponseBase::cacheControlContainsNoCache() const +{ + if (!m_haveParsedCacheControlHeader) + parseCacheControlDirectives(); + return m_cacheControlContainsNoCache; } -bool ResourceResponseBase::isAttachment() const +bool ResourceResponseBase::cacheControlContainsMustRevalidate() const { - lazyInit(); + if (!m_haveParsedCacheControlHeader) + parseCacheControlDirectives(); + return m_cacheControlContainsMustRevalidate; +} - String value = m_httpHeaderFields.get("Content-Disposition"); - int loc = value.find(';'); - if (loc != -1) - value = value.left(loc); - value = value.stripWhiteSpace(); - return equalIgnoringCase(value, "attachment"); +double ResourceResponseBase::cacheControlMaxAge() const +{ + if (!m_haveParsedCacheControlHeader) + parseCacheControlDirectives(); + return m_cacheControlMaxAge; } -void ResourceResponseBase::setExpirationDate(time_t expirationDate) +static double parseDateValueInHeader(const HTTPHeaderMap& headers, const AtomicString& headerName) +{ + String headerValue = headers.get(headerName); + if (headerValue.isEmpty()) + return std::numeric_limits<double>::quiet_NaN(); + // This handles all date formats required by RFC2616: + // Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 + // Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 + // Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format + double dateInMilliseconds = parseDate(headerValue); + if (!isfinite(dateInMilliseconds)) + return std::numeric_limits<double>::quiet_NaN(); + return dateInMilliseconds / 1000; +} + +double ResourceResponseBase::date() const { lazyInit(); - m_expirationDate = expirationDate; + if (!m_haveParsedDateHeader) { + DEFINE_STATIC_LOCAL(const AtomicString, headerName, ("date")); + m_date = parseDateValueInHeader(m_httpHeaderFields, headerName); + m_haveParsedDateHeader = true; + } + return m_date; +} + +double ResourceResponseBase::age() const +{ + lazyInit(); + + if (!m_haveParsedAgeHeader) { + DEFINE_STATIC_LOCAL(const AtomicString, headerName, ("age")); + String headerValue = m_httpHeaderFields.get(headerName); + bool ok; + m_age = headerValue.toDouble(&ok); + if (!ok) + m_age = std::numeric_limits<double>::quiet_NaN(); + m_haveParsedAgeHeader = true; + } + return m_age; } -time_t ResourceResponseBase::expirationDate() const +double ResourceResponseBase::expires() const { lazyInit(); - return m_expirationDate; + if (!m_haveParsedExpiresHeader) { + DEFINE_STATIC_LOCAL(const AtomicString, headerName, ("expires")); + m_expires = parseDateValueInHeader(m_httpHeaderFields, headerName); + m_haveParsedExpiresHeader = true; + } + return m_expires; +} + +double ResourceResponseBase::lastModified() const +{ + lazyInit(); + + if (!m_haveParsedLastModifiedHeader) { + DEFINE_STATIC_LOCAL(const AtomicString, headerName, ("last-modified")); + m_lastModified = parseDateValueInHeader(m_httpHeaderFields, headerName); + m_haveParsedLastModifiedHeader = true; + } + return m_lastModified; } -void ResourceResponseBase::setLastModifiedDate(time_t lastModifiedDate) +bool ResourceResponseBase::isAttachment() const +{ + lazyInit(); + + DEFINE_STATIC_LOCAL(const AtomicString, headerName, ("content-disposition")); + String value = m_httpHeaderFields.get(headerName); + int loc = value.find(';'); + if (loc != -1) + value = value.left(loc); + value = value.stripWhiteSpace(); + DEFINE_STATIC_LOCAL(const AtomicString, attachmentString, ("attachment")); + return equalIgnoringCase(value, attachmentString); +} + +void ResourceResponseBase::setLastModifiedDate(time_t lastModifiedDate) { lazyInit(); @@ -314,8 +442,6 @@ bool ResourceResponseBase::compare(const ResourceResponse& a, const ResourceResp return false; if (a.httpHeaderFields() != b.httpHeaderFields()) return false; - if (a.expirationDate() != b.expirationDate()) - return false; return ResourceResponse::platformCompare(a, b); } @@ -414,12 +540,4 @@ static void parseCacheHeader(const String& header, Vector<pair<String, String> > } } -static void parseCacheControlDirectiveValues(const String& directives, Vector<String>& result) -{ - directives.split(',', false, result); - unsigned max = result.size(); - for (unsigned i = 0; i < max; ++i) - result[i] = result[i].stripWhiteSpace(); -} - } diff --git a/WebCore/platform/network/ResourceResponseBase.h b/WebCore/platform/network/ResourceResponseBase.h index ff34a26..7138908 100644 --- a/WebCore/platform/network/ResourceResponseBase.h +++ b/WebCore/platform/network/ResourceResponseBase.h @@ -77,25 +77,21 @@ public: bool isMultipart() const { return mimeType() == "multipart/x-mixed-replace"; } bool isAttachment() const; - - void setExpirationDate(time_t); - time_t expirationDate() const; - + + // FIXME: These are used by PluginStream on some platforms. Calculations may differ from just returning plain Last-odified header. + // Leaving it for now but this should go away in favor of generic solution. void setLastModifiedDate(time_t); - time_t lastModifiedDate() const; - - bool cacheControlContainsNoCache() const - { - if (!m_haveParsedCacheControl) - parseCacheControlDirectives(); - return m_cacheControlContainsNoCache; - } - bool cacheControlContainsMustRevalidate() const - { - if (!m_haveParsedCacheControl) - parseCacheControlDirectives(); - return m_cacheControlContainsMustRevalidate; - } + time_t lastModifiedDate() const; + + // These functions return parsed values of the corresponding response headers. + // NaN means that the header was not present or had invalid value. + bool cacheControlContainsNoCache() const; + bool cacheControlContainsMustRevalidate() const; + double cacheControlMaxAge() const; + double date() const; + double age() const; + double expires() const; + double lastModified() const; // The ResourceResponse subclass may "shadow" this method to provide platform-specific memory usage information unsigned memoryUsage() const @@ -107,29 +103,8 @@ public: static bool compare(const ResourceResponse& a, const ResourceResponse& b); protected: - ResourceResponseBase() - : m_expectedContentLength(0) - , m_httpStatusCode(0) - , m_expirationDate(0) - , m_lastModifiedDate(0) - , m_isNull(true) - , m_haveParsedCacheControl(false) - { - } - - ResourceResponseBase(const KURL& url, const String& mimeType, long long expectedLength, const String& textEncodingName, const String& filename) - : m_url(url) - , m_mimeType(mimeType) - , m_expectedContentLength(expectedLength) - , m_textEncodingName(textEncodingName) - , m_suggestedFilename(filename) - , m_httpStatusCode(0) - , m_expirationDate(0) - , m_lastModifiedDate(0) - , m_isNull(false) - , m_haveParsedCacheControl(false) - { - } + ResourceResponseBase(); + ResourceResponseBase(const KURL& url, const String& mimeType, long long expectedLength, const String& textEncodingName, const String& filename); void lazyInit() const; @@ -147,16 +122,27 @@ protected: int m_httpStatusCode; String m_httpStatusText; HTTPHeaderMap m_httpHeaderFields; - time_t m_expirationDate; time_t m_lastModifiedDate; - bool m_isNull : 1; + bool m_isNull : 1; + private: void parseCacheControlDirectives() const; - mutable bool m_haveParsedCacheControl : 1; - mutable bool m_cacheControlContainsMustRevalidate : 1; + mutable bool m_haveParsedCacheControlHeader : 1; + mutable bool m_haveParsedAgeHeader : 1; + mutable bool m_haveParsedDateHeader : 1; + mutable bool m_haveParsedExpiresHeader : 1; + mutable bool m_haveParsedLastModifiedHeader : 1; + mutable bool m_cacheControlContainsNoCache : 1; + mutable bool m_cacheControlContainsMustRevalidate : 1; + mutable double m_cacheControlMaxAge; + + mutable double m_age; + mutable double m_date; + mutable double m_expires; + mutable double m_lastModified; }; inline bool operator==(const ResourceResponse& a, const ResourceResponse& b) { return ResourceResponseBase::compare(a, b); } @@ -171,11 +157,7 @@ struct CrossThreadResourceResponseData { int m_httpStatusCode; String m_httpStatusText; OwnPtr<CrossThreadHTTPHeaderMapData> m_httpHeaders; - time_t m_expirationDate; time_t m_lastModifiedDate; - bool m_haveParsedCacheControl : 1; - bool m_cacheControlContainsMustRevalidate : 1; - bool m_cacheControlContainsNoCache : 1; }; } // namespace WebCore diff --git a/WebCore/platform/network/android/Cookie.cpp b/WebCore/platform/network/android/Cookie.cpp index 0b7aa45..c461e83 100644 --- a/WebCore/platform/network/android/Cookie.cpp +++ b/WebCore/platform/network/android/Cookie.cpp @@ -34,10 +34,10 @@ namespace WebCore { class Document; - void setCookies(Document* , const KURL& url, const KURL& policyBaseURL, const String& value) + void setCookies(Document*, const KURL& url, const String& value) { if (JavaSharedClient::GetCookieClient()) - JavaSharedClient::GetCookieClient()->setCookies(url, policyBaseURL, value); + JavaSharedClient::GetCookieClient()->setCookies(url, value); } String cookies(const Document* , const KURL& url) diff --git a/WebCore/platform/network/android/CookieClient.h b/WebCore/platform/network/android/CookieClient.h index 4b6ffef..7cb28a0 100644 --- a/WebCore/platform/network/android/CookieClient.h +++ b/WebCore/platform/network/android/CookieClient.h @@ -37,7 +37,7 @@ namespace android { { public: virtual ~CookieClient() {} - virtual void setCookies(const KURL& url, const KURL& docURL, const String& value) = 0; + virtual void setCookies(const KURL& url, const String& value) = 0; virtual String cookies(const KURL& url) = 0; virtual bool cookiesEnabled() = 0; }; diff --git a/WebCore/platform/network/android/ResourceHandleAndroid.cpp b/WebCore/platform/network/android/ResourceHandleAndroid.cpp index 59084ab..7fe8ecf 100644 --- a/WebCore/platform/network/android/ResourceHandleAndroid.cpp +++ b/WebCore/platform/network/android/ResourceHandleAndroid.cpp @@ -143,7 +143,8 @@ private: WTF::Vector<char>* m_data; }; -void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, +void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, + StoredCredentials /*storedCredentials*/, ResourceError& error, ResourceResponse& response, WTF::Vector<char>& data, Frame* frame) { diff --git a/WebCore/platform/network/cf/AuthenticationCF.cpp b/WebCore/platform/network/cf/AuthenticationCF.cpp index bb05a39..51d60a4 100644 --- a/WebCore/platform/network/cf/AuthenticationCF.cpp +++ b/WebCore/platform/network/cf/AuthenticationCF.cpp @@ -37,6 +37,8 @@ namespace WebCore { +CFMutableDictionaryRef WebCoreCredentialStorage::m_storage; + AuthenticationChallenge::AuthenticationChallenge(const ProtectionSpace& protectionSpace, const Credential& proposedCredential, unsigned previousFailureCount, diff --git a/WebCore/platform/network/cf/AuthenticationCF.h b/WebCore/platform/network/cf/AuthenticationCF.h index 681e71f..d3fc014 100644 --- a/WebCore/platform/network/cf/AuthenticationCF.h +++ b/WebCore/platform/network/cf/AuthenticationCF.h @@ -43,6 +43,25 @@ CFURLProtectionSpaceRef createCF(const ProtectionSpace&); Credential core(CFURLCredentialRef); ProtectionSpace core(CFURLProtectionSpaceRef); +class WebCoreCredentialStorage { +public: + static void set(CFURLProtectionSpaceRef protectionSpace, CFURLCredentialRef credential) + { + if (!m_storage) + m_storage = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue(m_storage, protectionSpace, credential); + } + + static CFURLCredentialRef get(CFURLProtectionSpaceRef protectionSpace) + { + if (!m_storage) + return 0; + return (CFURLCredentialRef)CFDictionaryGetValue(m_storage, protectionSpace); + } + +private: + static CFMutableDictionaryRef m_storage; +}; } diff --git a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp index 2dcbbed..1d5bf9f 100644 --- a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp +++ b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp @@ -37,7 +37,7 @@ #include "Frame.h" #include "FrameLoader.h" #include "Logging.h" -#include "NotImplemented.h" +#include "MIMETypeRegistry.h" #include "ResourceError.h" #include "ResourceResponse.h" @@ -53,6 +53,38 @@ namespace WebCore { +static CFStringRef WebCoreSynchronousLoaderRunLoopMode = CFSTR("WebCoreSynchronousLoaderRunLoopMode"); + +class WebCoreSynchronousLoader { +public: + static RetainPtr<CFDataRef> load(const ResourceRequest&, StoredCredentials, ResourceResponse&, ResourceError&); + +private: + WebCoreSynchronousLoader(ResourceResponse& response, ResourceError& error) + : m_isDone(false) + , m_response(response) + , m_error(error) + { + } + + static CFURLRequestRef willSendRequest(CFURLConnectionRef, CFURLRequestRef, CFURLResponseRef, const void* clientInfo); + static void didReceiveResponse(CFURLConnectionRef, CFURLResponseRef, const void* clientInfo); + static void didReceiveData(CFURLConnectionRef, CFDataRef, CFIndex, const void* clientInfo); + static void didFinishLoading(CFURLConnectionRef, const void* clientInfo); + static void didFail(CFURLConnectionRef, CFErrorRef, const void* clientInfo); + static void didReceiveChallenge(CFURLConnectionRef, CFURLAuthChallengeRef, const void* clientInfo); + static Boolean shouldUseCredentialStorage(CFURLConnectionRef, const void* clientInfo); + + bool m_isDone; + RetainPtr<CFURLRef> m_url; + RetainPtr<CFStringRef> m_user; + RetainPtr<CFStringRef> m_pass; + bool m_allowStoredCredentials; + ResourceResponse& m_response; + RetainPtr<CFMutableDataRef> m_data; + ResourceError& m_error; +}; + static HashSet<String>& allowsAnyHTTPSCertificateHosts() { static HashSet<String> hosts; @@ -66,9 +98,16 @@ static HashMap<String, RetainPtr<CFDataRef> >& clientCerts() return certs; } +static void setDefaultMIMEType(CFURLResponseRef response) +{ + static CFStringRef defaultMIMETypeString = defaultMIMEType().createCFString(); + + CFURLResponseSetMIMEType(response, defaultMIMETypeString); +} + CFURLRequestRef willSendRequest(CFURLConnectionRef conn, CFURLRequestRef cfRequest, CFURLResponseRef cfRedirectResponse, const void* clientInfo) { - ResourceHandle* handle = (ResourceHandle*)clientInfo; + ResourceHandle* handle = static_cast<ResourceHandle*>(const_cast<void*>(clientInfo)); if (!cfRedirectResponse) { CFRetain(cfRequest); @@ -78,8 +117,7 @@ CFURLRequestRef willSendRequest(CFURLConnectionRef conn, CFURLRequestRef cfReque LOG(Network, "CFNet - willSendRequest(conn=%p, handle=%p) (%s)", conn, handle, handle->request().url().string().utf8().data()); ResourceRequest request(cfRequest); - if (handle->client()) - handle->client()->willSendRequest(handle, request, cfRedirectResponse); + handle->willSendRequest(request, cfRedirectResponse); cfRequest = request.cfURLRequest(); @@ -89,17 +127,25 @@ CFURLRequestRef willSendRequest(CFURLConnectionRef conn, CFURLRequestRef cfReque void didReceiveResponse(CFURLConnectionRef conn, CFURLResponseRef cfResponse, const void* clientInfo) { - ResourceHandle* handle = (ResourceHandle*)clientInfo; + ResourceHandle* handle = static_cast<ResourceHandle*>(const_cast<void*>(clientInfo)); LOG(Network, "CFNet - didReceiveResponse(conn=%p, handle=%p) (%s)", conn, handle, handle->request().url().string().utf8().data()); - if (handle->client()) - handle->client()->didReceiveResponse(handle, cfResponse); + if (!handle->client()) + return; + + if (!CFURLResponseGetMIMEType(cfResponse)) { + // We should never be applying the default MIMEType if we told the networking layer to do content sniffing for handle. + ASSERT(!handle->shouldContentSniff()); + setDefaultMIMEType(cfResponse); + } + + handle->client()->didReceiveResponse(handle, cfResponse); } void didReceiveData(CFURLConnectionRef conn, CFDataRef data, CFIndex originalLength, const void* clientInfo) { - ResourceHandle* handle = (ResourceHandle*)clientInfo; + ResourceHandle* handle = static_cast<ResourceHandle*>(const_cast<void*>(clientInfo)); const UInt8* bytes = CFDataGetBytePtr(data); CFIndex length = CFDataGetLength(data); @@ -111,7 +157,7 @@ void didReceiveData(CFURLConnectionRef conn, CFDataRef data, CFIndex originalLen static void didSendBodyData(CFURLConnectionRef conn, CFIndex bytesWritten, CFIndex totalBytesWritten, CFIndex totalBytesExpectedToWrite, const void *clientInfo) { - ResourceHandle* handle = (ResourceHandle*)clientInfo; + ResourceHandle* handle = static_cast<ResourceHandle*>(const_cast<void*>(clientInfo)); if (!handle || !handle->client()) return; handle->client()->didSendData(handle, totalBytesWritten, totalBytesExpectedToWrite); @@ -131,7 +177,7 @@ static Boolean shouldUseCredentialStorageCallback(CFURLConnectionRef conn, const void didFinishLoading(CFURLConnectionRef conn, const void* clientInfo) { - ResourceHandle* handle = (ResourceHandle*)clientInfo; + ResourceHandle* handle = static_cast<ResourceHandle*>(const_cast<void*>(clientInfo)); LOG(Network, "CFNet - didFinishLoading(conn=%p, handle=%p) (%s)", conn, handle, handle->request().url().string().utf8().data()); @@ -141,7 +187,7 @@ void didFinishLoading(CFURLConnectionRef conn, const void* clientInfo) void didFail(CFURLConnectionRef conn, CFErrorRef error, const void* clientInfo) { - ResourceHandle* handle = (ResourceHandle*)clientInfo; + ResourceHandle* handle = static_cast<ResourceHandle*>(const_cast<void*>(clientInfo)); LOG(Network, "CFNet - didFail(conn=%p, handle=%p, error = %p) (%s)", conn, handle, error, handle->request().url().string().utf8().data()); @@ -151,7 +197,7 @@ void didFail(CFURLConnectionRef conn, CFErrorRef error, const void* clientInfo) CFCachedURLResponseRef willCacheResponse(CFURLConnectionRef conn, CFCachedURLResponseRef cachedResponse, const void* clientInfo) { - ResourceHandle* handle = (ResourceHandle*)clientInfo; + ResourceHandle* handle = static_cast<ResourceHandle*>(const_cast<void*>(clientInfo)); if (handle->client() && !handle->client()->shouldCacheResponse(handle, cachedResponse)) return 0; @@ -174,7 +220,7 @@ CFCachedURLResponseRef willCacheResponse(CFURLConnectionRef conn, CFCachedURLRes void didReceiveChallenge(CFURLConnectionRef conn, CFURLAuthChallengeRef challenge, const void* clientInfo) { - ResourceHandle* handle = (ResourceHandle*)clientInfo; + ResourceHandle* handle = static_cast<ResourceHandle*>(const_cast<void*>(clientInfo)); ASSERT(handle); LOG(Network, "CFNet - didReceiveChallenge(conn=%p, handle=%p (%s)", conn, handle, handle->request().url().string().utf8().data()); @@ -273,6 +319,8 @@ static CFURLRequestRef makeFinalRequest(const ResourceRequest& request, bool sho sslProps.adoptCF(CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); CFDictionaryAddValue(sslProps.get(), kCFStreamSSLAllowsAnyRoot, kCFBooleanTrue); CFDictionaryAddValue(sslProps.get(), kCFStreamSSLAllowsExpiredRoots, kCFBooleanTrue); + CFDictionaryAddValue(sslProps.get(), kCFStreamSSLAllowsExpiredCertificates, kCFBooleanTrue); + CFDictionaryAddValue(sslProps.get(), kCFStreamSSLValidatesCertificateChain, kCFBooleanFalse); } HashMap<String, RetainPtr<CFDataRef> >::iterator clientCert = clientCerts().find(request.url().host().lower()); @@ -300,9 +348,17 @@ bool ResourceHandle::start(Frame* frame) if (!frame->page()) return false; + if ((!d->m_user.isEmpty() || !d->m_pass.isEmpty()) && !d->m_request.url().protocolInHTTPFamily()) { + // Credentials for ftp can only be passed in URL, the didReceiveAuthenticationChallenge delegate call won't be made. + KURL urlWithCredentials(d->m_request.url()); + urlWithCredentials.setUser(d->m_user); + urlWithCredentials.setPass(d->m_pass); + d->m_request.setURL(urlWithCredentials); + } + RetainPtr<CFURLRequestRef> request(AdoptCF, makeFinalRequest(d->m_request, d->m_shouldContentSniff)); - CFURLConnectionClient_V3 client = { 3, this, 0, 0, 0, willSendRequest, didReceiveResponse, didReceiveData, NULL, didFinishLoading, didFail, willCacheResponse, didReceiveChallenge, didSendBodyData, shouldUseCredentialStorageCallback, 0}; + CFURLConnectionClient_V3 client = { 3, this, 0, 0, 0, WebCore::willSendRequest, didReceiveResponse, didReceiveData, NULL, didFinishLoading, didFail, willCacheResponse, didReceiveChallenge, didSendBodyData, shouldUseCredentialStorageCallback, 0}; d->m_connection.adoptCF(CFURLConnectionCreate(0, request.get(), reinterpret_cast<CFURLConnectionClient*>(&client))); @@ -334,6 +390,16 @@ bool ResourceHandle::supportsBufferedData() return false; } +void ResourceHandle::willSendRequest(ResourceRequest& request, const ResourceResponse& redirectResponse) +{ + const KURL& url = request.url(); + d->m_user = url.user(); + d->m_pass = url.pass(); + request.removeCredentials(); + + client()->willSendRequest(this, request, redirectResponse); +} + bool ResourceHandle::shouldUseCredentialStorage() { LOG(Network, "CFNet - shouldUseCredentialStorage()"); @@ -351,7 +417,29 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall // Since CFURLConnection networking relies on keeping a reference to the original CFURLAuthChallengeRef, // we make sure that is actually present ASSERT(challenge.cfURLAuthChallengeRef()); - + + if (!d->m_user.isNull() && !d->m_pass.isNull()) { + RetainPtr<CFStringRef> user(AdoptCF, d->m_user.createCFString()); + RetainPtr<CFStringRef> pass(AdoptCF, d->m_pass.createCFString()); + RetainPtr<CFURLCredentialRef> credential(AdoptCF, + CFURLCredentialCreate(kCFAllocatorDefault, user.get(), pass.get(), 0, kCFURLCredentialPersistenceNone)); + WebCoreCredentialStorage::set(CFURLAuthChallengeGetProtectionSpace(challenge.cfURLAuthChallengeRef()), credential.get()); + CFURLConnectionUseCredential(d->m_connection.get(), credential.get(), challenge.cfURLAuthChallengeRef()); + d->m_user = String(); + d->m_pass = String(); + // FIXME: Per the specification, the user shouldn't be asked for credentials if there were incorrect ones provided explicitly. + return; + } + + if (!challenge.previousFailureCount() && (!client() || client()->shouldUseCredentialStorage(this))) { + CFURLCredentialRef credential = WebCoreCredentialStorage::get(CFURLAuthChallengeGetProtectionSpace(challenge.cfURLAuthChallengeRef())); + if (credential) { + ASSERT(CFURLCredentialGetPersistence(credential) == kCFURLCredentialPersistenceNone); + CFURLConnectionUseCredential(d->m_connection.get(), credential, challenge.cfURLAuthChallengeRef()); + return; + } + } + d->m_currentCFChallenge = challenge.cfURLAuthChallengeRef(); d->m_currentWebChallenge = AuthenticationChallenge(d->m_currentCFChallenge, this); @@ -367,9 +455,17 @@ void ResourceHandle::receivedCredential(const AuthenticationChallenge& challenge if (challenge != d->m_currentWebChallenge) return; - CFURLCredentialRef cfCredential = createCF(credential); - CFURLConnectionUseCredential(d->m_connection.get(), cfCredential, challenge.cfURLAuthChallengeRef()); - CFRelease(cfCredential); + if (credential.persistence() == CredentialPersistenceForSession) { + // Manage per-session credentials internally, because once NSURLCredentialPersistencePerSession is used, there is no way + // to ignore it for a particular request (short of removing it altogether). + Credential webCredential(credential.user(), credential.password(), CredentialPersistenceNone); + RetainPtr<CFURLCredentialRef> cfCredential(AdoptCF, createCF(webCredential)); + WebCoreCredentialStorage::set(CFURLAuthChallengeGetProtectionSpace(challenge.cfURLAuthChallengeRef()), cfCredential.get()); + CFURLConnectionUseCredential(d->m_connection.get(), cfCredential.get(), challenge.cfURLAuthChallengeRef()); + } else { + RetainPtr<CFURLCredentialRef> cfCredential(AdoptCF, createCF(credential)); + CFURLConnectionUseCredential(d->m_connection.get(), cfCredential.get(), challenge.cfURLAuthChallengeRef()); + } clearAuthentication(); } @@ -408,31 +504,27 @@ CFURLConnectionRef ResourceHandle::releaseConnectionForDownload() return d->m_connection.releaseRef(); } -void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& vector, Frame*) +void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, StoredCredentials storedCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& vector, Frame*) { ASSERT(!request.isEmpty()); - CFURLResponseRef cfResponse = 0; - CFErrorRef cfError = 0; - RetainPtr<CFURLRequestRef> cfRequest(AdoptCF, makeFinalRequest(request, true)); - CFDataRef data = CFURLConnectionSendSynchronousRequest(cfRequest.get(), &cfResponse, &cfError, request.timeoutInterval()); - - if (cfError) { - error = cfError; - CFRelease(cfError); + RetainPtr<CFDataRef> data = WebCoreSynchronousLoader::load(request, storedCredentials, response, error); + if (!error.isNull()) { response = ResourceResponse(request.url(), String(), 0, String(), String()); - response.setHTTPStatusCode(404); - } else { - response = cfResponse; - if (cfResponse) - CFRelease(cfResponse); + + CFErrorRef cfError = error; + CFStringRef domain = CFErrorGetDomain(cfError); + // FIXME: Return the actual response for failed authentication. + if (domain == kCFErrorDomainCFNetwork) + response.setHTTPStatusCode(CFErrorGetCode(cfError)); + else + response.setHTTPStatusCode(404); } if (data) { ASSERT(vector.isEmpty()); - vector.append(CFDataGetBytePtr(data), CFDataGetLength(data)); - CFRelease(data); + vector.append(CFDataGetBytePtr(data.get()), CFDataGetLength(data.get())); } } @@ -480,4 +572,142 @@ bool ResourceHandle::willLoadFromCache(ResourceRequest& request) return cached; } +CFURLRequestRef WebCoreSynchronousLoader::willSendRequest(CFURLConnectionRef, CFURLRequestRef cfRequest, CFURLResponseRef cfRedirectResponse, const void* clientInfo) +{ + WebCoreSynchronousLoader* loader = static_cast<WebCoreSynchronousLoader*>(const_cast<void*>(clientInfo)); + + // FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests. + if (loader->m_url && !protocolHostAndPortAreEqual(loader->m_url.get(), CFURLRequestGetURL(cfRequest))) { + RetainPtr<CFErrorRef> cfError(AdoptCF, CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainCFNetwork, kCFURLErrorBadServerResponse, 0)); + loader->m_error = cfError.get(); + loader->m_isDone = true; + return 0; + } + + loader->m_url = CFURLRequestGetURL(cfRequest); + + if (cfRedirectResponse) { + // Take user/pass out of the URL. + loader->m_user.adoptCF(CFURLCopyUserName(loader->m_url.get())); + loader->m_pass.adoptCF(CFURLCopyPassword(loader->m_url.get())); + if (loader->m_user || loader->m_pass) { + ResourceRequest requestWithoutCredentials = cfRequest; + requestWithoutCredentials.removeCredentials(); + cfRequest = requestWithoutCredentials.cfURLRequest(); + } + } + + CFRetain(cfRequest); + return cfRequest; +} + +void WebCoreSynchronousLoader::didReceiveResponse(CFURLConnectionRef, CFURLResponseRef cfResponse, const void* clientInfo) +{ + WebCoreSynchronousLoader* loader = static_cast<WebCoreSynchronousLoader*>(const_cast<void*>(clientInfo)); + + loader->m_response = cfResponse; +} + +void WebCoreSynchronousLoader::didReceiveData(CFURLConnectionRef, CFDataRef data, CFIndex originalLength, const void* clientInfo) +{ + WebCoreSynchronousLoader* loader = static_cast<WebCoreSynchronousLoader*>(const_cast<void*>(clientInfo)); + + if (!loader->m_data) + loader->m_data.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, 0)); + + const UInt8* bytes = CFDataGetBytePtr(data); + CFIndex length = CFDataGetLength(data); + + CFDataAppendBytes(loader->m_data.get(), bytes, length); +} + +void WebCoreSynchronousLoader::didFinishLoading(CFURLConnectionRef, const void* clientInfo) +{ + WebCoreSynchronousLoader* loader = static_cast<WebCoreSynchronousLoader*>(const_cast<void*>(clientInfo)); + + loader->m_isDone = true; +} + +void WebCoreSynchronousLoader::didFail(CFURLConnectionRef, CFErrorRef error, const void* clientInfo) +{ + WebCoreSynchronousLoader* loader = static_cast<WebCoreSynchronousLoader*>(const_cast<void*>(clientInfo)); + + loader->m_error = error; + loader->m_isDone = true; +} + +void WebCoreSynchronousLoader::didReceiveChallenge(CFURLConnectionRef conn, CFURLAuthChallengeRef challenge, const void* clientInfo) +{ + WebCoreSynchronousLoader* loader = static_cast<WebCoreSynchronousLoader*>(const_cast<void*>(clientInfo)); + + if (loader->m_user && loader->m_pass) { + RetainPtr<CFURLCredentialRef> credential(AdoptCF, + CFURLCredentialCreate(kCFAllocatorDefault, loader->m_user.get(), loader->m_pass.get(), 0, kCFURLCredentialPersistenceNone)); + WebCoreCredentialStorage::set(CFURLAuthChallengeGetProtectionSpace(challenge), credential.get()); + CFURLConnectionUseCredential(conn, credential.get(), challenge); + loader->m_user = 0; + loader->m_pass = 0; + return; + } + if (!CFURLAuthChallengeGetPreviousFailureCount(challenge) && loader->m_allowStoredCredentials) { + CFURLCredentialRef credential = WebCoreCredentialStorage::get(CFURLAuthChallengeGetProtectionSpace(challenge)); + if (credential) { + ASSERT(CFURLCredentialGetPersistence(credential) == kCFURLCredentialPersistenceNone); + CFURLConnectionUseCredential(conn, credential, challenge); + return; + } + } + // FIXME: The user should be asked for credentials, as in async case. + CFURLConnectionUseCredential(conn, 0, challenge); +} + +Boolean WebCoreSynchronousLoader::shouldUseCredentialStorage(CFURLConnectionRef, const void* clientInfo) +{ + WebCoreSynchronousLoader* loader = static_cast<WebCoreSynchronousLoader*>(const_cast<void*>(clientInfo)); + + // FIXME: We should ask FrameLoaderClient whether using credential storage is globally forbidden. + return loader->m_allowStoredCredentials; +} + +RetainPtr<CFDataRef> WebCoreSynchronousLoader::load(const ResourceRequest& request, StoredCredentials storedCredentials, ResourceResponse& response, ResourceError& error) +{ + ASSERT(response.isNull()); + ASSERT(error.isNull()); + + WebCoreSynchronousLoader loader(response, error); + + KURL url = request.url(); + + loader.m_user.adoptCF(url.user().createCFString()); + loader.m_pass.adoptCF(url.pass().createCFString()); + loader.m_allowStoredCredentials = (storedCredentials == AllowStoredCredentials); + + // Take user/pass out of the URL. + // Credentials for ftp can only be passed in URL, the didReceiveAuthenticationChallenge delegate call won't be made. + RetainPtr<CFURLRequestRef> cfRequest; + if ((loader.m_user || loader.m_pass) && url.protocolInHTTPFamily()) { + ResourceRequest requestWithoutCredentials(request); + requestWithoutCredentials.removeCredentials(); + cfRequest.adoptCF(makeFinalRequest(requestWithoutCredentials, ResourceHandle::shouldContentSniffURL(requestWithoutCredentials.url()))); + } else + cfRequest.adoptCF(makeFinalRequest(request, ResourceHandle::shouldContentSniffURL(request.url()))); + + CFURLConnectionClient_V3 client = { 3, &loader, 0, 0, 0, willSendRequest, didReceiveResponse, didReceiveData, 0, didFinishLoading, didFail, 0, didReceiveChallenge, 0, shouldUseCredentialStorage, 0 }; + RetainPtr<CFURLConnectionRef> connection(AdoptCF, CFURLConnectionCreate(kCFAllocatorDefault, cfRequest.get(), reinterpret_cast<CFURLConnectionClient*>(&client))); + + CFURLConnectionScheduleWithRunLoop(connection.get(), CFRunLoopGetCurrent(), WebCoreSynchronousLoaderRunLoopMode); + CFURLConnectionScheduleDownloadWithRunLoop(connection.get(), CFRunLoopGetCurrent(), WebCoreSynchronousLoaderRunLoopMode); + CFURLConnectionStart(connection.get()); + + while (!loader.m_isDone) + CFRunLoopRunInMode(WebCoreSynchronousLoaderRunLoopMode, UINT_MAX, true); + + CFURLConnectionCancel(connection.get()); + + if (error.isNull() && loader.m_response.mimeType().isNull()) + setDefaultMIMEType(loader.m_response.cfURLResponse()); + + return loader.m_data; +} + } // namespace WebCore diff --git a/WebCore/platform/network/cf/ResourceRequestCFNet.cpp b/WebCore/platform/network/cf/ResourceRequestCFNet.cpp index df6bbf9..7355401 100644 --- a/WebCore/platform/network/cf/ResourceRequestCFNet.cpp +++ b/WebCore/platform/network/cf/ResourceRequestCFNet.cpp @@ -30,6 +30,7 @@ #include "ResourceRequest.h" #include <CFNetwork/CFURLRequestPriv.h> +#include <WebKitSystemInterface/WebKitSystemInterface.h> namespace WebCore { @@ -95,13 +96,15 @@ void ResourceRequest::doUpdatePlatformRequest() CFMutableURLRequestRef cfRequest; RetainPtr<CFURLRef> url(AdoptCF, ResourceRequest::url().createCFURL()); - RetainPtr<CFURLRef> mainDocumentURL(AdoptCF, ResourceRequest::mainDocumentURL().createCFURL()); + RetainPtr<CFURLRef> firstPartyForCookies(AdoptCF, ResourceRequest::firstPartyForCookies().createCFURL()); if (m_cfRequest) { cfRequest = CFURLRequestCreateMutableCopy(0, m_cfRequest.get()); CFURLRequestSetURL(cfRequest, url.get()); - CFURLRequestSetMainDocumentURL(cfRequest, mainDocumentURL.get()); + CFURLRequestSetMainDocumentURL(cfRequest, firstPartyForCookies.get()); + CFURLRequestSetCachePolicy(cfRequest, (CFURLRequestCachePolicy)cachePolicy()); + CFURLRequestSetTimeoutInterval(cfRequest, timeoutInterval()); } else { - cfRequest = CFURLRequestCreateMutable(0, url.get(), (CFURLRequestCachePolicy)cachePolicy(), timeoutInterval(), mainDocumentURL.get()); + cfRequest = CFURLRequestCreateMutable(0, url.get(), (CFURLRequestCachePolicy)cachePolicy(), timeoutInterval(), firstPartyForCookies.get()); } RetainPtr<CFStringRef> requestMethod(AdoptCF, httpMethod().createCFString()); @@ -138,7 +141,7 @@ void ResourceRequest::doUpdateResourceRequest() m_cachePolicy = (ResourceRequestCachePolicy)CFURLRequestGetCachePolicy(m_cfRequest.get()); m_timeoutInterval = CFURLRequestGetTimeoutInterval(m_cfRequest.get()); - m_mainDocumentURL = CFURLRequestGetMainDocumentURL(m_cfRequest.get()); + m_firstPartyForCookies = CFURLRequestGetMainDocumentURL(m_cfRequest.get()); if (CFStringRef method = CFURLRequestCopyHTTPRequestMethod(m_cfRequest.get())) { m_httpMethod = method; CFRelease(method); @@ -162,11 +165,17 @@ void ResourceRequest::doUpdateResourceRequest() for (CFIndex i = 0; i < count; ++i) { CFStringEncoding encoding = reinterpret_cast<CFIndex>(CFArrayGetValueAtIndex(encodingFallbacks.get(), i)); if (encoding != kCFStringEncodingInvalidId) - m_responseContentDispositionEncodingFallbackArray.append(CFStringGetNameOfEncoding(encoding)); + m_responseContentDispositionEncodingFallbackArray.append(CFStringConvertEncodingToIANACharSetName(encoding)); } } m_httpBody = httpBodyFromRequest(m_cfRequest.get()); } +unsigned initializeMaximumHTTPConnectionCountPerHost() +{ + static const unsigned preferredConnectionCount = 6; + return wkInitializeMaximumHTTPConnectionCountPerHost(preferredConnectionCount); +} + } diff --git a/WebCore/platform/network/cf/ResourceResponseCFNet.cpp b/WebCore/platform/network/cf/ResourceResponseCFNet.cpp index 79efe89..95e9aff 100644 --- a/WebCore/platform/network/cf/ResourceResponseCFNet.cpp +++ b/WebCore/platform/network/cf/ResourceResponseCFNet.cpp @@ -24,11 +24,10 @@ */ #include "config.h" -#include "ResourceResponseCFNet.h" +#include "ResourceResponse.h" #include "HTTPParsers.h" #include "MIMETypeRegistry.h" -#include "ResourceResponse.h" #include <CFNetwork/CFURLResponsePriv.h> #include <wtf/RetainPtr.h> @@ -80,7 +79,6 @@ void ResourceResponse::platformLazyInit() m_expectedContentLength = CFURLResponseGetExpectedContentLength(m_cfResponse.get()); m_textEncodingName = CFURLResponseGetTextEncodingName(m_cfResponse.get()); - m_expirationDate = toTimeT(CFURLResponseGetExpirationTime(m_cfResponse.get())); m_lastModifiedDate = toTimeT(CFURLResponseGetLastModifiedDate(m_cfResponse.get())); RetainPtr<CFStringRef> suggestedFilename(AdoptCF, CFURLResponseCopySuggestedFilename(m_cfResponse.get())); @@ -92,9 +90,11 @@ void ResourceResponse::platformLazyInit() RetainPtr<CFStringRef> statusLine(AdoptCF, CFHTTPMessageCopyResponseStatusLine(httpResponse)); String statusText(statusLine.get()); - int spacePos = statusText.find(" "); - if (spacePos != -1) - statusText = statusText.substring(spacePos + 1); + int spacePos = statusText.find(' '); + // Remove the status code from the status text. + spacePos = statusText.find(' ', spacePos + 1); + statusText = statusText.substring(spacePos + 1); + m_httpStatusText = statusText; RetainPtr<CFDictionaryRef> headers(AdoptCF, CFHTTPMessageCopyAllHeaderFields(httpResponse)); diff --git a/WebCore/platform/network/chromium/CookieJarChromium.cpp b/WebCore/platform/network/chromium/CookieJarChromium.cpp index 50cab3b..65be451 100644 --- a/WebCore/platform/network/chromium/CookieJarChromium.cpp +++ b/WebCore/platform/network/chromium/CookieJarChromium.cpp @@ -36,16 +36,14 @@ namespace WebCore { -void setCookies(Document* document, const KURL& url, const KURL& policyURL, const String& value) +void setCookies(Document* document, const KURL& url, const String& value) { - // We ignore the policyURL and compute it directly ourselves to ensure - // consistency with the cookies() method below. - ChromiumBridge::setCookies(url, document->policyBaseURL(), value); + ChromiumBridge::setCookies(url, document->firstPartyForCookies(), value); } String cookies(const Document* document, const KURL& url) { - return ChromiumBridge::cookies(url, document->policyBaseURL()); + return ChromiumBridge::cookies(url, document->firstPartyForCookies()); } bool cookiesEnabled(const Document*) diff --git a/WebCore/platform/network/chromium/ResourceRequest.h b/WebCore/platform/network/chromium/ResourceRequest.h index b14dba6..aa76de4 100644 --- a/WebCore/platform/network/chromium/ResourceRequest.h +++ b/WebCore/platform/network/chromium/ResourceRequest.h @@ -49,6 +49,7 @@ namespace WebCore { : ResourceRequestBase(KURL(url), UseProtocolCachePolicy) , m_requestorID(0) , m_requestorProcessID(0) + , m_appCacheContextID(0) , m_targetType(TargetIsSubResource) { } @@ -57,6 +58,7 @@ namespace WebCore { : ResourceRequestBase(url, UseProtocolCachePolicy) , m_requestorID(0) , m_requestorProcessID(0) + , m_appCacheContextID(0) , m_targetType(TargetIsSubResource) , m_securityInfo(securityInfo) { @@ -66,6 +68,7 @@ namespace WebCore { : ResourceRequestBase(url, UseProtocolCachePolicy) , m_requestorID(0) , m_requestorProcessID(0) + , m_appCacheContextID(0) , m_targetType(TargetIsSubResource) { } @@ -74,6 +77,7 @@ namespace WebCore { : ResourceRequestBase(url, policy) , m_requestorID(0) , m_requestorProcessID(0) + , m_appCacheContextID(0) , m_targetType(TargetIsSubResource) { setHTTPReferrer(referrer); @@ -83,6 +87,7 @@ namespace WebCore { : ResourceRequestBase(KURL(), UseProtocolCachePolicy) , m_requestorID(0) , m_requestorProcessID(0) + , m_appCacheContextID(0) , m_targetType(TargetIsSubResource) { } @@ -95,10 +100,6 @@ namespace WebCore { TargetType targetType() const { return m_targetType; } void setTargetType(TargetType type) { m_targetType = type; } - // The document's policy base url. - KURL policyURL() const { return m_policyURL; } - void setPolicyURL(const KURL& policyURL) { m_policyURL = policyURL; } - // 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 @@ -106,6 +107,10 @@ namespace WebCore { int requestorProcessID() const { return m_requestorProcessID; } void setRequestorProcessID(int requestorProcessID) { m_requestorProcessID = requestorProcessID; } + // Allows the request to be matched up with its app cache context. + int appCacheContextID() const { return m_appCacheContextID; } + void setAppCacheContextID(int id) { m_appCacheContextID = id; } + // Opaque buffer that describes the security state (including SSL // connection state) for the resource that should be reported when the // resource has been loaded. This is used to simulate secure @@ -123,9 +128,9 @@ namespace WebCore { int m_requestorID; int m_requestorProcessID; + int m_appCacheContextID; TargetType m_targetType; CString m_securityInfo; - KURL m_policyURL; }; } // namespace WebCore diff --git a/WebCore/platform/network/chromium/ResourceResponse.h b/WebCore/platform/network/chromium/ResourceResponse.h index 256df74..6c928c0 100644 --- a/WebCore/platform/network/chromium/ResourceResponse.h +++ b/WebCore/platform/network/chromium/ResourceResponse.h @@ -37,12 +37,14 @@ namespace WebCore { public: ResourceResponse() : m_isContentFiltered(false) + , m_appCacheID(0) { } ResourceResponse(const KURL& url, const String& mimeType, long long expectedLength, const String& textEncodingName, const String& filename) - : ResourceResponseBase(url, mimeType, expectedLength, textEncodingName, filename), - m_isContentFiltered(false) + : ResourceResponseBase(url, mimeType, expectedLength, textEncodingName, filename) + , m_isContentFiltered(false) + , m_appCacheID(0) { } @@ -58,6 +60,12 @@ namespace WebCore { m_isContentFiltered = isContentFiltered; } + long long getAppCacheID() const { return m_appCacheID; } + void setAppCacheID(long long id) + { + m_appCacheID = id; + } + private: friend class ResourceResponseBase; @@ -74,6 +82,10 @@ namespace WebCore { // Whether the contents for this response has been altered/blocked (usually // for security reasons. bool m_isContentFiltered; + + // The id of the appcache this response was retrieved from, or zero if + // the response was not retrieved from an appcache. + long long m_appCacheID; }; } // namespace WebCore diff --git a/WebCore/platform/network/curl/CookieJarCurl.cpp b/WebCore/platform/network/curl/CookieJarCurl.cpp index 2f76ebc..5ac0f9c 100644 --- a/WebCore/platform/network/curl/CookieJarCurl.cpp +++ b/WebCore/platform/network/curl/CookieJarCurl.cpp @@ -17,6 +17,7 @@ #include "config.h" #include "CookieJar.h" +#include "Document.h" #include "KURL.h" #include "PlatformString.h" #include "StringHash.h" @@ -27,7 +28,7 @@ namespace WebCore { static HashMap<String, String> cookieJar; -void setCookies(Document* /*document*/, const KURL& url, const KURL& /*policyURL*/, const String& value) +void setCookies(Document* /*document*/, const KURL& url, const String& value) { cookieJar.set(url.string(), value); } diff --git a/WebCore/platform/network/curl/ResourceHandleCurl.cpp b/WebCore/platform/network/curl/ResourceHandleCurl.cpp index ca24ec5..a2e692c 100644 --- a/WebCore/platform/network/curl/ResourceHandleCurl.cpp +++ b/WebCore/platform/network/curl/ResourceHandleCurl.cpp @@ -191,7 +191,7 @@ bool ResourceHandle::loadsBlocked() return false; } -void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data, Frame*) +void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, StoredCredentials storedCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data, Frame*) { WebCoreSynchronousLoader syncLoader; ResourceHandle handle(request, &syncLoader, true, false, true); diff --git a/WebCore/platform/network/curl/ResourceHandleManager.cpp b/WebCore/platform/network/curl/ResourceHandleManager.cpp index 6f009db..c61ad4f 100644 --- a/WebCore/platform/network/curl/ResourceHandleManager.cpp +++ b/WebCore/platform/network/curl/ResourceHandleManager.cpp @@ -46,12 +46,6 @@ #include <stdio.h> #include <wtf/Vector.h> -#if PLATFORM(GTK) - #if GLIB_CHECK_VERSION(2,12,0) - #define USE_GLIB_BASE64 - #endif -#endif - namespace WebCore { const int selectTimeoutMS = 5; @@ -320,13 +314,13 @@ void ResourceHandleManager::downloadTimerCallback(Timer<ResourceHandleManager>* if (d->client()) d->client()->didFinishLoading(job); } else { -#ifndef NDEBUG char* url = 0; curl_easy_getinfo(d->m_handle, CURLINFO_EFFECTIVE_URL, &url); +#ifndef NDEBUG fprintf(stderr, "Curl ERROR for url='%s', error: '%s'\n", url, curl_easy_strerror(msg->data.result)); #endif if (d->client()) - d->client()->didFail(job, ResourceError()); + d->client()->didFail(job, ResourceError(String(), msg->data.result, String(url), String(curl_easy_strerror(msg->data.result)))); } removeFromCurl(job); @@ -512,20 +506,10 @@ static void parseDataUrl(ResourceHandle* handle) response.setTextEncodingName(charset); client->didReceiveResponse(handle, response); - // Use the GLib Base64 if available, since WebCore's decoder isn't - // general-purpose and fails on Acid3 test 97 (whitespace). -#ifdef USE_GLIB_BASE64 - size_t outLength = 0; - char* outData = 0; - outData = reinterpret_cast<char*>(g_base64_decode(data.utf8().data(), &outLength)); - if (outData && outLength > 0) - client->didReceiveData(handle, outData, outLength, 0); - g_free(outData); -#else + // WebCore's decoder fails on Acid3 test 97 (whitespace). Vector<char> out; if (base64Decode(data.latin1().data(), data.latin1().length(), out) && out.size() > 0) client->didReceiveData(handle, out.data(), out.size(), 0); -#endif } else { // We have to convert to UTF-16 early due to limitations in KURL data = decodeURLEscapeSequences(data, TextEncoding(charset)); @@ -606,8 +590,11 @@ void ResourceHandleManager::initializeHandle(ResourceHandle* job) if (kurl.isLocalFile()) { String query = kurl.query(); // Remove any query part sent to a local file. - if (!query.isEmpty()) - url = url.left(url.find(query)); + if (!query.isEmpty()) { + int queryIndex = url.find(query); + if (queryIndex != -1) + url = url.left(queryIndex - 1); + } // Determine the MIME type based on the path. d->m_response.setMimeType(MIMETypeRegistry::getMIMETypeForPath(url)); } diff --git a/WebCore/platform/network/mac/AuthenticationMac.h b/WebCore/platform/network/mac/AuthenticationMac.h index f55ac24..7fb6bee 100644 --- a/WebCore/platform/network/mac/AuthenticationMac.h +++ b/WebCore/platform/network/mac/AuthenticationMac.h @@ -45,6 +45,24 @@ AuthenticationChallenge core(NSURLAuthenticationChallenge *); ProtectionSpace core(NSURLProtectionSpace *); Credential core(NSURLCredential *); +class WebCoreCredentialStorage { +public: + static void set(NSURLCredential *credential, NSURLProtectionSpace *protectionSpace) + { + if (!m_storage) + m_storage = [[NSMutableDictionary alloc] init]; + [m_storage setObject:credential forKey:protectionSpace]; + } + + static NSURLCredential *get(NSURLProtectionSpace *protectionSpace) + { + return static_cast<NSURLCredential *>([m_storage objectForKey:protectionSpace]); + } + +private: + static NSMutableDictionary* m_storage; +}; + } #endif diff --git a/WebCore/platform/network/mac/AuthenticationMac.mm b/WebCore/platform/network/mac/AuthenticationMac.mm index 54e7681..961a79d 100644 --- a/WebCore/platform/network/mac/AuthenticationMac.mm +++ b/WebCore/platform/network/mac/AuthenticationMac.mm @@ -37,6 +37,8 @@ namespace WebCore { +NSMutableDictionary* WebCoreCredentialStorage::m_storage; + AuthenticationChallenge::AuthenticationChallenge(const ProtectionSpace& protectionSpace, const Credential& proposedCredential, unsigned previousFailureCount, diff --git a/WebCore/platform/network/mac/ResourceHandleMac.mm b/WebCore/platform/network/mac/ResourceHandleMac.mm index 9bc322d..3af1b97 100644 --- a/WebCore/platform/network/mac/ResourceHandleMac.mm +++ b/WebCore/platform/network/mac/ResourceHandleMac.mm @@ -33,15 +33,23 @@ #import "FormDataStreamMac.h" #import "Frame.h" #import "FrameLoader.h" +#import "Logging.h" +#import "MIMETypeRegistry.h" #import "Page.h" #import "ResourceError.h" #import "ResourceResponse.h" #import "SchedulePair.h" +#import "Settings.h" #import "SharedBuffer.h" #import "SubresourceLoader.h" #import "WebCoreSystemInterface.h" +#import "WebCoreURLResponse.h" #import <wtf/UnusedParam.h> +#ifndef BUILDING_ON_TIGER +#import <objc/objc-class.h> +#endif + #ifdef BUILDING_ON_TIGER typedef int NSInteger; #endif @@ -51,9 +59,6 @@ using namespace WebCore; @interface WebCoreResourceHandleAsDelegate : NSObject <NSURLAuthenticationChallengeSender> { ResourceHandle* m_handle; -#ifndef BUILDING_ON_TIGER - NSURL *m_url; -#endif } - (id)initWithHandle:(ResourceHandle*)handle; - (void)detachHandle; @@ -63,20 +68,34 @@ using namespace WebCore; - (NSData *)_bufferedData; @end +@interface NSURLResponse (Details) +- (void)_setMIMEType:(NSString *)type; +@end + +@interface NSURLRequest (Details) +- (id)_propertyForKey:(NSString *)key; +@end + #ifndef BUILDING_ON_TIGER @interface WebCoreSynchronousLoader : NSObject { NSURL *m_url; + NSString *m_user; + NSString *m_pass; + BOOL m_allowStoredCredentials; NSURLResponse *m_response; NSMutableData *m_data; NSError *m_error; BOOL m_isDone; } -+ (NSData *)loadRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error; ++ (NSData *)loadRequest:(NSURLRequest *)request allowStoredCredentials:(BOOL)allowStoredCredentials returningResponse:(NSURLResponse **)response error:(NSError **)error; @end static NSString *WebCoreSynchronousLoaderRunLoopMode = @"WebCoreSynchronousLoaderRunLoopMode"; +static IMP oldNSURLResponseMIMETypeIMP = 0; +static NSString *webNSURLResponseMIMEType(id, SEL); + #endif namespace WebCore { @@ -113,6 +132,8 @@ ResourceHandleInternal::~ResourceHandleInternal() ResourceHandle::~ResourceHandle() { releaseDelegate(); + + LOG(Network, "Handle %p destroyed", this); } static const double MaxFoundationVersionWithoutdidSendBodyDataDelegate = 677.21; @@ -150,9 +171,19 @@ bool ResourceHandle::start(Frame* frame) } else delegate = ResourceHandle::delegate(); + if ((!d->m_user.isEmpty() || !d->m_pass.isEmpty()) && !d->m_request.url().protocolInHTTPFamily()) { + // Credentials for ftp can only be passed in URL, the connection:didReceiveAuthenticationChallenge: delegate call won't be made. + KURL urlWithCredentials(d->m_request.url()); + urlWithCredentials.setUser(d->m_user); + urlWithCredentials.setPass(d->m_pass); + d->m_request.setURL(urlWithCredentials); + } + if (!ResourceHandle::didSendBodyDataDelegateExists()) associateStreamWithResourceHandle([d->m_request.nsURLRequest() HTTPBodyStream], this); + d->m_needsSiteSpecificQuirks = frame->settings() && frame->settings()->needsSiteSpecificQuirks(); + NSURLConnection *connection; if (d->m_shouldContentSniff) @@ -195,6 +226,8 @@ bool ResourceHandle::start(Frame* frame) #ifndef NDEBUG isInitializingConnection = NO; #endif + + LOG(Network, "Handle %p starting connection %p for %@", this, connection, d->m_request.nsURLRequest()); d->m_connection = connection; @@ -214,6 +247,8 @@ bool ResourceHandle::start(Frame* frame) void ResourceHandle::cancel() { + LOG(Network, "Handle %p cancel connection %p", this, d->m_connection.get()); + if (!ResourceHandle::didSendBodyDataDelegateExists()) disassociateStreamWithResourceHandle([d->m_request.nsURLRequest() HTTPBodyStream]); [d->m_connection.get() cancel]; @@ -221,6 +256,8 @@ void ResourceHandle::cancel() void ResourceHandle::setDefersLoading(bool defers) { + LOG(Network, "Handle %p setDefersLoading(%s)", this, defers ? "true" : "false"); + d->m_defersLoading = defers; if (d->m_connection) wkSetNSURLConnectionDefersCallbacks(d->m_connection.get(), defers); @@ -313,6 +350,7 @@ bool ResourceHandle::loadsBlocked() bool ResourceHandle::willLoadFromCache(ResourceRequest& request) { +#ifndef BUILDING_ON_TIGER request.setCachePolicy(ReturnCacheDataDontLoad); NSURLResponse *nsURLResponse = nil; BEGIN_BLOCK_OBJC_EXCEPTIONS; @@ -322,9 +360,14 @@ bool ResourceHandle::willLoadFromCache(ResourceRequest& request) END_BLOCK_OBJC_EXCEPTIONS; return nsURLResponse; +#else + // <rdar://problem/6803217> - Re-enable after <rdar://problem/6786454> is resolved. + UNUSED_PARAM(request); + return false; +#endif } -void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data, Frame*) +void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, StoredCredentials storedCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data, Frame*) { NSError *nsError = nil; @@ -333,12 +376,21 @@ void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, R ASSERT(!request.isEmpty()); + NSURLRequest *nsRequest; + if (!shouldContentSniffURL(request.url())) { + NSMutableURLRequest *mutableRequest = [[request.nsURLRequest() mutableCopy] autorelease]; + wkSetNSURLRequestShouldContentSniff(mutableRequest, NO); + nsRequest = mutableRequest; + } else + nsRequest = request.nsURLRequest(); + BEGIN_BLOCK_OBJC_EXCEPTIONS; #ifndef BUILDING_ON_TIGER - result = [WebCoreSynchronousLoader loadRequest:request.nsURLRequest() returningResponse:&nsURLResponse error:&nsError]; + result = [WebCoreSynchronousLoader loadRequest:nsRequest allowStoredCredentials:(storedCredentials == AllowStoredCredentials) returningResponse:&nsURLResponse error:&nsError]; #else - result = [NSURLConnection sendSynchronousRequest:request.nsURLRequest() returningResponse:&nsURLResponse error:&nsError]; + UNUSED_PARAM(storedCredentials); + result = [NSURLConnection sendSynchronousRequest:nsRequest returningResponse:&nsURLResponse error:&nsError]; #endif END_BLOCK_OBJC_EXCEPTIONS; @@ -365,6 +417,16 @@ void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, R error = nsError; } +void ResourceHandle::willSendRequest(ResourceRequest& request, const ResourceResponse& redirectResponse) +{ + const KURL& url = request.url(); + d->m_user = url.user(); + d->m_pass = url.pass(); + request.removeCredentials(); + + client()->willSendRequest(this, request, redirectResponse); +} + bool ResourceHandle::shouldUseCredentialStorage() { if (client()) @@ -380,7 +442,29 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall // Since NSURLConnection networking relies on keeping a reference to the original NSURLAuthenticationChallenge, // we make sure that is actually present ASSERT(challenge.nsURLAuthenticationChallenge()); - + + if (!d->m_user.isNull() && !d->m_pass.isNull()) { + NSURLCredential *credential = [[NSURLCredential alloc] initWithUser:d->m_user + password:d->m_pass + persistence:NSURLCredentialPersistenceNone]; + d->m_currentMacChallenge = challenge.nsURLAuthenticationChallenge(); + d->m_currentWebChallenge = challenge; + receivedCredential(challenge, core(credential)); + [credential release]; + // FIXME: Per the specification, the user shouldn't be asked for credentials if there were incorrect ones provided explicitly. + d->m_user = String(); + d->m_pass = String(); + return; + } + + if (!challenge.previousFailureCount() && (!client() || client()->shouldUseCredentialStorage(this))) { + NSURLCredential *credential = WebCoreCredentialStorage::get([mac(challenge) protectionSpace]); + if (credential) { + [challenge.sender() useCredential:credential forAuthenticationChallenge:mac(challenge)]; + return; + } + } + d->m_currentMacChallenge = challenge.nsURLAuthenticationChallenge(); NSURLAuthenticationChallenge *webChallenge = [[NSURLAuthenticationChallenge alloc] initWithAuthenticationChallenge:d->m_currentMacChallenge sender:(id<NSURLAuthenticationChallengeSender>)delegate()]; @@ -407,7 +491,24 @@ void ResourceHandle::receivedCredential(const AuthenticationChallenge& challenge if (challenge != d->m_currentWebChallenge) return; - [[d->m_currentMacChallenge sender] useCredential:mac(credential) forAuthenticationChallenge:d->m_currentMacChallenge]; +#ifdef BUILDING_ON_TIGER + if (credential.persistence() == CredentialPersistenceNone) { + // NSURLCredentialPersistenceNone doesn't work on Tiger, so we have to use session persistence. + Credential webCredential(credential.user(), credential.password(), CredentialPersistenceForSession); + WebCoreCredentialStorage::set(mac(webCredential), [d->m_currentMacChallenge protectionSpace]); + [[d->m_currentMacChallenge sender] useCredential:mac(webCredential) forAuthenticationChallenge:d->m_currentMacChallenge]; + } else +#else + if (credential.persistence() == CredentialPersistenceForSession && (!d->m_needsSiteSpecificQuirks || ![[[mac(challenge) protectionSpace] host] isEqualToString:@"gallery.me.com"])) { + // 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); + WebCoreCredentialStorage::set(mac(webCredential), [d->m_currentMacChallenge protectionSpace]); + [[d->m_currentMacChallenge sender] useCredential:mac(webCredential) forAuthenticationChallenge:d->m_currentMacChallenge]; + } else +#endif + [[d->m_currentMacChallenge sender] useCredential:mac(credential) forAuthenticationChallenge:d->m_currentMacChallenge]; clearAuthentication(); } @@ -445,22 +546,14 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen return self; } -#ifndef BUILDING_ON_TIGER -- (void)dealloc -{ - [m_url release]; - [super dealloc]; -} -#endif - - (void)detachHandle { m_handle = 0; } -- (NSURLRequest *)connection:(NSURLConnection *)unusedConnection willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse +- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse { - UNUSED_PARAM(unusedConnection); + UNUSED_PARAM(connection); // the willSendRequest call may cancel this load, in which case self could be deallocated RetainPtr<WebCoreResourceHandleAsDelegate> protect(self); @@ -472,14 +565,11 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen if (!redirectResponse) return newRequest; + LOG(Network, "Handle %p delegate connection:%p willSendRequest:%@ redirectResponse:%p", m_handle, connection, [newRequest description], redirectResponse); + CallbackGuard guard; ResourceRequest request = newRequest; - m_handle->client()->willSendRequest(m_handle, request, redirectResponse); -#ifndef BUILDING_ON_TIGER - NSURL *copy = [[request.nsURLRequest() URL] copy]; - [m_url release]; - m_url = copy; -#endif + m_handle->willSendRequest(request, redirectResponse); if (!ResourceHandle::didSendBodyDataDelegateExists()) { // The client may change the request's body stream, in which case we have to re-associate @@ -495,9 +585,11 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen return request.nsURLRequest(); } -- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)unusedConnection +- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection { - UNUSED_PARAM(unusedConnection); + UNUSED_PARAM(connection); + + LOG(Network, "Handle %p delegate connectionShouldUseCredentialStorage:%p", m_handle, connection); if (!m_handle) return NO; @@ -506,35 +598,23 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen return m_handle->shouldUseCredentialStorage(); } -- (void)connection:(NSURLConnection *)unusedConnection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge +- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { - UNUSED_PARAM(unusedConnection); + UNUSED_PARAM(connection); + + LOG(Network, "Handle %p delegate connection:%p didReceiveAuthenticationChallenge:%p", m_handle, connection, challenge); -#ifndef BUILDING_ON_TIGER - if ([challenge previousFailureCount] == 0) { - NSString *user = [m_url user]; - NSString *password = [m_url password]; - - if (user && password) { - NSURLCredential *credential = [[NSURLCredential alloc] initWithUser:user - password:password - persistence:NSURLCredentialPersistenceForSession]; - [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; - [credential release]; - return; - } - } -#endif - if (!m_handle) return; CallbackGuard guard; m_handle->didReceiveAuthenticationChallenge(core(challenge)); } -- (void)connection:(NSURLConnection *)unusedConnection didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge +- (void)connection:(NSURLConnection *)connection didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { - UNUSED_PARAM(unusedConnection); + UNUSED_PARAM(connection); + + LOG(Network, "Handle %p delegate connection:%p didCancelAuthenticationChallenge:%p", m_handle, connection, challenge); if (!m_handle) return; @@ -542,19 +622,51 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen m_handle->didCancelAuthenticationChallenge(core(challenge)); } -- (void)connection:(NSURLConnection *)unusedConnection didReceiveResponse:(NSURLResponse *)r +- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)r { - UNUSED_PARAM(unusedConnection); + UNUSED_PARAM(connection); + + LOG(Network, "Handle %p delegate connection:%p didReceiveResponse:%p (HTTP status %d)", m_handle, connection, r, [r respondsToSelector:@selector(statusCode)] ? [(id)r statusCode] : 0); if (!m_handle || !m_handle->client()) return; CallbackGuard guard; + +#ifndef BUILDING_ON_TIGER + if (!oldNSURLResponseMIMETypeIMP) { + Method nsURLResponseMIMETypeMethod = class_getInstanceMethod(objc_getClass("NSURLResponse"), @selector(MIMEType)); + ASSERT(nsURLResponseMIMETypeMethod); + oldNSURLResponseMIMETypeIMP = method_setImplementation(nsURLResponseMIMETypeMethod, (IMP)webNSURLResponseMIMEType); + } +#endif + + if ([m_handle->request().nsURLRequest() _propertyForKey:@"ForceHTMLMIMEType"]) + [r _setMIMEType:@"text/html"]; + +#if ENABLE(WML) + const KURL& url = [r URL]; + if (url.isLocalFile()) { + // FIXME: Workaround for <rdar://problem/6917571>: The WML file extension ".wml" is not mapped to + // the right MIME type, work around that CFNetwork problem, to unbreak WML support for local files. + const String& path = url.path(); + + DEFINE_STATIC_LOCAL(const String, wmlExt, (".wml")); + if (path.endsWith(wmlExt, false)) { + static NSString* defaultMIMETypeString = [(NSString*) defaultMIMEType() retain]; + if ([[r _webcore_MIMEType] isEqualToString:defaultMIMETypeString]) + [r _setMIMEType:@"text/vnd.wap.wml"]; + } + } +#endif + m_handle->client()->didReceiveResponse(m_handle, r); } -- (void)connection:(NSURLConnection *)unusedConnection didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived { - UNUSED_PARAM(unusedConnection); + UNUSED_PARAM(connection); + + LOG(Network, "Handle %p delegate connection:%p didReceiveData:%p lengthReceived:%lld", m_handle, connection, data, lengthReceived); if (!m_handle || !m_handle->client()) return; @@ -565,9 +677,11 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen m_handle->client()->didReceiveData(m_handle, (const char*)[data bytes], [data length], static_cast<int>(lengthReceived)); } -- (void)connection:(NSURLConnection *)unusedConnection willStopBufferingData:(NSData *)data +- (void)connection:(NSURLConnection *)connection willStopBufferingData:(NSData *)data { - UNUSED_PARAM(unusedConnection); + UNUSED_PARAM(connection); + + LOG(Network, "Handle %p delegate connection:%p willStopBufferingData:%p", m_handle, connection, data); if (!m_handle || !m_handle->client()) return; @@ -578,10 +692,12 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen m_handle->client()->willStopBufferingData(m_handle, (const char*)[data bytes], static_cast<int>([data length])); } -- (void)connection:(NSURLConnection *)unusedConnection didSendBodyData:(NSInteger)unusedBytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite +- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite { - UNUSED_PARAM(unusedConnection); - UNUSED_PARAM(unusedBytesWritten); + UNUSED_PARAM(connection); + UNUSED_PARAM(bytesWritten); + + LOG(Network, "Handle %p delegate connection:%p didSendBodyData:%d totalBytesWritten:%d totalBytesExpectedToWrite:%d", m_handle, connection, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite); if (!m_handle || !m_handle->client()) return; @@ -589,9 +705,11 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen m_handle->client()->didSendData(m_handle, totalBytesWritten, totalBytesExpectedToWrite); } -- (void)connectionDidFinishLoading:(NSURLConnection *)unusedConnection +- (void)connectionDidFinishLoading:(NSURLConnection *)connection { - UNUSED_PARAM(unusedConnection); + UNUSED_PARAM(connection); + + LOG(Network, "Handle %p delegate connectionDidFinishLoading:%p", m_handle, connection); if (!m_handle || !m_handle->client()) return; @@ -603,9 +721,11 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen m_handle->client()->didFinishLoading(m_handle); } -- (void)connection:(NSURLConnection *)unusedConnection didFailWithError:(NSError *)error +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { - UNUSED_PARAM(unusedConnection); + UNUSED_PARAM(connection); + + LOG(Network, "Handle %p delegate connection:%p didFailWithError:%@", m_handle, connection, error); if (!m_handle || !m_handle->client()) return; @@ -630,6 +750,8 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen - (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse { + LOG(Network, "Handle %p delegate connection:%p willCacheResponse:%p", m_handle, connection, cachedResponse); + #ifdef BUILDING_ON_TIGER // On Tiger CFURLConnection can sometimes call the connection:willCacheResponse: delegate method on // a secondary thread instead of the main thread. If this happens perform the work on the main thread. @@ -717,6 +839,8 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen - (void)dealloc { [m_url release]; + [m_user release]; + [m_pass release]; [m_response release]; [m_data release]; [m_error release]; @@ -724,36 +848,71 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen [super dealloc]; } -- (NSURLRequest *)connection:(NSURLConnection *)unusedConnection willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)unusedRedirectResponse +- (NSURLRequest *)connection:(NSURLConnection *)unusedConnection willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse { UNUSED_PARAM(unusedConnection); - UNUSED_PARAM(unusedRedirectResponse); + + // FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests. + if (m_url && !protocolHostAndPortAreEqual(m_url, [newRequest URL])) { + m_error = [[NSError alloc] initWithDomain:NSURLErrorDomain code:NSURLErrorBadServerResponse userInfo:nil]; + m_isDone = YES; + return nil; + } NSURL *copy = [[newRequest URL] copy]; [m_url release]; m_url = copy; + if (redirectResponse) { + // Take user/pass out of the URL. + [m_user release]; + [m_pass release]; + m_user = [[m_url user] copy]; + m_pass = [[m_url password] copy]; + if (m_user || m_pass) { + ResourceRequest requestWithoutCredentials = newRequest; + requestWithoutCredentials.removeCredentials(); + return requestWithoutCredentials.nsURLRequest(); + } + } + return newRequest; } +- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)unusedConnection +{ + UNUSED_PARAM(unusedConnection); + + // FIXME: We should ask FrameLoaderClient whether using credential storage is globally forbidden. + return m_allowStoredCredentials; +} + - (void)connection:(NSURLConnection *)unusedConnection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { UNUSED_PARAM(unusedConnection); - if ([challenge previousFailureCount] == 0) { - NSString *user = [m_url user]; - NSString *password = [m_url password]; - - if (user && password) { - NSURLCredential *credential = [[NSURLCredential alloc] initWithUser:user - password:password - persistence:NSURLCredentialPersistenceForSession]; + if (m_user && m_pass) { + NSURLCredential *credential = [[NSURLCredential alloc] initWithUser:m_user + password:m_pass + persistence:NSURLCredentialPersistenceNone]; + WebCoreCredentialStorage::set(credential, [challenge protectionSpace]); + [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; + [credential release]; + [m_user release]; + [m_pass release]; + m_user = 0; + m_pass = 0; + return; + } + if ([challenge previousFailureCount] == 0 && m_allowStoredCredentials) { + NSURLCredential *credential = WebCoreCredentialStorage::get([challenge protectionSpace]); + ASSERT([credential persistence] == NSURLCredentialPersistenceNone); + if (credential) { [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; - [credential release]; return; } } - + // FIXME: The user should be asked for credentials, as in async case. [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge]; } @@ -809,11 +968,26 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen return [[m_error retain] autorelease]; } -+ (NSData *)loadRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error ++ (NSData *)loadRequest:(NSURLRequest *)request allowStoredCredentials:(BOOL)allowStoredCredentials returningResponse:(NSURLResponse **)response error:(NSError **)error { WebCoreSynchronousLoader *delegate = [[WebCoreSynchronousLoader alloc] init]; - - NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:delegate startImmediately:NO]; + + NSURL *url = [request URL]; + delegate->m_user = [[url user] copy]; + delegate->m_pass = [[url password] copy]; + delegate->m_allowStoredCredentials = allowStoredCredentials; + + NSURLConnection *connection; + + // Take user/pass out of the URL. + // Credentials for ftp can only be passed in URL, the connection:didReceiveAuthenticationChallenge: delegate call won't be made. + if ((delegate->m_user || delegate->m_pass) && KURL(url).protocolInHTTPFamily()) { + ResourceRequest requestWithoutCredentials = request; + requestWithoutCredentials.removeCredentials(); + connection = [[NSURLConnection alloc] initWithRequest:requestWithoutCredentials.nsURLRequest() delegate:delegate startImmediately:NO]; + } else + connection = [[NSURLConnection alloc] initWithRequest:request delegate:delegate startImmediately:NO]; + [connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:WebCoreSynchronousLoaderRunLoopMode]; [connection start]; @@ -834,4 +1008,14 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen @end +static NSString *webNSURLResponseMIMEType(id self, SEL _cmd) +{ + ASSERT(oldNSURLResponseMIMETypeIMP); + if (NSString *result = oldNSURLResponseMIMETypeIMP(self, _cmd)) + return result; + + static NSString *defaultMIMETypeString = [(NSString *)defaultMIMEType() retain]; + return defaultMIMETypeString; +} + #endif diff --git a/WebCore/platform/network/mac/ResourceRequestMac.mm b/WebCore/platform/network/mac/ResourceRequestMac.mm index 92c37ee..6bb36a0 100644 --- a/WebCore/platform/network/mac/ResourceRequestMac.mm +++ b/WebCore/platform/network/mac/ResourceRequestMac.mm @@ -57,7 +57,7 @@ void ResourceRequest::doUpdateResourceRequest() m_url = [m_nsRequest.get() URL]; m_cachePolicy = (ResourceRequestCachePolicy)[m_nsRequest.get() cachePolicy]; m_timeoutInterval = [m_nsRequest.get() timeoutInterval]; - m_mainDocumentURL = [m_nsRequest.get() mainDocumentURL]; + m_firstPartyForCookies = [m_nsRequest.get() mainDocumentURL]; if (NSString* method = [m_nsRequest.get() HTTPMethod]) m_httpMethod = method; @@ -78,7 +78,7 @@ void ResourceRequest::doUpdateResourceRequest() for (NSUInteger i = 0; i < count; ++i) { CFStringEncoding encoding = CFStringConvertNSStringEncodingToEncoding([(NSNumber *)[encodingFallbacks objectAtIndex:i] unsignedLongValue]); if (encoding != kCFStringEncodingInvalidId) - m_responseContentDispositionEncodingFallbackArray.append(CFStringGetNameOfEncoding(encoding)); + m_responseContentDispositionEncodingFallbackArray.append(CFStringConvertEncodingToIANACharSetName(encoding)); } } @@ -110,7 +110,7 @@ void ResourceRequest::doUpdatePlatformRequest() [nsRequest setCachePolicy:(NSURLRequestCachePolicy)cachePolicy()]; if (timeoutInterval() != unspecifiedTimeoutInterval) [nsRequest setTimeoutInterval:timeoutInterval()]; - [nsRequest setMainDocumentURL:mainDocumentURL()]; + [nsRequest setMainDocumentURL:firstPartyForCookies()]; if (!httpMethod().isEmpty()) [nsRequest setHTTPMethod:httpMethod()]; [nsRequest setHTTPShouldHandleCookies:allowHTTPCookies()]; @@ -146,5 +146,11 @@ void ResourceRequest::applyWebArchiveHackForMail() // Hack because Mail checks for this property to detect data / archive loads [NSURLProtocol setProperty:@"" forKey:@"WebDataRequest" inRequest:(NSMutableURLRequest *)nsURLRequest()]; } + +unsigned initializeMaximumHTTPConnectionCountPerHost() +{ + static const unsigned preferredConnectionCount = 6; + return wkInitializeMaximumHTTPConnectionCountPerHost(preferredConnectionCount); +} } diff --git a/WebCore/platform/network/mac/ResourceResponseMac.mm b/WebCore/platform/network/mac/ResourceResponseMac.mm index d501b31..60a4dc6 100644 --- a/WebCore/platform/network/mac/ResourceResponseMac.mm +++ b/WebCore/platform/network/mac/ResourceResponseMac.mm @@ -74,12 +74,6 @@ void ResourceResponse::platformLazyInit() m_textEncodingName = [m_nsResponse.get() textEncodingName]; m_suggestedFilename = [m_nsResponse.get() suggestedFilename]; - const time_t maxTime = std::numeric_limits<time_t>::max(); - - NSTimeInterval expiration = [m_nsResponse.get() _calculatedExpiration]; - expiration += kCFAbsoluteTimeIntervalSince1970; - m_expirationDate = expiration > maxTime ? maxTime : static_cast<time_t>(expiration); - if ([m_nsResponse.get() isKindOfClass:[NSHTTPURLResponse class]]) { NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)m_nsResponse.get(); diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp index 2c730a6..06b60bf 100644 --- a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp +++ b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp @@ -136,7 +136,6 @@ QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode load , m_redirected(false) , m_responseSent(false) , m_loadMode(loadMode) - , m_startTime(0) , m_shouldStart(true) , m_shouldFinish(false) , m_shouldSendResponse(false) @@ -174,6 +173,7 @@ void QNetworkReplyHandler::abort() if (m_reply) { QNetworkReply* reply = release(); reply->abort(); + reply->deleteLater(); deleteLater(); } } @@ -291,7 +291,7 @@ void QNetworkReplyHandler::sendResponseIfNeeded() } if (isLocalFileReply) - response.setExpirationDate(m_startTime); + response.setHTTPHeaderField(QString::fromAscii("Cache-Control"), QString::fromAscii("no-cache")); QUrl redirection = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); if (redirection.isValid()) { @@ -354,8 +354,6 @@ void QNetworkReplyHandler::start() && (!url.toLocalFile().isEmpty() || url.scheme() == QLatin1String("data"))) m_method = QNetworkAccessManager::GetOperation; - m_startTime = QDateTime::currentDateTime().toTime_t(); - switch (m_method) { case QNetworkAccessManager::GetOperation: m_reply = manager->get(m_request); diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.h b/WebCore/platform/network/qt/QNetworkReplyHandler.h index 98be28d..3de6d88 100644 --- a/WebCore/platform/network/qt/QNetworkReplyHandler.h +++ b/WebCore/platform/network/qt/QNetworkReplyHandler.h @@ -72,7 +72,6 @@ private: LoadMode m_loadMode; QNetworkAccessManager::Operation m_method; QNetworkRequest m_request; - uint m_startTime; // defer state holding bool m_shouldStart; diff --git a/WebCore/platform/network/qt/ResourceHandleQt.cpp b/WebCore/platform/network/qt/ResourceHandleQt.cpp index 7af5895..c5816a4 100644 --- a/WebCore/platform/network/qt/ResourceHandleQt.cpp +++ b/WebCore/platform/network/qt/ResourceHandleQt.cpp @@ -171,7 +171,7 @@ PassRefPtr<SharedBuffer> ResourceHandle::bufferedData() return 0; } -void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data, Frame* frame) +void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, StoredCredentials /*storedCredentials*/, ResourceError& error, ResourceResponse& response, Vector<char>& data, Frame* frame) { WebCoreSynchronousLoader syncLoader; ResourceHandle handle(request, &syncLoader, true, false, true); diff --git a/WebCore/platform/network/qt/ResourceRequestQt.cpp b/WebCore/platform/network/qt/ResourceRequestQt.cpp index 9308878..c8f6ad5 100644 --- a/WebCore/platform/network/qt/ResourceRequestQt.cpp +++ b/WebCore/platform/network/qt/ResourceRequestQt.cpp @@ -41,6 +41,22 @@ QNetworkRequest ResourceRequest::toNetworkRequest() const request.setRawHeader(name, value); } + switch (cachePolicy()) { + case ReloadIgnoringCacheData: + request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); + break; + case ReturnCacheDataElseLoad: + request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); + break; + case ReturnCacheDataDontLoad: + request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysCache); + break; + case UseProtocolCachePolicy: + // QNetworkRequest::PreferNetwork + default: + break; + } + return request; } diff --git a/WebCore/platform/network/soup/CookieJarSoup.cpp b/WebCore/platform/network/soup/CookieJarSoup.cpp index e3064e1..705fdf2 100644 --- a/WebCore/platform/network/soup/CookieJarSoup.cpp +++ b/WebCore/platform/network/soup/CookieJarSoup.cpp @@ -22,6 +22,7 @@ #include "CookieJarSoup.h" #include "CString.h" +#include "Document.h" #include "KURL.h" namespace WebCore { @@ -52,7 +53,7 @@ void setDefaultCookieJar(SoupCookieJar* jar) g_object_ref(cookieJar); } -void setCookies(Document* /*document*/, const KURL& url, const KURL& /*policyURL*/, const String& value) +void setCookies(Document* /*document*/, const KURL& url, const String& value) { SoupCookieJar* jar = defaultCookieJar(); if (!jar) diff --git a/WebCore/platform/network/soup/ResourceHandleSoup.cpp b/WebCore/platform/network/soup/ResourceHandleSoup.cpp index 1b91e32..6be13e2 100644 --- a/WebCore/platform/network/soup/ResourceHandleSoup.cpp +++ b/WebCore/platform/network/soup/ResourceHandleSoup.cpp @@ -53,10 +53,6 @@ #include <sys/stat.h> #include <unistd.h> -#if PLATFORM(GTK) -#define USE_GLIB_BASE64 -#endif - namespace WebCore { class WebCoreSynchronousLoader : public ResourceHandleClient, Noncopyable { @@ -121,14 +117,6 @@ void WebCoreSynchronousLoader::run() g_main_loop_run(m_mainLoop); } -enum -{ - ERROR_TRANSPORT, - ERROR_UNKNOWN_PROTOCOL, - ERROR_BAD_NON_HTTP_METHOD, - ERROR_UNABLE_TO_OPEN_FILE, -}; - static void cleanupGioOperation(ResourceHandleInternal* handle); ResourceHandleInternal::~ResourceHandleInternal() @@ -148,6 +136,9 @@ ResourceHandleInternal::~ResourceHandleInternal() ResourceHandle::~ResourceHandle() { + if (d->m_msg) + g_signal_handlers_disconnect_matched(d->m_msg, G_SIGNAL_MATCH_DATA, + 0, 0, 0, 0, this); } static void fillResponseFromMessage(SoupMessage* msg, ResourceResponse* response) @@ -171,17 +162,24 @@ static void fillResponseFromMessage(SoupMessage* msg, ResourceResponse* response contentType = contentTypes[0]; if (contentTypeParameters) { + GString* parametersString = g_string_new(0); GHashTableIter hashTableIter; - gpointer hashKey; - gpointer hashValue; + const char* hashKey; + const char* hashValue; g_hash_table_iter_init(&hashTableIter, contentTypeParameters); - while (g_hash_table_iter_next(&hashTableIter, &hashKey, &hashValue)) { - contentType += String("; "); - contentType += String(static_cast<char*>(hashKey)); - contentType += String("="); - contentType += String(static_cast<char*>(hashValue)); + while (g_hash_table_iter_next(&hashTableIter, reinterpret_cast<void**>(const_cast<char**>(&hashKey)), reinterpret_cast<void**>(const_cast<char**>(&hashValue)))) { + // Work-around bug in soup which causes a crash; + // See http://bugzilla.gnome.org/show_bug.cgi?id=577728 + if (!hashValue) + hashValue = ""; + + g_string_append(parametersString, "; "); + soup_header_g_string_append_param(parametersString, hashKey, hashValue); } + contentType += String(parametersString->str); + + g_string_free(parametersString, true); g_hash_table_destroy(contentTypeParameters); } @@ -228,8 +226,6 @@ static void restartedCallback(SoupMessage* msg, gpointer data) fillResponseFromMessage(msg, &response); if (d->client()) d->client()->willSendRequest(handle, request, response); - - d->m_request.setURL(newURL); } static void gotHeadersCallback(SoupMessage* msg, gpointer data) @@ -258,11 +254,12 @@ static void gotHeadersCallback(SoupMessage* msg, gpointer data) // sniffing the contents of the file, and then report that we got // headers; we will not do content sniffing for 304 responses, // though, since they do not have a body. + const char* contentType = soup_message_headers_get_content_type(msg->response_headers, NULL); if ((msg->status_code != SOUP_STATUS_NOT_MODIFIED) - && !soup_message_headers_get_content_type(msg->response_headers, NULL)) + && (!contentType || !g_ascii_strcasecmp(contentType, "text/plain"))) return; - ResourceHandle* handle = static_cast<ResourceHandle*>(data); + RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data); if (!handle) return; ResourceHandleInternal* d = handle->getInternal(); @@ -273,8 +270,8 @@ static void gotHeadersCallback(SoupMessage* msg, gpointer data) return; fillResponseFromMessage(msg, &d->m_response); - client->didReceiveResponse(handle, d->m_response); d->m_reportedHeaders = true; + client->didReceiveResponse(handle.get(), d->m_response); } static void gotChunkCallback(SoupMessage* msg, SoupBuffer* chunk, gpointer data) @@ -284,7 +281,7 @@ static void gotChunkCallback(SoupMessage* msg, SoupBuffer* chunk, gpointer data) || (msg->status_code == SOUP_STATUS_UNAUTHORIZED)) return; - ResourceHandle* handle = static_cast<ResourceHandle*>(data); + RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data); if (!handle) return; ResourceHandleInternal* d = handle->getInternal(); @@ -301,11 +298,15 @@ static void gotChunkCallback(SoupMessage* msg, SoupBuffer* chunk, gpointer data) g_free(contentType); fillResponseFromMessage(msg, &d->m_response); - client->didReceiveResponse(handle, d->m_response); + client->didReceiveResponse(handle.get(), d->m_response); d->m_reportedHeaders = true; + + // the didReceiveResponse call above may have cancelled the request + if (d->m_cancelled) + return; } - client->didReceiveData(handle, chunk->data, chunk->length, false); + client->didReceiveData(handle.get(), chunk->data, chunk->length, false); } // Called at the end of the message, with all the necessary about the last informations. @@ -327,9 +328,10 @@ static void finishedCallback(SoupSession *session, SoupMessage* msg, gpointer da return; if (SOUP_STATUS_IS_TRANSPORT_ERROR(msg->status_code)) { - char* uri = soup_uri_to_string(soup_message_get_uri(msg), false); - ResourceError error("webkit-network-error", ERROR_TRANSPORT, uri, String::fromUTF8(msg->reason_phrase)); - g_free(uri); + ResourceError error(g_quark_to_string(SOUP_HTTP_ERROR), + msg->status_code, + soup_uri_to_string(soup_message_get_uri(msg), false), + String::fromUTF8(msg->reason_phrase)); client->didFail(handle.get(), error); return; } @@ -354,8 +356,11 @@ static gboolean parseDataUrl(gpointer callback_data) { ResourceHandle* handle = static_cast<ResourceHandle*>(callback_data); ResourceHandleClient* client = handle->client(); + ResourceHandleInternal* d = handle->getInternal(); + if (d->m_cancelled) + return false; - handle->getInternal()->m_idleHandler = 0; + d->m_idleHandler = 0; ASSERT(client); if (!client) @@ -391,27 +396,31 @@ static gboolean parseDataUrl(gpointer callback_data) response.setTextEncodingName(charset); client->didReceiveResponse(handle, response); - // Use the GLib Base64 if available, since WebCore's decoder isn't + if (d->m_cancelled) + return false; + + // Use the GLib Base64, since WebCore's decoder isn't // general-purpose and fails on Acid3 test 97 (whitespace). -#ifdef USE_GLIB_BASE64 size_t outLength = 0; char* outData = 0; outData = reinterpret_cast<char*>(g_base64_decode(data.utf8().data(), &outLength)); if (outData && outLength > 0) client->didReceiveData(handle, outData, outLength, 0); g_free(outData); -#else - Vector<char> out; - if (base64Decode(data.latin1().data(), data.latin1().length(), out) && out.size() > 0) - client->didReceiveData(handle, out.data(), out.size(), 0); -#endif } else { // We have to convert to UTF-16 early due to limitations in KURL data = decodeURLEscapeSequences(data, TextEncoding(charset)); response.setTextEncodingName("UTF-16"); client->didReceiveResponse(handle, response); + + if (d->m_cancelled) + return false; + if (data.length() > 0) client->didReceiveData(handle, reinterpret_cast<const char*>(data.characters()), data.length() * sizeof(UChar), 0); + + if (d->m_cancelled) + return false; } client->didFinishLoading(handle); @@ -459,20 +468,12 @@ bool ResourceHandle::startHttp(String urlString) SoupSession* session = defaultSession(); ensureSessionIsInitialized(session); - SoupMessage* msg; - msg = soup_message_new(request().httpMethod().utf8().data(), urlString.utf8().data()); - g_signal_connect(msg, "restarted", G_CALLBACK(restartedCallback), this); - g_signal_connect(msg, "got-headers", G_CALLBACK(gotHeadersCallback), this); - g_signal_connect(msg, "got-chunk", G_CALLBACK(gotChunkCallback), this); - - g_object_set_data(G_OBJECT(msg), "resourceHandle", reinterpret_cast<void*>(this)); + d->m_msg = request().toSoupMessage(); + g_signal_connect(d->m_msg, "restarted", G_CALLBACK(restartedCallback), this); + g_signal_connect(d->m_msg, "got-headers", G_CALLBACK(gotHeadersCallback), this); + g_signal_connect(d->m_msg, "got-chunk", G_CALLBACK(gotChunkCallback), this); - HTTPHeaderMap customHeaders = d->m_request.httpHeaderFields(); - if (!customHeaders.isEmpty()) { - HTTPHeaderMap::const_iterator end = customHeaders.end(); - for (HTTPHeaderMap::const_iterator it = customHeaders.begin(); it != end; ++it) - soup_message_headers_append(msg->request_headers, it->first.string().utf8().data(), it->second.utf8().data()); - } + g_object_set_data(G_OBJECT(d->m_msg), "resourceHandle", reinterpret_cast<void*>(this)); FormData* httpBody = d->m_request.httpBody(); if (httpBody && !httpBody->isEmpty()) { @@ -482,7 +483,7 @@ bool ResourceHandle::startHttp(String urlString) if (numElements < 2) { Vector<char> body; httpBody->flatten(body); - soup_message_set_request(msg, d->m_request.httpContentType().utf8().data(), + soup_message_set_request(d->m_msg, d->m_request.httpContentType().utf8().data(), SOUP_MEMORY_COPY, body.data(), body.size()); } else { /* @@ -491,12 +492,12 @@ bool ResourceHandle::startHttp(String urlString) * copying into memory; TODO: support upload of non-local * (think sftp://) files by using GIO? */ - soup_message_body_set_accumulate(msg->request_body, FALSE); + soup_message_body_set_accumulate(d->m_msg->request_body, FALSE); for (size_t i = 0; i < numElements; i++) { const FormDataElement& element = httpBody->elements()[i]; if (element.m_type == FormDataElement::data) - soup_message_body_append(msg->request_body, SOUP_MEMORY_TEMPORARY, element.m_data.data(), element.m_data.size()); + soup_message_body_append(d->m_msg->request_body, SOUP_MEMORY_TEMPORARY, element.m_data.data(), element.m_data.size()); else { /* * mapping for uploaded files code inspired by technique used in @@ -509,53 +510,50 @@ bool ResourceHandle::startHttp(String urlString) g_free(fileName); if (error) { - ResourceError resourceError("webkit-network-error", ERROR_UNABLE_TO_OPEN_FILE, urlString, error->message); + ResourceError resourceError(g_quark_to_string(SOUP_HTTP_ERROR), + d->m_msg->status_code, + urlString, + String::fromUTF8(error->message)); g_error_free(error); d->client()->didFail(this, resourceError); - g_object_unref(msg); + g_signal_handlers_disconnect_matched(d->m_msg, G_SIGNAL_MATCH_DATA, + 0, 0, 0, 0, this); + g_object_unref(d->m_msg); + d->m_msg = 0; + return false; } SoupBuffer* soupBuffer = soup_buffer_new_with_owner(g_mapped_file_get_contents(fileMapping), g_mapped_file_get_length(fileMapping), fileMapping, reinterpret_cast<GDestroyNotify>(g_mapped_file_free)); - soup_message_body_append_buffer(msg->request_body, soupBuffer); + soup_message_body_append_buffer(d->m_msg->request_body, soupBuffer); soup_buffer_free(soupBuffer); } } } } - d->m_msg = static_cast<SoupMessage*>(g_object_ref(msg)); // balanced by a deref() in finishedCallback, which should always run ref(); + // FIXME: For now, we cannot accept content encoded in anything + // other than identity, so force servers to do it our way. When + // libsoup gets proper Content-Encoding support we will want to + // use it here instead. + soup_message_headers_replace(d->m_msg->request_headers, "Accept-Encoding", "identity"); + + // Balanced in ResourceHandleInternal's destructor; we need to + // keep our own ref, because after queueing the message, the + // session owns the initial reference. + g_object_ref(d->m_msg); soup_session_queue_message(session, d->m_msg, finishedCallback, this); return true; } -static gboolean reportUnknownProtocolError(gpointer callback_data) -{ - ResourceHandle* handle = static_cast<ResourceHandle*>(callback_data); - ResourceHandleInternal* d = handle->getInternal(); - ResourceHandleClient* client = handle->client(); - - if (d->m_cancelled || !client) { - handle->deref(); - return false; - } - - KURL url = handle->request().url(); - ResourceError error("webkit-network-error", ERROR_UNKNOWN_PROTOCOL, url.string(), url.protocol()); - client->didFail(handle, error); - - handle->deref(); - return false; -} - bool ResourceHandle::start(Frame* frame) { ASSERT(!d->m_msg); @@ -585,11 +583,9 @@ bool ResourceHandle::start(Frame* frame) // FIXME: should we be doing any other protocols here? return startGio(url); - // Error must not be reported immediately, but through an idle function. - // Despite error, we should return true so a proper handle is created, - // to which this failure can be reported. - ref(); - d->m_idleHandler = g_idle_add(reportUnknownProtocolError, this); + // Error must not be reported immediately + this->scheduleFailure(InvalidURLFailure); + return true; } @@ -632,7 +628,7 @@ bool ResourceHandle::willLoadFromCache(ResourceRequest&) return false; } -void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data, Frame* frame) +void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, StoredCredentials /*storedCredentials*/, ResourceError& error, ResourceResponse& response, Vector<char>& data, Frame* frame) { WebCoreSynchronousLoader syncLoader(error, response, data); ResourceHandle handle(request, &syncLoader, true, false, true); @@ -643,15 +639,6 @@ void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, R // GIO-based loader -static inline ResourceError networkErrorForFile(GFile* file, GError* error) -{ - // FIXME: Map gio errors to a more detailed error code when we have it in WebKit. - gchar* uri = g_file_get_uri(file); - ResourceError resourceError("webkit-network-error", ERROR_TRANSPORT, uri, error ? String::fromUTF8(error->message) : String()); - g_free(uri); - return resourceError; -} - static void cleanupGioOperation(ResourceHandleInternal* d) { if (d->m_gfile) { @@ -710,7 +697,10 @@ static void readCallback(GObject* source, GAsyncResult* res, gpointer) gssize bytesRead = g_input_stream_read_finish(d->m_inputStream, res, &error); if (error) { - ResourceError resourceError = networkErrorForFile(d->m_gfile, error); + ResourceError resourceError(g_quark_to_string(G_IO_ERROR), + error->code, + g_file_get_uri(d->m_gfile), + error ? String::fromUTF8(error->message) : String()); g_error_free(error); cleanupGioOperation(d); client->didFail(handle.get(), resourceError); @@ -753,7 +743,11 @@ static void openCallback(GObject* source, GAsyncResult* res, gpointer) GError *error = 0; GFileInputStream* in = g_file_read_finish(G_FILE(source), res, &error); if (error) { - ResourceError resourceError = networkErrorForFile(d->m_gfile, error); + ResourceError resourceError(g_quark_to_string(G_IO_ERROR), + error->code, + g_file_get_uri(d->m_gfile), + error ? String::fromUTF8(error->message) : String()); + g_error_free(error); cleanupGioOperation(d); client->didFail(handle, resourceError); @@ -800,8 +794,10 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer) // server (and then keep track of the fact that we mounted it, // and set a timeout to unmount it later after it's been idle // for a while). - - ResourceError resourceError = networkErrorForFile(d->m_gfile, error); + ResourceError resourceError(g_quark_to_string(G_IO_ERROR), + error->code, + g_file_get_uri(d->m_gfile), + error ? String::fromUTF8(error->message) : String()); g_error_free(error); cleanupGioOperation(d); client->didFail(handle, resourceError); @@ -811,8 +807,10 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer) if (g_file_info_get_file_type(info) != G_FILE_TYPE_REGULAR) { // FIXME: what if the URI points to a directory? Should we // generate a listing? How? What do other backends do here? - - ResourceError resourceError = networkErrorForFile(d->m_gfile, 0); + ResourceError resourceError(g_quark_to_string(G_IO_ERROR), + G_IO_ERROR_FAILED, + g_file_get_uri(d->m_gfile), + String()); cleanupGioOperation(d); client->didFail(handle, resourceError); return; @@ -834,7 +832,9 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer) bool ResourceHandle::startGio(KURL url) { if (request().httpMethod() != "GET" && request().httpMethod() != "POST") { - ResourceError error("webkit-network-error", ERROR_BAD_NON_HTTP_METHOD, url.string(), request().httpMethod()); + ResourceError error(g_quark_to_string(SOUP_HTTP_ERROR), + SOUP_STATUS_METHOD_NOT_ALLOWED, + url.string(), request().httpMethod()); d->client()->didFail(this, error); return false; } @@ -846,12 +846,14 @@ bool ResourceHandle::startGio(KURL url) url.setQuery(String()); url.setPort(0); +#if !PLATFORM(WIN_OS) // we avoid the escaping for local files, because // g_filename_from_uri (used internally by GFile) has problems // decoding strings with arbitrary percent signs if (url.isLocalFile()) d->m_gfile = g_file_new_for_path(url.prettyURL().utf8().data() + sizeof("file://") - 1); else +#endif d->m_gfile = g_file_new_for_uri(url.string().utf8().data()); g_object_set_data(G_OBJECT(d->m_gfile), "webkit-resource", this); d->m_cancellable = g_cancellable_new(); diff --git a/WebCore/platform/network/soup/ResourceRequest.h b/WebCore/platform/network/soup/ResourceRequest.h index efb1240..82b4eb9 100644 --- a/WebCore/platform/network/soup/ResourceRequest.h +++ b/WebCore/platform/network/soup/ResourceRequest.h @@ -29,6 +29,8 @@ #include "ResourceRequestBase.h" +#include <libsoup/soup.h> + namespace WebCore { struct ResourceRequest : ResourceRequestBase { @@ -54,11 +56,20 @@ namespace WebCore { { } + ResourceRequest(SoupMessage* soupMessage) + : ResourceRequestBase(KURL(), UseProtocolCachePolicy) + { + updateFromSoupMessage(soupMessage); + } + + SoupMessage* toSoupMessage() const; + void updateFromSoupMessage(SoupMessage* soupMessage); + private: - friend class ResourceRequestBase; + friend struct ResourceRequestBase; - void doUpdatePlatformRequest() {} - void doUpdateResourceRequest() {} + void doUpdatePlatformRequest() {}; + void doUpdateResourceRequest() {}; }; } // namespace WebCore diff --git a/WebCore/platform/network/soup/ResourceRequestSoup.cpp b/WebCore/platform/network/soup/ResourceRequestSoup.cpp new file mode 100644 index 0000000..f2011bb --- /dev/null +++ b/WebCore/platform/network/soup/ResourceRequestSoup.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2009 Gustavo Noronha Silva + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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 "ResourceRequest.h" + +#include "CString.h" +#include "GOwnPtr.h" +#include "PlatformString.h" + +#include <libsoup/soup.h> + +using namespace std; + +namespace WebCore { + +SoupMessage* ResourceRequest::toSoupMessage() const +{ + SoupMessage* soupMessage = soup_message_new(httpMethod().utf8().data(), url().string().utf8().data()); + if (!soupMessage) + return 0; + + HTTPHeaderMap headers = httpHeaderFields(); + SoupMessageHeaders* soupHeaders = soupMessage->request_headers; + if (!headers.isEmpty()) { + HTTPHeaderMap::const_iterator end = headers.end(); + for (HTTPHeaderMap::const_iterator it = headers.begin(); it != end; ++it) + soup_message_headers_append(soupHeaders, it->first.string().utf8().data(), it->second.utf8().data()); + } + + // Body data is only handled at ResourceHandleSoup::startHttp for + // now; this is because this may not be a good place to go + // openning and mmapping files. We should maybe revisit this. + return soupMessage; +} + +void ResourceRequest::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_httpMethod = String::fromUTF8(soupMessage->method); + + SoupMessageHeadersIter headersIter; + const char* headerName; + const char* headerValue; + + soup_message_headers_iter_init(&headersIter, soupMessage->request_headers); + while (soup_message_headers_iter_next(&headersIter, &headerName, &headerValue)) + m_httpHeaderFields.set(String::fromUTF8(headerName), String::fromUTF8(headerValue)); + + m_httpBody = FormData::create(soupMessage->request_body->data, soupMessage->request_body->length); + + // FIXME: m_allowHTTPCookies and m_firstPartyForCookies should + // probably be handled here and on doUpdatePlatformRequest + // somehow. +} + +} diff --git a/WebCore/platform/network/win/CookieJarCFNetWin.cpp b/WebCore/platform/network/win/CookieJarCFNetWin.cpp index 7e64813..af9e3f3 100644 --- a/WebCore/platform/network/win/CookieJarCFNetWin.cpp +++ b/WebCore/platform/network/win/CookieJarCFNetWin.cpp @@ -63,7 +63,7 @@ static RetainPtr<CFArrayRef> filterCookies(CFArrayRef unfilteredCookies) return filteredCookies; } -void setCookies(Document* /*document*/, const KURL& url, const KURL& policyURL, const String& value) +void setCookies(Document* document, const KURL& url, const String& value) { // <rdar://problem/5632883> CFHTTPCookieStorage stores an empty cookie, which would be sent as "Cookie: =". if (value.isEmpty()) @@ -74,7 +74,7 @@ void setCookies(Document* /*document*/, const KURL& url, const KURL& policyURL, return; RetainPtr<CFURLRef> urlCF(AdoptCF, url.createCFURL()); - RetainPtr<CFURLRef> policyURLCF(AdoptCF, policyURL.createCFURL()); + RetainPtr<CFURLRef> firstPartyForCookiesCF(AdoptCF, document->firstPartyForCookies().createCFURL()); // <http://bugs.webkit.org/show_bug.cgi?id=6531>, <rdar://4409034> // cookiesWithResponseHeaderFields doesn't parse cookies without a value @@ -88,7 +88,7 @@ void setCookies(Document* /*document*/, const KURL& url, const KURL& policyURL, RetainPtr<CFArrayRef> cookiesCF(AdoptCF, CFHTTPCookieCreateWithResponseHeaderFields(kCFAllocatorDefault, headerFieldsCF.get(), urlCF.get())); - CFHTTPCookieStorageSetCookies(cookieStorage, filterCookies(cookiesCF.get()).get(), urlCF.get(), policyURLCF.get()); + CFHTTPCookieStorageSetCookies(cookieStorage, filterCookies(cookiesCF.get()).get(), urlCF.get(), firstPartyForCookiesCF.get()); } String cookies(const Document* /*document*/, const KURL& url) diff --git a/WebCore/platform/network/win/CookieJarWin.cpp b/WebCore/platform/network/win/CookieJarWin.cpp index cdafb1b..41d12d9 100644 --- a/WebCore/platform/network/win/CookieJarWin.cpp +++ b/WebCore/platform/network/win/CookieJarWin.cpp @@ -36,9 +36,9 @@ namespace WebCore { -void setCookies(Document* /*document*/, const KURL& url, const KURL& policyURL, const String& value) +void setCookies(Document* /*document*/, const KURL& url, const String& value) { - // FIXME: Deal with the policy URL. + // FIXME: Deal with document->firstPartyForCookies(). String str = url.string(); String val = value; InternetSetCookie(str.charactersWithNullTermination(), 0, val.charactersWithNullTermination()); diff --git a/WebCore/platform/posix/FileSystemPOSIX.cpp b/WebCore/platform/posix/FileSystemPOSIX.cpp index c1bef60..e55b8a4 100644 --- a/WebCore/platform/posix/FileSystemPOSIX.cpp +++ b/WebCore/platform/posix/FileSystemPOSIX.cpp @@ -30,7 +30,6 @@ #include "FileSystem.h" #include "CString.h" -#include "NotImplemented.h" #include "PlatformString.h" #include <sys/stat.h> diff --git a/WebCore/platform/qt/ContextMenuQt.cpp b/WebCore/platform/qt/ContextMenuQt.cpp index 3e093b1..063a46b 100644 --- a/WebCore/platform/qt/ContextMenuQt.cpp +++ b/WebCore/platform/qt/ContextMenuQt.cpp @@ -26,7 +26,6 @@ #include "config.h" #include "ContextMenu.h" -#include "MenuEventProxy.h" #include <wtf/Assertions.h> diff --git a/WebCore/platform/qt/CookieJarQt.cpp b/WebCore/platform/qt/CookieJarQt.cpp index 4077407..40d9309 100644 --- a/WebCore/platform/qt/CookieJarQt.cpp +++ b/WebCore/platform/qt/CookieJarQt.cpp @@ -28,11 +28,11 @@ #include "config.h" #include "CookieJar.h" +#include "Document.h" #include "KURL.h" #include "PlatformString.h" #if QT_VERSION >= 0x040400 -#include "Document.h" #include "qwebpage.h" #include "qwebframe.h" #include "FrameLoaderClientQt.h" @@ -61,10 +61,10 @@ static QNetworkCookieJar *cookieJar(const Document *document) } #endif -void setCookies(Document* document, const KURL& url, const KURL& policyURL, const String& value) +void setCookies(Document* document, const KURL& url, const String& value) { QUrl u(url); - QUrl p(policyURL); + QUrl p(document->firstPartyForCookies()); #if QT_VERSION >= 0x040400 QNetworkCookieJar* jar = cookieJar(document); if (!jar) diff --git a/WebCore/platform/qt/DragDataQt.cpp b/WebCore/platform/qt/DragDataQt.cpp index 9d95373..bc5cce1 100644 --- a/WebCore/platform/qt/DragDataQt.cpp +++ b/WebCore/platform/qt/DragDataQt.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 @@ -30,7 +30,6 @@ #include "Document.h" #include "DocumentFragment.h" #include "markup.h" -#include "NotImplemented.h" #include <QList> #include <QMimeData> @@ -126,6 +125,10 @@ String DragData::asURL(String* title) const if (!m_platformDragData) return String(); QList<QUrl> urls = m_platformDragData->urls(); + + if (urls.isEmpty()) + return String(); + return urls.first().toString(); } diff --git a/WebCore/platform/qt/FileSystemQt.cpp b/WebCore/platform/qt/FileSystemQt.cpp index 8a272c1..a17f3ab 100644 --- a/WebCore/platform/qt/FileSystemQt.cpp +++ b/WebCore/platform/qt/FileSystemQt.cpp @@ -33,7 +33,6 @@ #include "FileSystem.h" #include "CString.h" -#include "NotImplemented.h" #include "PlatformString.h" #include <QDateTime> diff --git a/WebCore/platform/qt/Localizations.cpp b/WebCore/platform/qt/Localizations.cpp index cb805f9..a6c7513 100644 --- a/WebCore/platform/qt/Localizations.cpp +++ b/WebCore/platform/qt/Localizations.cpp @@ -30,7 +30,6 @@ #include "IntSize.h" #include "LocalizedStrings.h" -#include "NotImplemented.h" #include "PlatformString.h" #include <QCoreApplication> @@ -245,12 +244,12 @@ String contextMenuItemTagDefaultDirection() String contextMenuItemTagLeftToRight() { - return QCoreApplication::translate("QWebPage", "LTR", "Left to Right context menu item"); + return QCoreApplication::translate("QWebPage", "Left to Right", "Left to Right context menu item"); } String contextMenuItemTagRightToLeft() { - return QCoreApplication::translate("QWebPage", "RTL", "Right to Left context menu item"); + return QCoreApplication::translate("QWebPage", "Right to Left", "Right to Left context menu item"); } String contextMenuItemTagInspectElement() diff --git a/WebCore/platform/qt/MenuEventProxy.h b/WebCore/platform/qt/MenuEventProxy.h deleted file mode 100644 index 658d1ee..0000000 --- a/WebCore/platform/qt/MenuEventProxy.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2007 Staikos Computing Services Inc. <info@staikos.net> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - - -#ifndef MENUEVENTPROXY_H -#define MENUEVENTPROXY_H - -#include "Platform.h" -#include <qobject.h> -#include <qmap.h> -#include "ContextMenu.h" -#include "ContextMenuItem.h" -#include "ContextMenuController.h" - -namespace WebCore { -class MenuEventProxy : public QObject { - Q_OBJECT - public: - MenuEventProxy(WebCore::ContextMenu *m) : m_m(m) {} - ~MenuEventProxy() {} - - void map(QAction* action, unsigned actionTag) { _map[action] = actionTag; } - - public slots: - void trigger(QAction *action) { - WebCore::ContextMenuItem item(WebCore::ActionType, static_cast<WebCore::ContextMenuAction>(_map[action]), WebCore::String()); - m_m->controller()->contextMenuItemSelected(&item); - } - - private: - WebCore::ContextMenu *m_m; - QMap<QAction*, unsigned> _map; -}; - -} - -#endif -// vim: ts=4 sw=4 et diff --git a/WebCore/platform/qt/PopupMenuQt.cpp b/WebCore/platform/qt/PopupMenuQt.cpp index 76728fa..a7d6643 100644 --- a/WebCore/platform/qt/PopupMenuQt.cpp +++ b/WebCore/platform/qt/PopupMenuQt.cpp @@ -30,7 +30,6 @@ #include "FrameView.h" #include "HostWindow.h" #include "PopupMenuClient.h" -#include "NotImplemented.h" #include "QWebPopup.h" #include <QAction> diff --git a/WebCore/platform/qt/QWebPopup.cpp b/WebCore/platform/qt/QWebPopup.cpp index 4d57c9b..f437c27 100644 --- a/WebCore/platform/qt/QWebPopup.cpp +++ b/WebCore/platform/qt/QWebPopup.cpp @@ -82,4 +82,6 @@ void QWebPopup::activeChanged(int index) m_client->valueChanged(index); } -} +} // namespace WebCore + +#include "moc_QWebPopup.cpp" diff --git a/WebCore/platform/qt/RenderThemeQt.cpp b/WebCore/platform/qt/RenderThemeQt.cpp index 942e95b..b16cbc4 100644 --- a/WebCore/platform/qt/RenderThemeQt.cpp +++ b/WebCore/platform/qt/RenderThemeQt.cpp @@ -41,6 +41,7 @@ #include <QWidget> #include <QPainter> #include <QPushButton> +#include <QLineEdit> #include <QStyleFactory> #include <QStyleOptionButton> #include <QStyleOptionFrameV2> @@ -124,6 +125,12 @@ RenderThemeQt::RenderThemeQt() #endif m_fallbackStyle = 0; + + // this will need to be regenerated when the style changes + QLineEdit lineEdit; + QStyleOptionFrameV2 opt; + m_frameLineWidth = QApplication::style()->pixelMetric(QStyle::PM_DefaultFrameWidth, + &opt, &lineEdit); } RenderThemeQt::~RenderThemeQt() @@ -272,7 +279,7 @@ int RenderThemeQt::minimumMenuListSize(RenderStyle*) const return 7 * fm.width(QLatin1Char('x')); } -static void computeSizeBasedOnStyle(RenderStyle* renderStyle) +void RenderThemeQt::computeSizeBasedOnStyle(RenderStyle* renderStyle) const { // If the width and height are both specified, then we have nothing to do. if (!renderStyle->width().isIntrinsicOrAuto() && !renderStyle->height().isAuto()) @@ -339,13 +346,15 @@ static void computeSizeBasedOnStyle(RenderStyle* renderStyle) int h = qMax(fm.lineSpacing(), 14) + 2*verticalMargin; int w = fm.width(QLatin1Char('x')) * 17 + 2*horizontalMargin; QStyleOptionFrameV2 opt; - opt.lineWidth = applicationStyle->pixelMetric(QStyle::PM_DefaultFrameWidth, - &opt, 0); + opt.lineWidth = m_frameLineWidth; QSize sz = applicationStyle->sizeFromContents(QStyle::CT_LineEdit, - &opt, - QSize(w, h).expandedTo(QApplication::globalStrut()), - 0); + &opt, + QSize(w, h).expandedTo(QApplication::globalStrut()), + 0); size.setHeight(sz.height()); + + renderStyle->setPaddingLeft(Length(opt.lineWidth, Fixed)); + renderStyle->setPaddingRight(Length(opt.lineWidth, Fixed)); break; } default: @@ -486,6 +495,9 @@ void RenderThemeQt::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, { style->setBackgroundColor(Color::transparent); style->setColor(QApplication::palette().text().color()); + style->resetBorder(); + style->resetPadding(); + computeSizeBasedOnStyle(style); } bool RenderThemeQt::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) @@ -499,7 +511,7 @@ bool RenderThemeQt::paintTextField(RenderObject* o, const RenderObject::PaintInf panel.initFrom(p.widget); panel.rect = r; - panel.lineWidth = p.style->pixelMetric(QStyle::PM_DefaultFrameWidth, &panel, p.widget); + panel.lineWidth = m_frameLineWidth; panel.state |= QStyle::State_Sunken; panel.features = QStyleOptionFrameV2::None; @@ -729,6 +741,10 @@ ControlPart RenderThemeQt::applyTheme(QStyleOption& option, RenderObject* o) con if (isHovered(o)) option.state |= QStyle::State_MouseOver; + option.direction = Qt::LeftToRight; + if (o->style() && o->style()->direction() == WebCore::RTL) + option.direction = Qt::RightToLeft; + ControlPart result = o->style()->appearance(); switch (result) { diff --git a/WebCore/platform/qt/RenderThemeQt.h b/WebCore/platform/qt/RenderThemeQt.h index b4a5064..5c78a72 100644 --- a/WebCore/platform/qt/RenderThemeQt.h +++ b/WebCore/platform/qt/RenderThemeQt.h @@ -128,6 +128,7 @@ private: void paintMediaBackground(QPainter* painter, const IntRect& r) const; QColor getMediaControlForegroundColor(RenderObject* o = 0) const; #endif + void computeSizeBasedOnStyle(RenderStyle* renderStyle) const; private: bool supportsFocus(ControlPart) const; @@ -144,6 +145,8 @@ private: QStyle* m_fallbackStyle; QStyle* fallbackStyle(); + + int m_frameLineWidth; }; class StylePainter diff --git a/WebCore/platform/qt/ScrollViewQt.cpp b/WebCore/platform/qt/ScrollViewQt.cpp index 76d9f01..48885d3 100644 --- a/WebCore/platform/qt/ScrollViewQt.cpp +++ b/WebCore/platform/qt/ScrollViewQt.cpp @@ -36,27 +36,33 @@ namespace WebCore { void ScrollView::platformInit() { - m_widgetsThatPreventBlitting = 0; + m_widgetsPreventingBlitting = 0; } void ScrollView::platformDestroy() { } -void ScrollView::platformAddChild(Widget* child) +// Windowed plugins are using native windows and are thus preventing +// us from doing any kind of scrolling optimization. + +void ScrollView::adjustWidgetsPreventingBlittingCount(int delta) { - root()->m_widgetsThatPreventBlitting++; + m_widgetsPreventingBlitting += delta; if (parent()) - parent()->platformAddChild(child); + parent()->adjustWidgetsPreventingBlittingCount(delta); +} + +void ScrollView::platformAddChild(Widget* child) +{ + adjustWidgetsPreventingBlittingCount(1); } void ScrollView::platformRemoveChild(Widget* child) { - ASSERT(root()->m_widgetsThatPreventBlitting); - root()->m_widgetsThatPreventBlitting--; child->hide(); + adjustWidgetsPreventingBlittingCount(-1); } } - // vim: ts=4 sw=4 et diff --git a/WebCore/platform/qt/TemporaryLinkStubs.cpp b/WebCore/platform/qt/TemporaryLinkStubs.cpp index ff0b27d..f76eb43 100644 --- a/WebCore/platform/qt/TemporaryLinkStubs.cpp +++ b/WebCore/platform/qt/TemporaryLinkStubs.cpp @@ -74,39 +74,6 @@ using namespace WebCore; -#if (!defined(Q_WS_X11) && !defined(Q_WS_WIN) && !defined(Q_WS_MAC32)) || defined(Q_OS_WINCE) - -bool PluginPackage::fetchInfo() { notImplemented(); return false; } -unsigned PluginPackage::hash() const { notImplemented(); return 0; } -bool PluginPackage::equal(const PluginPackage&, const PluginPackage&) { notImplemented(); return false; } -int PluginPackage::compareFileVersion(const PlatformModuleVersion&) const { notImplemented(); return -1; } - -void PluginView::setNPWindowRect(const IntRect&) { notImplemented(); } -const char* PluginView::userAgent() { notImplemented(); return 0; } -#if ENABLE(NETSCAPE_PLUGIN_API) -const char* PluginView::userAgentStatic() { notImplemented(); return 0; } -#endif -void PluginView::invalidateRect(NPRect*) { notImplemented(); } -void PluginView::invalidateRect(const IntRect&) { notImplemented(); } -void PluginView::invalidateRegion(NPRegion) { notImplemented(); } -void PluginView::forceRedraw() { notImplemented(); } -void PluginView::setFocus() { Widget::setFocus(); } -void PluginView::show() { Widget::show(); } -void PluginView::hide() { Widget::hide(); } -void PluginView::paint(GraphicsContext*, const IntRect&) { notImplemented(); } -void PluginView::setParent(ScrollView* view) { Widget::setParent(view); } -void PluginView::setParentVisible(bool) { notImplemented(); } -void PluginView::updatePluginWidget() { notImplemented(); } -void PluginView::handleKeyboardEvent(KeyboardEvent*) { notImplemented(); } -void PluginView::handleMouseEvent(MouseEvent*) { notImplemented(); } -NPError PluginView::handlePostReadFile(Vector<char>&, uint32, const char*) { notImplemented(); return NPERR_GENERIC_ERROR; } -NPError PluginView::getValue(NPNVariable, void*) { notImplemented(); return NPERR_GENERIC_ERROR; } -#if ENABLE(NETSCAPE_PLUGIN_API) -NPError PluginView::getValueStatic(NPNVariable, void*) { return NPERR_GENERIC_ERROR; } -#endif -PluginView::~PluginView() {} -#endif - #if defined(Q_OS_WINCE) Vector<String> PluginDatabase::defaultPluginDirectories() { notImplemented(); return Vector<String>(); } void PluginDatabase::getPluginPathsInDirectories(HashSet<String>& paths) const { notImplemented(); } diff --git a/WebCore/platform/text/AtomicString.cpp b/WebCore/platform/text/AtomicString.cpp index d85f5ee..409439e 100644 --- a/WebCore/platform/text/AtomicString.cpp +++ b/WebCore/platform/text/AtomicString.cpp @@ -206,7 +206,7 @@ PassRefPtr<StringImpl> AtomicString::add(const UChar* s) PassRefPtr<StringImpl> AtomicString::add(StringImpl* r) { - if (!r || r->m_inTable) + if (!r || r->inTable()) return r; if (r->length() == 0) @@ -214,7 +214,7 @@ PassRefPtr<StringImpl> AtomicString::add(StringImpl* r) StringImpl* result = *stringTable().add(r).first; if (result == r) - r->m_inTable = true; + r->setInTable(); return result; } diff --git a/WebCore/platform/text/AtomicString.h b/WebCore/platform/text/AtomicString.h index f4efab9..3307a2d 100644 --- a/WebCore/platform/text/AtomicString.h +++ b/WebCore/platform/text/AtomicString.h @@ -67,17 +67,21 @@ public: UChar operator[](unsigned int i) const { return m_string[i]; } bool contains(UChar c) const { return m_string.contains(c); } - bool contains(const AtomicString& s, bool caseSensitive = true) const - { return m_string.contains(s.string(), caseSensitive); } + bool contains(const char* s, bool caseSensitive = true) const + { return m_string.contains(s, caseSensitive); } + bool contains(const String& s, bool caseSensitive = true) const + { return m_string.contains(s, caseSensitive); } int find(UChar c, int start = 0) const { return m_string.find(c, start); } - int find(const AtomicString& s, int start = 0, bool caseSentitive = true) const - { return m_string.find(s.string(), start, caseSentitive); } + int find(const char* s, int start = 0, bool caseSentitive = true) const + { return m_string.find(s, start, caseSentitive); } + int find(const String& s, int start = 0, bool caseSentitive = true) const + { return m_string.find(s, start, caseSentitive); } - bool startsWith(const AtomicString& s, bool caseSensitive = true) const - { return m_string.startsWith(s.string(), caseSensitive); } - bool endsWith(const AtomicString& s, bool caseSensitive = true) const - { return m_string.endsWith(s.string(), caseSensitive); } + bool startsWith(const String& s, bool caseSensitive = true) const + { return m_string.startsWith(s, caseSensitive); } + bool endsWith(const String& s, bool caseSensitive = true) const + { return m_string.endsWith(s, caseSensitive); } int toInt(bool* ok = 0) const { return m_string.toInt(ok); } double toDouble(bool* ok = 0) const { return m_string.toDouble(ok); } diff --git a/WebCore/platform/text/BidiContext.cpp b/WebCore/platform/text/BidiContext.cpp index ef3c225..546571e 100644 --- a/WebCore/platform/text/BidiContext.cpp +++ b/WebCore/platform/text/BidiContext.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2000 Lars Knoll (knoll@kde.org) - * Copyright (C) 2003, 2004, 2006, 2007 Apple Inc. All right reserved. + * Copyright (C) 2003, 2004, 2006, 2007, 2009 Apple Inc. All right reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -22,8 +22,37 @@ #include "config.h" #include "BidiContext.h" +#include <wtf/StdLibExtras.h> + namespace WebCore { +using namespace WTF::Unicode; + +PassRefPtr<BidiContext> BidiContext::create(unsigned char level, Direction direction, bool override, BidiContext* parent) +{ + ASSERT(direction == level % 2 ? RightToLeft : LeftToRight); + + if (parent) + return adoptRef(new BidiContext(level, direction, override, parent)); + + ASSERT(level <= 1); + if (!level) { + DEFINE_STATIC_LOCAL(BidiContext, ltrContext, (0, LeftToRight, false, 0)); + if (!override) + return <rContext; + + DEFINE_STATIC_LOCAL(BidiContext, ltrOverrideContext, (0, LeftToRight, true, 0)); + return <rOverrideContext; + } + + DEFINE_STATIC_LOCAL(BidiContext, rtlContext, (1, RightToLeft, false, 0)); + if (!override) + return &rtlContext; + + DEFINE_STATIC_LOCAL(BidiContext, rtlOverrideContext, (1, RightToLeft, true, 0)); + return &rtlOverrideContext; +} + bool operator==(const BidiContext& c1, const BidiContext& c2) { if (&c1 == &c2) diff --git a/WebCore/platform/text/BidiContext.h b/WebCore/platform/text/BidiContext.h index 89123c8..8791605 100644 --- a/WebCore/platform/text/BidiContext.h +++ b/WebCore/platform/text/BidiContext.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2000 Lars Knoll (knoll@kde.org) - * Copyright (C) 2003, 2004, 2006, 2007 Apple Inc. All right reserved. + * Copyright (C) 2003, 2004, 2006, 2007, 2009 Apple Inc. All right reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -23,31 +23,17 @@ #define BidiContext_h #include <wtf/Assertions.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> #include <wtf/RefPtr.h> #include <wtf/unicode/Unicode.h> namespace WebCore { // Used to keep track of explicit embeddings. -class BidiContext { +class BidiContext : public RefCounted<BidiContext> { public: - BidiContext(unsigned char level, WTF::Unicode::Direction direction, bool override = false, BidiContext* parent = 0) - : m_level(level) - , m_direction(direction) - , m_override(override) - , m_parent(parent) - , m_refCount(0) - { - ASSERT(direction == WTF::Unicode::LeftToRight || direction == WTF::Unicode::RightToLeft); - } - - void ref() const { m_refCount++; } - void deref() const - { - m_refCount--; - if (m_refCount <= 0) - delete this; - } + static PassRefPtr<BidiContext> create(unsigned char level, WTF::Unicode::Direction direction, bool override = false, BidiContext* parent = 0); BidiContext* parent() const { return m_parent.get(); } unsigned char level() const { return m_level; } @@ -55,11 +41,18 @@ public: bool override() const { return m_override; } private: + BidiContext(unsigned char level, WTF::Unicode::Direction direction, bool override, BidiContext* parent) + : m_level(level) + , m_direction(direction) + , m_override(override) + , m_parent(parent) + { + } + unsigned char m_level; unsigned m_direction : 5; // Direction bool m_override : 1; RefPtr<BidiContext> m_parent; - mutable int m_refCount; }; bool operator==(const BidiContext&, const BidiContext&); diff --git a/WebCore/platform/text/BidiResolver.h b/WebCore/platform/text/BidiResolver.h index 8288be4..b6c2e88 100644 --- a/WebCore/platform/text/BidiResolver.h +++ b/WebCore/platform/text/BidiResolver.h @@ -402,7 +402,7 @@ void BidiResolver<Iterator, Run>::commitExplicitEmbedding() level &= ~1; } if (level < 61) - toContext = new BidiContext(level, direction, override, toContext.get()); + toContext = BidiContext::create(level, direction, override, toContext.get()); } } diff --git a/WebCore/platform/text/CharacterNames.h b/WebCore/platform/text/CharacterNames.h index f589a6c..5b1a337 100644 --- a/WebCore/platform/text/CharacterNames.h +++ b/WebCore/platform/text/CharacterNames.h @@ -37,6 +37,7 @@ namespace WebCore { const UChar blackSquare = 0x25A0; const UChar bullet = 0x2022; + const UChar hebrewPunctuationGershayim = 0x05F4; const UChar horizontalEllipsis = 0x2026; const UChar ideographicSpace = 0x3000; const UChar ideographicComma = 0x3001; @@ -49,6 +50,7 @@ namespace WebCore { const UChar objectReplacementCharacter = 0xFFFC; const UChar popDirectionalFormatting = 0x202C; const UChar replacementCharacter = 0xFFFD; + const UChar rightSingleQuotationMark = 0x2019; const UChar rightToLeftMark = 0x200F; const UChar rightToLeftEmbed = 0x202B; const UChar rightToLeftOverride = 0x202E; diff --git a/WebCore/platform/text/PlatformString.h b/WebCore/platform/text/PlatformString.h index a1541d2..1cc60b2 100644 --- a/WebCore/platform/text/PlatformString.h +++ b/WebCore/platform/text/PlatformString.h @@ -162,6 +162,11 @@ public: static String format(const char *, ...) WTF_ATTRIBUTE_PRINTF(1, 2); + // Returns an uninitialized string. The characters needs to be written + // into the buffer returned in data before the returned string is used. + // Failure to do this will have unpredictable results. + static String createUninitialized(unsigned length, UChar*& data) { return StringImpl::createUninitialized(length, data); } + void split(const String& separator, Vector<String>& result) const; void split(const String& separator, bool allowEmptyEntries, Vector<String>& result) const; void split(UChar separator, Vector<String>& result) const; diff --git a/WebCore/platform/text/String.cpp b/WebCore/platform/text/String.cpp index 733b661..cd87e2c 100644 --- a/WebCore/platform/text/String.cpp +++ b/WebCore/platform/text/String.cpp @@ -85,10 +85,12 @@ void String::append(const String& str) // call to fastMalloc every single time. if (str.m_impl) { if (m_impl) { - StringBuffer buffer(m_impl->length() + str.length()); - memcpy(buffer.characters(), m_impl->characters(), m_impl->length() * sizeof(UChar)); - memcpy(buffer.characters() + m_impl->length(), str.characters(), str.length() * sizeof(UChar)); - m_impl = StringImpl::adopt(buffer); + UChar* data; + RefPtr<StringImpl> newImpl = + StringImpl::createUninitialized(m_impl->length() + str.length(), data); + memcpy(data, m_impl->characters(), m_impl->length() * sizeof(UChar)); + memcpy(data + m_impl->length(), str.characters(), str.length() * sizeof(UChar)); + m_impl = newImpl.release(); } else m_impl = str.m_impl; } @@ -101,10 +103,12 @@ void String::append(char c) // one String is pointing at this StringImpl, but even then it's going to require a // call to fastMalloc every single time. if (m_impl) { - StringBuffer buffer(m_impl->length() + 1); - memcpy(buffer.characters(), m_impl->characters(), m_impl->length() * sizeof(UChar)); - buffer[m_impl->length()] = c; - m_impl = StringImpl::adopt(buffer); + UChar* data; + RefPtr<StringImpl> newImpl = + StringImpl::createUninitialized(m_impl->length() + 1, data); + memcpy(data, m_impl->characters(), m_impl->length() * sizeof(UChar)); + data[m_impl->length()] = c; + m_impl = newImpl.release(); } else m_impl = StringImpl::create(&c, 1); } @@ -116,10 +120,12 @@ void String::append(UChar c) // one String is pointing at this StringImpl, but even then it's going to require a // call to fastMalloc every single time. if (m_impl) { - StringBuffer buffer(m_impl->length() + 1); - memcpy(buffer.characters(), m_impl->characters(), m_impl->length() * sizeof(UChar)); - buffer[m_impl->length()] = c; - m_impl = StringImpl::adopt(buffer); + UChar* data; + RefPtr<StringImpl> newImpl = + StringImpl::createUninitialized(m_impl->length() + 1, data); + memcpy(data, m_impl->characters(), m_impl->length() * sizeof(UChar)); + data[m_impl->length()] = c; + m_impl = newImpl.release(); } else m_impl = StringImpl::create(&c, 1); } @@ -170,10 +176,12 @@ void String::append(const UChar* charactersToAppend, unsigned lengthToAppend) return; ASSERT(charactersToAppend); - StringBuffer buffer(length() + lengthToAppend); - memcpy(buffer.characters(), characters(), length() * sizeof(UChar)); - memcpy(buffer.characters() + length(), charactersToAppend, lengthToAppend * sizeof(UChar)); - m_impl = StringImpl::adopt(buffer); + UChar* data; + RefPtr<StringImpl> newImpl = + StringImpl::createUninitialized(length() + lengthToAppend, data); + memcpy(data, characters(), length() * sizeof(UChar)); + memcpy(data + length(), charactersToAppend, lengthToAppend * sizeof(UChar)); + m_impl = newImpl.release(); } void String::insert(const UChar* charactersToInsert, unsigned lengthToInsert, unsigned position) @@ -189,11 +197,13 @@ void String::insert(const UChar* charactersToInsert, unsigned lengthToInsert, un return; ASSERT(charactersToInsert); - StringBuffer buffer(length() + lengthToInsert); - memcpy(buffer.characters(), characters(), position * sizeof(UChar)); - memcpy(buffer.characters() + position, charactersToInsert, lengthToInsert * sizeof(UChar)); - memcpy(buffer.characters() + position + lengthToInsert, characters() + position, (length() - position) * sizeof(UChar)); - m_impl = StringImpl::adopt(buffer); + UChar* data; + RefPtr<StringImpl> newImpl = + StringImpl::createUninitialized(length() + lengthToInsert, data); + memcpy(data, characters(), position * sizeof(UChar)); + memcpy(data + position, charactersToInsert, lengthToInsert * sizeof(UChar)); + memcpy(data + position + lengthToInsert, characters() + position, (length() - position) * sizeof(UChar)); + m_impl = newImpl.release(); } UChar String::operator[](unsigned i) const @@ -221,9 +231,10 @@ void String::truncate(unsigned position) { if (position >= length()) return; - StringBuffer buffer(position); - memcpy(buffer.characters(), characters(), position * sizeof(UChar)); - m_impl = StringImpl::adopt(buffer); + UChar* data; + RefPtr<StringImpl> newImpl = StringImpl::createUninitialized(position, data); + memcpy(data, characters(), position * sizeof(UChar)); + m_impl = newImpl.release(); } void String::remove(unsigned position, int lengthToRemove) @@ -234,11 +245,13 @@ void String::remove(unsigned position, int lengthToRemove) return; if (static_cast<unsigned>(lengthToRemove) > length() - position) lengthToRemove = length() - position; - StringBuffer buffer(length() - lengthToRemove); - memcpy(buffer.characters(), characters(), position * sizeof(UChar)); - memcpy(buffer.characters() + position, characters() + position + lengthToRemove, + UChar* data; + RefPtr<StringImpl> newImpl = + StringImpl::createUninitialized(length() - lengthToRemove, data); + memcpy(data, characters(), position * sizeof(UChar)); + memcpy(data + position, characters() + position + lengthToRemove, (length() - lengthToRemove - position) * sizeof(UChar)); - m_impl = StringImpl::adopt(buffer); + m_impl = newImpl.release(); } String String::substring(unsigned pos, unsigned len) const @@ -637,21 +650,21 @@ String::String(const Identifier& str) { if (str.isNull()) return; - m_impl = StringImpl::create(str.data(), str.size()); + m_impl = StringImpl::create(str.ustring()); } String::String(const UString& str) { if (str.isNull()) return; - m_impl = StringImpl::create(str.data(), str.size()); + m_impl = StringImpl::create(str); } String::operator UString() const { if (!m_impl) return UString(); - return UString(m_impl->characters(), m_impl->length()); + return m_impl->ustring(); } #endif diff --git a/WebCore/platform/text/StringBuilder.cpp b/WebCore/platform/text/StringBuilder.cpp index 0e9555c..c21e366 100644 --- a/WebCore/platform/text/StringBuilder.cpp +++ b/WebCore/platform/text/StringBuilder.cpp @@ -79,9 +79,10 @@ String StringBuilder::toString() const if (count == 1) return m_strings[0]; - StringBuffer buffer(m_totalLength); + UChar* buffer; + String result = String::createUninitialized(m_totalLength, buffer); - UChar* p = buffer.characters(); + UChar* p = buffer; for (unsigned i = 0; i < count; ++i) { StringImpl* string = m_strings[i].impl(); unsigned length = string->length(); @@ -89,9 +90,9 @@ String StringBuilder::toString() const p += length; } - ASSERT(p == m_totalLength + buffer.characters()); + ASSERT(p == m_totalLength + buffer); - return String::adopt(buffer); + return result; } } diff --git a/WebCore/platform/text/StringImpl.cpp b/WebCore/platform/text/StringImpl.cpp index 6bba990..8bc4dde 100644 --- a/WebCore/platform/text/StringImpl.cpp +++ b/WebCore/platform/text/StringImpl.cpp @@ -44,6 +44,8 @@ using namespace Unicode; namespace WebCore { +static const unsigned minLengthToShare = 20; + static inline UChar* newUCharVector(unsigned n) { return static_cast<UChar*>(fastMalloc(sizeof(UChar) * n)); @@ -80,8 +82,6 @@ StringImpl::StringImpl() : m_length(0) , m_data(0) , m_hash(0) - , m_inTable(false) - , m_hasTerminatingNullCharacter(false) , m_bufferIsInternal(false) { // Ensure that the hash is computed so that AtomicStringHash can call existingHash() @@ -96,8 +96,6 @@ StringImpl::StringImpl() inline StringImpl::StringImpl(const UChar* characters, unsigned length) : m_length(length) , m_hash(0) - , m_inTable(false) - , m_hasTerminatingNullCharacter(false) , m_bufferIsInternal(false) { UChar* data = newUCharVector(length); @@ -108,10 +106,9 @@ inline StringImpl::StringImpl(const UChar* characters, unsigned length) inline StringImpl::StringImpl(const StringImpl& str, WithTerminatingNullCharacter) : m_length(str.m_length) , m_hash(str.m_hash) - , m_inTable(false) - , m_hasTerminatingNullCharacter(true) , m_bufferIsInternal(false) { + m_sharedBufferAndFlags.setFlag(HasTerminatingNullCharacter); UChar* data = newUCharVector(str.m_length + 1); memcpy(data, str.m_data, str.m_length * sizeof(UChar)); data[str.m_length] = 0; @@ -121,8 +118,6 @@ inline StringImpl::StringImpl(const StringImpl& str, WithTerminatingNullCharacte inline StringImpl::StringImpl(const char* characters, unsigned length) : m_length(length) , m_hash(0) - , m_inTable(false) - , m_hasTerminatingNullCharacter(false) , m_bufferIsInternal(false) { ASSERT(characters); @@ -140,8 +135,6 @@ inline StringImpl::StringImpl(UChar* characters, unsigned length, AdoptBuffer) : m_length(length) , m_data(characters) , m_hash(0) - , m_inTable(false) - , m_hasTerminatingNullCharacter(false) , m_bufferIsInternal(false) { ASSERT(characters); @@ -152,14 +145,13 @@ inline StringImpl::StringImpl(UChar* characters, unsigned length, AdoptBuffer) StringImpl::StringImpl(const UChar* characters, unsigned length, unsigned hash) : m_length(length) , m_hash(hash) - , m_inTable(true) - , m_hasTerminatingNullCharacter(false) , m_bufferIsInternal(false) { ASSERT(hash); ASSERT(characters); ASSERT(length); + setInTable(); UChar* data = newUCharVector(length); memcpy(data, characters, length * sizeof(UChar)); m_data = data; @@ -169,14 +161,13 @@ StringImpl::StringImpl(const UChar* characters, unsigned length, unsigned hash) StringImpl::StringImpl(const char* characters, unsigned length, unsigned hash) : m_length(length) , m_hash(hash) - , m_inTable(true) - , m_hasTerminatingNullCharacter(false) , m_bufferIsInternal(false) { ASSERT(hash); ASSERT(characters); ASSERT(length); + setInTable(); UChar* data = newUCharVector(length); for (unsigned i = 0; i != length; ++i) { unsigned char c = characters[i]; @@ -187,10 +178,15 @@ StringImpl::StringImpl(const char* characters, unsigned length, unsigned hash) StringImpl::~StringImpl() { - if (m_inTable) + if (inTable()) AtomicString::remove(this); - if (!m_bufferIsInternal) - deleteUCharVector(m_data); + if (!m_bufferIsInternal) { + SharedUChar* sharedBuffer = m_sharedBufferAndFlags.get(); + if (sharedBuffer) + sharedBuffer->deref(); + else + deleteUCharVector(m_data); + } } StringImpl* StringImpl::empty() @@ -264,7 +260,8 @@ bool StringImpl::isLower() PassRefPtr<StringImpl> StringImpl::lower() { - StringBuffer data(m_length); + UChar* data; + PassRefPtr<StringImpl> newImpl = createUninitialized(m_length, data); int32_t length = m_length; // Do a faster loop for the case where all the characters are ASCII. @@ -275,23 +272,24 @@ PassRefPtr<StringImpl> StringImpl::lower() data[i] = toASCIILower(c); } if (!(ored & ~0x7F)) - return adopt(data); + return newImpl; // Do a slower implementation for cases that include non-ASCII characters. bool error; - int32_t realLength = Unicode::toLower(data.characters(), length, m_data, m_length, &error); + int32_t realLength = Unicode::toLower(data, length, m_data, m_length, &error); if (!error && realLength == length) - return adopt(data); - data.resize(realLength); - Unicode::toLower(data.characters(), realLength, m_data, m_length, &error); + return newImpl; + newImpl = createUninitialized(realLength, data); + Unicode::toLower(data, realLength, m_data, m_length, &error); if (error) return this; - return adopt(data); + return newImpl; } PassRefPtr<StringImpl> StringImpl::upper() { - StringBuffer data(m_length); + UChar* data; + PassRefPtr<StringImpl> newImpl = createUninitialized(m_length, data); int32_t length = m_length; // Do a faster loop for the case where all the characters are ASCII. @@ -302,32 +300,34 @@ PassRefPtr<StringImpl> StringImpl::upper() data[i] = toASCIIUpper(c); } if (!(ored & ~0x7F)) - return adopt(data); + return newImpl; // Do a slower implementation for cases that include non-ASCII characters. bool error; - int32_t realLength = Unicode::toUpper(data.characters(), length, m_data, m_length, &error); + int32_t realLength = Unicode::toUpper(data, length, m_data, m_length, &error); if (!error && realLength == length) - return adopt(data); - data.resize(realLength); - Unicode::toUpper(data.characters(), realLength, m_data, m_length, &error); + return newImpl; + newImpl = createUninitialized(realLength, data); + Unicode::toUpper(data, realLength, m_data, m_length, &error); if (error) return this; - return adopt(data); + return newImpl; } PassRefPtr<StringImpl> StringImpl::secure(UChar aChar) { - int length = m_length; - StringBuffer data(length); + UChar* data; + PassRefPtr<StringImpl> newImpl = createUninitialized(m_length, data); + int32_t length = m_length; for (int i = 0; i < length; ++i) data[i] = aChar; - return adopt(data); + return newImpl; } PassRefPtr<StringImpl> StringImpl::foldCase() { - StringBuffer data(m_length); + UChar* data; + PassRefPtr<StringImpl> newImpl = createUninitialized(m_length, data); int32_t length = m_length; // Do a faster loop for the case where all the characters are ASCII. @@ -338,18 +338,18 @@ PassRefPtr<StringImpl> StringImpl::foldCase() data[i] = toASCIILower(c); } if (!(ored & ~0x7F)) - return adopt(data); + return newImpl; // Do a slower implementation for cases that include non-ASCII characters. bool error; - int32_t realLength = Unicode::foldCase(data.characters(), length, m_data, m_length, &error); + int32_t realLength = Unicode::foldCase(data, length, m_data, m_length, &error); if (!error && realLength == length) - return adopt(data); - data.resize(realLength); - Unicode::foldCase(data.characters(), realLength, m_data, m_length, &error); + return newImpl; + newImpl = createUninitialized(realLength, data); + Unicode::foldCase(data, realLength, m_data, m_length, &error); if (error) return this; - return adopt(data); + return newImpl; } PassRefPtr<StringImpl> StringImpl::stripWhiteSpace() @@ -727,14 +727,16 @@ PassRefPtr<StringImpl> StringImpl::replace(UChar oldC, UChar newC) if (i == m_length) return this; - StringBuffer data(m_length); + UChar* data; + PassRefPtr<StringImpl> newImpl = createUninitialized(m_length, data); + for (i = 0; i != m_length; ++i) { UChar ch = m_data[i]; if (ch == oldC) ch = newC; data[i] = ch; } - return adopt(data); + return newImpl; } PassRefPtr<StringImpl> StringImpl::replace(unsigned position, unsigned lengthToReplace, StringImpl* str) @@ -744,13 +746,15 @@ PassRefPtr<StringImpl> StringImpl::replace(unsigned position, unsigned lengthToR unsigned lengthToInsert = str ? str->length() : 0; if (!lengthToReplace && !lengthToInsert) return this; - StringBuffer buffer(length() - lengthToReplace + lengthToInsert); - memcpy(buffer.characters(), characters(), position * sizeof(UChar)); + UChar* data; + PassRefPtr<StringImpl> newImpl = + createUninitialized(length() - lengthToReplace + lengthToInsert, data); + memcpy(data, characters(), position * sizeof(UChar)); if (str) - memcpy(buffer.characters() + position, str->characters(), lengthToInsert * sizeof(UChar)); - memcpy(buffer.characters() + position + lengthToInsert, characters() + position + lengthToReplace, + memcpy(data + position, str->characters(), lengthToInsert * sizeof(UChar)); + memcpy(data + position + lengthToInsert, characters() + position + lengthToReplace, (length() - position - lengthToReplace) * sizeof(UChar)); - return adopt(buffer); + return newImpl; } PassRefPtr<StringImpl> StringImpl::replace(UChar pattern, StringImpl* replacement) @@ -772,8 +776,10 @@ PassRefPtr<StringImpl> StringImpl::replace(UChar pattern, StringImpl* replacemen if (!matchCount) return this; - StringBuffer data(m_length - matchCount + (matchCount * repStrLength)); - + UChar* data; + PassRefPtr<StringImpl> newImpl = + createUninitialized(m_length - matchCount + (matchCount * repStrLength), data); + // Construct the new data int srcSegmentEnd; int srcSegmentLength; @@ -782,19 +788,19 @@ PassRefPtr<StringImpl> StringImpl::replace(UChar pattern, StringImpl* replacemen while ((srcSegmentEnd = find(pattern, srcSegmentStart)) >= 0) { srcSegmentLength = srcSegmentEnd - srcSegmentStart; - memcpy(data.characters() + dstOffset, m_data + srcSegmentStart, srcSegmentLength * sizeof(UChar)); + memcpy(data + dstOffset, m_data + srcSegmentStart, srcSegmentLength * sizeof(UChar)); dstOffset += srcSegmentLength; - memcpy(data.characters() + dstOffset, replacement->m_data, repStrLength * sizeof(UChar)); + memcpy(data + dstOffset, replacement->m_data, repStrLength * sizeof(UChar)); dstOffset += repStrLength; srcSegmentStart = srcSegmentEnd + 1; } srcSegmentLength = m_length - srcSegmentStart; - memcpy(data.characters() + dstOffset, m_data + srcSegmentStart, srcSegmentLength * sizeof(UChar)); + memcpy(data + dstOffset, m_data + srcSegmentStart, srcSegmentLength * sizeof(UChar)); - ASSERT(dstOffset + srcSegmentLength == static_cast<int>(data.length())); + ASSERT(dstOffset + srcSegmentLength == static_cast<int>(newImpl->length())); - return adopt(data); + return newImpl; } PassRefPtr<StringImpl> StringImpl::replace(StringImpl* pattern, StringImpl* replacement) @@ -820,7 +826,9 @@ PassRefPtr<StringImpl> StringImpl::replace(StringImpl* pattern, StringImpl* repl if (!matchCount) return this; - StringBuffer data(m_length + matchCount * (repStrLength - patternLength)); + UChar* data; + PassRefPtr<StringImpl> newImpl = + createUninitialized(m_length + matchCount * (repStrLength - patternLength), data); // Construct the new data int srcSegmentEnd; @@ -830,19 +838,19 @@ PassRefPtr<StringImpl> StringImpl::replace(StringImpl* pattern, StringImpl* repl while ((srcSegmentEnd = find(pattern, srcSegmentStart)) >= 0) { srcSegmentLength = srcSegmentEnd - srcSegmentStart; - memcpy(data.characters() + dstOffset, m_data + srcSegmentStart, srcSegmentLength * sizeof(UChar)); + memcpy(data + dstOffset, m_data + srcSegmentStart, srcSegmentLength * sizeof(UChar)); dstOffset += srcSegmentLength; - memcpy(data.characters() + dstOffset, replacement->m_data, repStrLength * sizeof(UChar)); + memcpy(data + dstOffset, replacement->m_data, repStrLength * sizeof(UChar)); dstOffset += repStrLength; srcSegmentStart = srcSegmentEnd + patternLength; } srcSegmentLength = m_length - srcSegmentStart; - memcpy(data.characters() + dstOffset, m_data + srcSegmentStart, srcSegmentLength * sizeof(UChar)); + memcpy(data + dstOffset, m_data + srcSegmentStart, srcSegmentLength * sizeof(UChar)); - ASSERT(dstOffset + srcSegmentLength == static_cast<int>(data.length())); + ASSERT(dstOffset + srcSegmentLength == static_cast<int>(newImpl->length())); - return adopt(data); + return newImpl; } bool equal(StringImpl* a, StringImpl* b) @@ -965,41 +973,47 @@ PassRefPtr<StringImpl> StringImpl::adopt(Vector<UChar>& vector) return adoptRef(new StringImpl(vector.releaseBuffer(), size, AdoptBuffer())); } -PassRefPtr<StringImpl> StringImpl::create(const UChar* characters, unsigned length) +PassRefPtr<StringImpl> StringImpl::createUninitialized(unsigned length, UChar*& data) { - if (!characters || !length) + if (!length) { + data = 0; return empty(); + } // Allocate a single buffer large enough to contain the StringImpl // struct as well as the data which it contains. This removes one // heap allocation from this call. size_t size = sizeof(StringImpl) + length * sizeof(UChar); char* buffer = static_cast<char*>(fastMalloc(size)); - UChar* data = reinterpret_cast<UChar*>(buffer + sizeof(StringImpl)); - memcpy(data, characters, length * sizeof(UChar)); + data = reinterpret_cast<UChar*>(buffer + sizeof(StringImpl)); StringImpl* string = new (buffer) StringImpl(data, length, AdoptBuffer()); string->m_bufferIsInternal = true; return adoptRef(string); } +PassRefPtr<StringImpl> StringImpl::create(const UChar* characters, unsigned length) +{ + if (!characters || !length) + return empty(); + + UChar* data; + PassRefPtr<StringImpl> string = createUninitialized(length, data); + memcpy(data, characters, length * sizeof(UChar)); + return string; +} + PassRefPtr<StringImpl> StringImpl::create(const char* characters, unsigned length) { if (!characters || !length) return empty(); - // Allocate a single buffer large enough to contain the StringImpl - // struct as well as the data which it contains. This removes one - // heap allocation from this call. - size_t size = sizeof(StringImpl) + length * sizeof(UChar); - char* buffer = static_cast<char*>(fastMalloc(size)); - UChar* data = reinterpret_cast<UChar*>(buffer + sizeof(StringImpl)); + UChar* data; + PassRefPtr<StringImpl> string = createUninitialized(length, data); for (unsigned i = 0; i != length; ++i) { unsigned char c = characters[i]; data[i] = c; } - StringImpl* string = new (buffer) StringImpl(data, length, AdoptBuffer()); - string->m_bufferIsInternal = true; - return adoptRef(string); + return string; } PassRefPtr<StringImpl> StringImpl::create(const char* string) @@ -1009,6 +1023,29 @@ PassRefPtr<StringImpl> StringImpl::create(const char* string) return create(string, strlen(string)); } +#if USE(JSC) +PassRefPtr<StringImpl> StringImpl::create(const JSC::UString& str) +{ + SharedUChar* sharedBuffer = const_cast<JSC::UString*>(&str)->rep()->baseString()->sharedBuffer(); + if (sharedBuffer) { + PassRefPtr<StringImpl> impl = adoptRef(new StringImpl(const_cast<UChar*>(str.data()), str.size(), AdoptBuffer())); + sharedBuffer->ref(); + impl->m_sharedBufferAndFlags.set(sharedBuffer); + return impl; + } + return StringImpl::create(str.data(), str.size()); +} + +JSC::UString StringImpl::ustring() +{ + SharedUChar* sharedBuffer = StringImpl::sharedBuffer(); + if (sharedBuffer) + return JSC::UString::Rep::create(const_cast<UChar*>(m_data), m_length, sharedBuffer); + + return JSC::UString(m_data, m_length); +} +#endif + PassRefPtr<StringImpl> StringImpl::createWithTerminatingNullCharacter(const StringImpl& string) { return adoptRef(new StringImpl(string, WithTerminatingNullCharacter())); @@ -1019,4 +1056,15 @@ PassRefPtr<StringImpl> StringImpl::copy() return create(m_data, m_length); } +StringImpl::SharedUChar* StringImpl::sharedBuffer() +{ + if (m_length < minLengthToShare || m_bufferIsInternal) + return 0; + + if (!m_sharedBufferAndFlags.get()) + m_sharedBufferAndFlags.set(SharedUChar::create(new OwnFastMallocPtr<UChar>(const_cast<UChar*>(m_data))).releaseRef()); + return m_sharedBufferAndFlags.get(); +} + + } // namespace WebCore diff --git a/WebCore/platform/text/StringImpl.h b/WebCore/platform/text/StringImpl.h index 1242f27..f591800 100644 --- a/WebCore/platform/text/StringImpl.h +++ b/WebCore/platform/text/StringImpl.h @@ -1,6 +1,7 @@ /* * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google 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 @@ -24,11 +25,18 @@ #include <limits.h> #include <wtf/ASCIICType.h> +#include <wtf/CrossThreadRefCounted.h> +#include <wtf/OwnFastMallocPtr.h> #include <wtf/PassRefPtr.h> +#include <wtf/PtrAndFlags.h> #include <wtf/RefCounted.h> #include <wtf/Vector.h> #include <wtf/unicode/Unicode.h> +#if USE(JSC) +#include <runtime/UString.h> +#endif + #if PLATFORM(CF) || (PLATFORM(QT) && PLATFORM(DARWIN)) typedef const struct __CFString * CFStringRef; #endif @@ -72,23 +80,34 @@ private: StringImpl(const UChar*, unsigned length, unsigned hash); StringImpl(const char*, unsigned length, unsigned hash); + typedef CrossThreadRefCounted<OwnFastMallocPtr<UChar> > SharedUChar; + public: ~StringImpl(); static PassRefPtr<StringImpl> create(const UChar*, unsigned length); static PassRefPtr<StringImpl> create(const char*, unsigned length); static PassRefPtr<StringImpl> create(const char*); + static PassRefPtr<StringImpl> createUninitialized(unsigned length, UChar*& data); static PassRefPtr<StringImpl> createWithTerminatingNullCharacter(const StringImpl&); static PassRefPtr<StringImpl> createStrippingNullCharacters(const UChar*, unsigned length); static PassRefPtr<StringImpl> adopt(StringBuffer&); static PassRefPtr<StringImpl> adopt(Vector<UChar>&); +#if USE(JSC) + static PassRefPtr<StringImpl> create(const JSC::UString&); + JSC::UString ustring(); +#endif + SharedUChar* sharedBuffer(); const UChar* characters() { return m_data; } unsigned length() { return m_length; } - bool hasTerminatingNullCharacter() { return m_hasTerminatingNullCharacter; } + bool hasTerminatingNullCharacter() const { return m_sharedBufferAndFlags.isFlagSet(HasTerminatingNullCharacter); } + + bool inTable() const { return m_sharedBufferAndFlags.isFlagSet(InTable); } + void setInTable() { return m_sharedBufferAndFlags.setFlag(InTable); } unsigned hash() { if (m_hash == 0) m_hash = computeHash(m_data, m_length); return m_hash; } unsigned existingHash() const { ASSERT(m_hash); return m_hash; } @@ -176,11 +195,16 @@ private: static PassRefPtr<StringImpl> createStrippingNullCharactersSlowCase(const UChar*, unsigned length); + enum StringImplFlags { + HasTerminatingNullCharacter, + InTable, + }; + unsigned m_length; const UChar* m_data; mutable unsigned m_hash; - bool m_inTable; - bool m_hasTerminatingNullCharacter; + PtrAndFlags<SharedUChar, StringImplFlags> m_sharedBufferAndFlags; + // In some cases, we allocate the StringImpl struct and its data // within a single heap buffer. In this case, the m_data pointer // is an "internal buffer", and does not need to be deallocated. diff --git a/WebCore/platform/text/TextBoundaries.h b/WebCore/platform/text/TextBoundaries.h index 118dd1a..7eb9cab 100644 --- a/WebCore/platform/text/TextBoundaries.h +++ b/WebCore/platform/text/TextBoundaries.h @@ -30,6 +30,11 @@ namespace WebCore { + inline bool requiresContextForWordBoundary(UChar32 ch) + { + return WTF::Unicode::hasLineBreakingPropertyComplexContext(ch); + } + void findWordBoundary(const UChar*, int len, int position, int* start, int* end); int findNextWordFromIndex(const UChar*, int len, int position, bool forward); diff --git a/WebCore/platform/text/TextBoundariesICU.cpp b/WebCore/platform/text/TextBoundariesICU.cpp index d226048..b1e8ee2 100644 --- a/WebCore/platform/text/TextBoundariesICU.cpp +++ b/WebCore/platform/text/TextBoundariesICU.cpp @@ -27,6 +27,7 @@ #include "TextBoundaries.h" #include <unicode/ubrk.h> +#include <unicode/uchar.h> #include "StringImpl.h" #include "TextBreakIterator.h" diff --git a/WebCore/platform/text/TextCodec.h b/WebCore/platform/text/TextCodec.h index 0a56262..df42582 100644 --- a/WebCore/platform/text/TextCodec.h +++ b/WebCore/platform/text/TextCodec.h @@ -29,6 +29,7 @@ #include <memory> #include <wtf/Noncopyable.h> +#include <wtf/PassOwnPtr.h> #include <wtf/Vector.h> #include <wtf/unicode/Unicode.h> @@ -76,7 +77,7 @@ namespace WebCore { typedef void (*EncodingNameRegistrar)(const char* alias, const char* name); - typedef std::auto_ptr<TextCodec> (*NewTextCodecFunction)(const TextEncoding&, const void* additionalData); + typedef PassOwnPtr<TextCodec> (*NewTextCodecFunction)(const TextEncoding&, const void* additionalData); typedef void (*TextCodecRegistrar)(const char* name, NewTextCodecFunction, const void* additionalData); } // namespace WebCore diff --git a/WebCore/platform/text/TextCodecICU.cpp b/WebCore/platform/text/TextCodecICU.cpp index 72054fa..b8e40a9 100644 --- a/WebCore/platform/text/TextCodecICU.cpp +++ b/WebCore/platform/text/TextCodecICU.cpp @@ -34,10 +34,10 @@ #include <unicode/ucnv.h> #include <unicode/ucnv_cb.h> #include <wtf/Assertions.h> +#include <wtf/PassOwnPtr.h> #include <wtf/StringExtras.h> #include <wtf/Threading.h> -using std::auto_ptr; using std::min; namespace WebCore { @@ -55,9 +55,9 @@ static UConverter*& cachedConverterICU() return threadGlobalData().cachedConverterICU().converter; } -static auto_ptr<TextCodec> newTextCodecICU(const TextEncoding& encoding, const void*) +static PassOwnPtr<TextCodec> newTextCodecICU(const TextEncoding& encoding, const void*) { - return auto_ptr<TextCodec>(new TextCodecICU(encoding)); + return new TextCodecICU(encoding); } void TextCodecICU::registerBaseEncodingNames(EncodingNameRegistrar registrar) diff --git a/WebCore/platform/text/TextCodecICU.h b/WebCore/platform/text/TextCodecICU.h index f07758f..bf517f7 100644 --- a/WebCore/platform/text/TextCodecICU.h +++ b/WebCore/platform/text/TextCodecICU.h @@ -30,6 +30,8 @@ #include "TextCodec.h" #include "TextEncoding.h" +#include <unicode/utypes.h> + typedef struct UConverter UConverter; namespace WebCore { diff --git a/WebCore/platform/text/TextCodecLatin1.cpp b/WebCore/platform/text/TextCodecLatin1.cpp index 50f9f97..cfdc5b9 100644 --- a/WebCore/platform/text/TextCodecLatin1.cpp +++ b/WebCore/platform/text/TextCodecLatin1.cpp @@ -30,8 +30,7 @@ #include "PlatformString.h" #include "StringBuffer.h" #include <stdio.h> - -using std::auto_ptr; +#include <wtf/PassOwnPtr.h> namespace WebCore { @@ -104,9 +103,9 @@ void TextCodecLatin1::registerEncodingNames(EncodingNameRegistrar registrar) registrar("x-ansi", "US-ASCII"); } -static auto_ptr<TextCodec> newStreamingTextDecoderWindowsLatin1(const TextEncoding&, const void*) +static PassOwnPtr<TextCodec> newStreamingTextDecoderWindowsLatin1(const TextEncoding&, const void*) { - return auto_ptr<TextCodec>(new TextCodecLatin1); + return new TextCodecLatin1; } void TextCodecLatin1::registerCodecs(TextCodecRegistrar registrar) @@ -120,7 +119,8 @@ void TextCodecLatin1::registerCodecs(TextCodecRegistrar registrar) String TextCodecLatin1::decode(const char* bytes, size_t length, bool, bool, bool&) { - StringBuffer characters(length); + UChar* characters; + String result = String::createUninitialized(length, characters); // Convert the string a fast way and simultaneously do an efficient check to see if it's all ASCII. unsigned char ored = 0; @@ -131,7 +131,7 @@ String TextCodecLatin1::decode(const char* bytes, size_t length, bool, bool, boo } if (!(ored & 0x80)) - return String::adopt(characters); + return result; // Convert the slightly slower way when there are non-ASCII characters. for (size_t i = 0; i < length; ++i) { @@ -139,7 +139,7 @@ String TextCodecLatin1::decode(const char* bytes, size_t length, bool, bool, boo characters[i] = table[c]; } - return String::adopt(characters); + return result; } static CString encodeComplexWindowsLatin1(const UChar* characters, size_t length, UnencodableHandling handling) diff --git a/WebCore/platform/text/TextCodecUTF16.cpp b/WebCore/platform/text/TextCodecUTF16.cpp index a4d0d28..db77000 100644 --- a/WebCore/platform/text/TextCodecUTF16.cpp +++ b/WebCore/platform/text/TextCodecUTF16.cpp @@ -29,8 +29,7 @@ #include "CString.h" #include "PlatformString.h" #include "StringBuffer.h" - -using std::auto_ptr; +#include <wtf/PassOwnPtr.h> namespace WebCore { @@ -49,14 +48,14 @@ void TextCodecUTF16::registerEncodingNames(EncodingNameRegistrar registrar) registrar("unicodeFFFE", "UTF-16BE"); } -static auto_ptr<TextCodec> newStreamingTextDecoderUTF16LE(const TextEncoding&, const void*) +static PassOwnPtr<TextCodec> newStreamingTextDecoderUTF16LE(const TextEncoding&, const void*) { - return auto_ptr<TextCodec>(new TextCodecUTF16(true)); + return new TextCodecUTF16(true); } -static auto_ptr<TextCodec> newStreamingTextDecoderUTF16BE(const TextEncoding&, const void*) +static PassOwnPtr<TextCodec> newStreamingTextDecoderUTF16BE(const TextEncoding&, const void*) { - return auto_ptr<TextCodec>(new TextCodecUTF16(false)); + return new TextCodecUTF16(false); } void TextCodecUTF16::registerCodecs(TextCodecRegistrar registrar) diff --git a/WebCore/platform/text/TextCodecUserDefined.cpp b/WebCore/platform/text/TextCodecUserDefined.cpp index 2dae0f3..b7c8896 100644 --- a/WebCore/platform/text/TextCodecUserDefined.cpp +++ b/WebCore/platform/text/TextCodecUserDefined.cpp @@ -30,8 +30,7 @@ #include "PlatformString.h" #include "StringBuffer.h" #include <stdio.h> - -using std::auto_ptr; +#include <wtf/PassOwnPtr.h> namespace WebCore { @@ -40,9 +39,9 @@ void TextCodecUserDefined::registerEncodingNames(EncodingNameRegistrar registrar registrar("x-user-defined", "x-user-defined"); } -static auto_ptr<TextCodec> newStreamingTextDecoderUserDefined(const TextEncoding&, const void*) +static PassOwnPtr<TextCodec> newStreamingTextDecoderUserDefined(const TextEncoding&, const void*) { - return auto_ptr<TextCodec>(new TextCodecUserDefined); + return new TextCodecUserDefined; } void TextCodecUserDefined::registerCodecs(TextCodecRegistrar registrar) @@ -52,14 +51,15 @@ void TextCodecUserDefined::registerCodecs(TextCodecRegistrar registrar) String TextCodecUserDefined::decode(const char* bytes, size_t length, bool, bool, bool&) { - StringBuffer buffer(length); + UChar* buffer; + String result = String::createUninitialized(length, buffer); for (size_t i = 0; i < length; ++i) { signed char c = bytes[i]; buffer[i] = c & 0xF7FF; } - return String::adopt(buffer); + return result; } static CString encodeComplexUserDefined(const UChar* characters, size_t length, UnencodableHandling handling) diff --git a/WebCore/platform/text/TextEncoding.cpp b/WebCore/platform/text/TextEncoding.cpp index ed58412..5fa927b 100644 --- a/WebCore/platform/text/TextEncoding.cpp +++ b/WebCore/platform/text/TextEncoding.cpp @@ -31,7 +31,7 @@ #include "PlatformString.h" #include "TextCodec.h" #include "TextEncodingRegistry.h" -#if USE(ICU_UNICODE) +#if USE(ICU_UNICODE) || USE(GLIB_ICU_UNICODE_HYBRID) #include <unicode/unorm.h> #elif USE(QT4_UNICODE) #include <QString> @@ -83,7 +83,7 @@ CString TextEncoding::encode(const UChar* characters, size_t length, Unencodable if (!length) return ""; -#if USE(ICU_UNICODE) +#if USE(ICU_UNICODE) || USE(GLIB_ICU_UNICODE_HYBRID) // 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. @@ -116,6 +116,24 @@ CString TextEncoding::encode(const UChar* characters, size_t length, Unencodable #endif } +const char* TextEncoding::domName() const +{ + if (noExtendedTextEncodingNameUsed()) + return m_name; + + // We treat EUC-KR as windows-949 (its superset), but need to expose + // the name 'EUC-KR' because the name 'windows-949' is not recognized by + // most Korean web servers even though they do use the encoding + // 'windows-949' with the name 'EUC-KR'. + // FIXME: This is not thread-safe. At the moment, this function is + // only accessed in a single thread, but eventually has to be made + // thread-safe along with usesVisualOrdering(). + static const char* const a = atomicCanonicalTextEncodingName("windows-949"); + if (m_name == a) + return "EUC-KR"; + return m_name; +} + bool TextEncoding::usesVisualOrdering() const { if (noExtendedTextEncodingNameUsed()) diff --git a/WebCore/platform/text/TextEncoding.h b/WebCore/platform/text/TextEncoding.h index b3909f7..a99bfc8 100644 --- a/WebCore/platform/text/TextEncoding.h +++ b/WebCore/platform/text/TextEncoding.h @@ -42,6 +42,7 @@ namespace WebCore { bool isValid() const { return m_name; } const char* name() const { return m_name; } + const char* domName() const; // name exposed via DOM bool usesVisualOrdering() const; bool isJapanese() const; diff --git a/WebCore/platform/text/TextEncodingDetectorICU.cpp b/WebCore/platform/text/TextEncodingDetectorICU.cpp index 26c997e..fcb2aa9 100644 --- a/WebCore/platform/text/TextEncodingDetectorICU.cpp +++ b/WebCore/platform/text/TextEncodingDetectorICU.cpp @@ -32,7 +32,7 @@ #include "TextEncodingDetector.h" #include "TextEncoding.h" -#include "UnusedParam.h" +#include <wtf/UnusedParam.h> #ifndef BUILDING_ON_TIGER #include "unicode/ucnv.h" diff --git a/WebCore/platform/text/TextEncodingDetectorNone.cpp b/WebCore/platform/text/TextEncodingDetectorNone.cpp index 2655f08..3b62bc5 100644 --- a/WebCore/platform/text/TextEncodingDetectorNone.cpp +++ b/WebCore/platform/text/TextEncodingDetectorNone.cpp @@ -32,18 +32,11 @@ #include "TextEncodingDetector.h" #include "TextEncoding.h" -#include "UnusedParam.h" namespace WebCore { -bool detectTextEncoding(const char* data, size_t len, - const char* hintEncodingName, - TextEncoding* detectedEncoding) +bool detectTextEncoding(const char*, size_t, const char*, TextEncoding* detectedEncoding) { - UNUSED_PARAM(data) - UNUSED_PARAM(len) - UNUSED_PARAM(hintEncodingName) - *detectedEncoding = TextEncoding(); return false; } diff --git a/WebCore/platform/text/TextEncodingRegistry.cpp b/WebCore/platform/text/TextEncodingRegistry.cpp index 2d89fac..3c9d65f 100644 --- a/WebCore/platform/text/TextEncodingRegistry.cpp +++ b/WebCore/platform/text/TextEncodingRegistry.cpp @@ -38,7 +38,7 @@ #include <wtf/StringExtras.h> #include <wtf/Threading.h> -#if USE(ICU_UNICODE) +#if USE(ICU_UNICODE) || USE(GLIB_ICU_UNICODE_HYBRID) #include "TextCodecICU.h" #endif #if PLATFORM(MAC) @@ -185,7 +185,7 @@ static void buildBaseTextCodecMaps() TextCodecUserDefined::registerEncodingNames(addToTextEncodingNameMap); TextCodecUserDefined::registerCodecs(addToTextCodecMap); -#if USE(ICU_UNICODE) +#if USE(ICU_UNICODE) || USE(GLIB_ICU_UNICODE_HYBRID) TextCodecICU::registerBaseEncodingNames(addToTextEncodingNameMap); TextCodecICU::registerBaseCodecs(addToTextCodecMap); #endif @@ -193,7 +193,7 @@ static void buildBaseTextCodecMaps() static void extendTextCodecMaps() { -#if USE(ICU_UNICODE) +#if USE(ICU_UNICODE) || USE(GLIB_ICU_UNICODE_HYBRID) TextCodecICU::registerExtendedEncodingNames(addToTextEncodingNameMap); TextCodecICU::registerExtendedCodecs(addToTextCodecMap); #endif @@ -209,7 +209,7 @@ static void extendTextCodecMaps() #endif } -std::auto_ptr<TextCodec> newTextCodec(const TextEncoding& encoding) +PassOwnPtr<TextCodec> newTextCodec(const TextEncoding& encoding) { MutexLocker lock(encodingRegistryMutex()); diff --git a/WebCore/platform/text/TextEncodingRegistry.h b/WebCore/platform/text/TextEncodingRegistry.h index d204734..e6950cf 100644 --- a/WebCore/platform/text/TextEncodingRegistry.h +++ b/WebCore/platform/text/TextEncodingRegistry.h @@ -27,6 +27,7 @@ #define TextEncodingRegistry_h #include <memory> +#include <wtf/PassOwnPtr.h> #include <wtf/unicode/Unicode.h> namespace WebCore { @@ -36,7 +37,7 @@ namespace WebCore { // Use TextResourceDecoder::decode to decode resources, since it handles BOMs. // Use TextEncoding::encode to encode, since it takes care of normalization. - std::auto_ptr<TextCodec> newTextCodec(const TextEncoding&); + PassOwnPtr<TextCodec> newTextCodec(const TextEncoding&); // Only TextEncoding should use this function directly. const char* atomicCanonicalTextEncodingName(const char* alias); diff --git a/WebCore/platform/text/mac/TextBoundaries.mm b/WebCore/platform/text/mac/TextBoundaries.mm index ff1dfd2..bd7ddf8 100644 --- a/WebCore/platform/text/mac/TextBoundaries.mm +++ b/WebCore/platform/text/mac/TextBoundaries.mm @@ -26,6 +26,8 @@ #import "config.h" #import "TextBoundaries.h" +using namespace WTF::Unicode; + namespace WebCore { void findWordBoundary(const UChar* chars, int len, int position, int* start, int* end) diff --git a/WebCore/platform/text/mac/TextCodecMac.cpp b/WebCore/platform/text/mac/TextCodecMac.cpp index 3baf21f..93b9da2 100644 --- a/WebCore/platform/text/mac/TextCodecMac.cpp +++ b/WebCore/platform/text/mac/TextCodecMac.cpp @@ -33,9 +33,9 @@ #include "PlatformString.h" #include "ThreadGlobalData.h" #include <wtf/Assertions.h> +#include <wtf/PassOwnPtr.h> #include <wtf/Threading.h> -using std::auto_ptr; using std::min; namespace WebCore { @@ -64,9 +64,9 @@ void TextCodecMac::registerEncodingNames(EncodingNameRegistrar registrar) } } -static auto_ptr<TextCodec> newTextCodecMac(const TextEncoding&, const void* additionalData) +static PassOwnPtr<TextCodec> newTextCodecMac(const TextEncoding&, const void* additionalData) { - return auto_ptr<TextCodec>(new TextCodecMac(*static_cast<const TECTextEncodingID*>(additionalData))); + return new TextCodecMac(*static_cast<const TECTextEncodingID*>(additionalData)); } void TextCodecMac::registerCodecs(TextCodecRegistrar registrar) diff --git a/WebCore/platform/text/qt/TextBreakIteratorQt.cpp b/WebCore/platform/text/qt/TextBreakIteratorQt.cpp index 4dc23ee..06e8f37 100644 --- a/WebCore/platform/text/qt/TextBreakIteratorQt.cpp +++ b/WebCore/platform/text/qt/TextBreakIteratorQt.cpp @@ -20,6 +20,7 @@ * */ +#include "config.h" #include "TextBreakIterator.h" #if QT_VERSION >= 0x040400 diff --git a/WebCore/platform/text/qt/TextCodecQt.cpp b/WebCore/platform/text/qt/TextCodecQt.cpp index 0f385dd..c6c02cf 100644 --- a/WebCore/platform/text/qt/TextCodecQt.cpp +++ b/WebCore/platform/text/qt/TextCodecQt.cpp @@ -63,9 +63,9 @@ void TextCodecQt::registerEncodingNames(EncodingNameRegistrar registrar) } } -static std::auto_ptr<TextCodec> newTextCodecQt(const TextEncoding& encoding, const void*) +static PassOwnPtr<TextCodec> newTextCodecQt(const TextEncoding& encoding, const void*) { - return std::auto_ptr<TextCodec>(new TextCodecQt(encoding)); + return new TextCodecQt(encoding); } void TextCodecQt::registerCodecs(TextCodecRegistrar registrar) diff --git a/WebCore/platform/text/win/TextBreakIteratorInternalICUWin.cpp b/WebCore/platform/text/win/TextBreakIteratorInternalICUWin.cpp index 14cf130..ce436df 100644 --- a/WebCore/platform/text/win/TextBreakIteratorInternalICUWin.cpp +++ b/WebCore/platform/text/win/TextBreakIteratorInternalICUWin.cpp @@ -25,7 +25,11 @@ namespace WebCore { const char* currentTextBreakLocaleID() { - return "en_us"; + // Using en_US_POSIX now so word selection in address field works as expected as before (double-clicking + // in a URL selects a word delimited by periods rather than selecting the entire URL). + // However, this is not entirely correct - we should honor the system locale in the normal case. + // FIXME: <rdar://problem/6786703> Should use system locale for text breaking + return "en_US_POSIX"; } } diff --git a/WebCore/platform/win/ClipboardUtilitiesWin.cpp b/WebCore/platform/win/ClipboardUtilitiesWin.cpp index 3762a1a..0358b7a 100644 --- a/WebCore/platform/win/ClipboardUtilitiesWin.cpp +++ b/WebCore/platform/win/ClipboardUtilitiesWin.cpp @@ -291,7 +291,12 @@ static bool urlFromPath(CFStringRef path, String& url) if (!cfURL) return false; - url = String(CFURLGetString(cfURL.get())); + url = CFURLGetString(cfURL.get()); + + // Work around <rdar://problem/6708300>, where CFURLCreateWithFileSystemPath makes URLs with "localhost". + if (url.startsWith("file://localhost/")) + url.remove(7, 9); + return true; } diff --git a/WebCore/platform/win/EditorWin.cpp b/WebCore/platform/win/EditorWin.cpp index 813eb78..09abdbd 100644 --- a/WebCore/platform/win/EditorWin.cpp +++ b/WebCore/platform/win/EditorWin.cpp @@ -31,7 +31,6 @@ #include "Document.h" #include "Element.h" #include "htmlediting.h" -#include "NotImplemented.h" #include "TextIterator.h" #include "visible_units.h" diff --git a/WebCore/platform/win/Language.cpp b/WebCore/platform/win/Language.cpp index 787c5a3..588c5df 100644 --- a/WebCore/platform/win/Language.cpp +++ b/WebCore/platform/win/Language.cpp @@ -37,11 +37,11 @@ static String localeInfo(LCTYPE localeType, const String& fallback) int localeChars = GetLocaleInfo(langID, localeType, 0, 0); if (!localeChars) return fallback; - Vector<WCHAR> localeNameBuf(localeChars); - localeChars = GetLocaleInfo(langID, localeType, localeNameBuf.data(), localeChars); + UChar* localeNameBuf; + String localeName = String::createUninitialized(localeChars, localeNameBuf); + localeChars = GetLocaleInfo(langID, localeType, localeNameBuf, localeChars); if (!localeChars) return fallback; - String localeName = String::adopt(localeNameBuf); if (localeName.isEmpty()) return fallback; diff --git a/WebCore/platform/win/PasteboardWin.cpp b/WebCore/platform/win/PasteboardWin.cpp index 506cc7b..8cf9bf2 100644 --- a/WebCore/platform/win/PasteboardWin.cpp +++ b/WebCore/platform/win/PasteboardWin.cpp @@ -35,7 +35,6 @@ #include "HitTestResult.h" #include "Image.h" #include "KURL.h" -#include "NotImplemented.h" #include "Page.h" #include "Range.h" #include "RenderImage.h" diff --git a/WebCore/platform/win/PopupMenuWin.cpp b/WebCore/platform/win/PopupMenuWin.cpp index 52f2eb9..2b4749a 100644 --- a/WebCore/platform/win/PopupMenuWin.cpp +++ b/WebCore/platform/win/PopupMenuWin.cpp @@ -123,9 +123,7 @@ void PopupMenu::show(const IntRect& r, FrameView* v, int index) // Determine whether we should animate our popups // Note: Must use 'BOOL' and 'FALSE' instead of 'bool' and 'false' to avoid stack corruption with SystemParametersInfo BOOL shouldAnimate = FALSE; -#ifdef CAN_ANIMATE_TRANSPARENT_WINDOWS_SMOOTHLY ::SystemParametersInfo(SPI_GETCOMBOBOXANIMATION, 0, &shouldAnimate, 0); -#endif if (shouldAnimate) { RECT viewRect = {0}; @@ -598,7 +596,7 @@ static ATOM registerPopup() wcex.cbSize = sizeof(WNDCLASSEX); - wcex.style = 0; + wcex.style = CS_DROPSHADOW; wcex.lpfnWndProc = PopupWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = sizeof(PopupMenu*); // For the PopupMenu pointer diff --git a/WebCore/platform/win/ScrollbarThemeWin.cpp b/WebCore/platform/win/ScrollbarThemeWin.cpp index e13d893..2ee3512 100644 --- a/WebCore/platform/win/ScrollbarThemeWin.cpp +++ b/WebCore/platform/win/ScrollbarThemeWin.cpp @@ -30,6 +30,7 @@ #include "PlatformMouseEvent.h" #include "Scrollbar.h" #include "SoftLinking.h" +#include "SystemInfo.h" // Generic state constants #define TS_NORMAL 1 @@ -61,7 +62,6 @@ using namespace std; namespace WebCore { static HANDLE scrollbarTheme; -static bool haveTheme; static bool runningVista; // FIXME: Refactor the soft-linking code so that it can be shared with RenderThemeWin @@ -72,27 +72,17 @@ SOFT_LINK(uxtheme, DrawThemeBackground, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc SOFT_LINK(uxtheme, IsThemeActive, BOOL, WINAPI, (), ()) SOFT_LINK(uxtheme, IsThemeBackgroundPartiallyTransparent, BOOL, WINAPI, (HANDLE hTheme, int iPartId, int iStateId), (hTheme, iPartId, iStateId)) -static bool isRunningOnVistaOrLater() -{ - static bool os = false; - static bool initialized = false; - if (!initialized) { - OSVERSIONINFOEX vi = {sizeof(vi), 0}; - GetVersionEx((OSVERSIONINFO*)&vi); - - // NOTE: This does not work under a debugger - Vista shims Visual Studio, - // making it believe it is xpsp2, which is inherited by debugged applications - os = vi.dwMajorVersion >= 6; - initialized = true; - } - return os; -} +// Constants used to figure the drag rect outside which we should snap the +// scrollbar thumb back to its origin. These calculations are based on +// observing the behavior of the MSVC8 main window scrollbar + some +// guessing/extrapolation. +static const int kOffEndMultiplier = 3; +static const int kOffSideMultiplier = 8; static void checkAndInitScrollbarTheme() { - if (uxthemeLibrary() && !scrollbarTheme) + if (uxthemeLibrary() && !scrollbarTheme && IsThemeActive()) scrollbarTheme = OpenThemeData(0, L"Scrollbar"); - haveTheme = scrollbarTheme && IsThemeActive(); } #if !USE(SAFARI_THEME) @@ -127,8 +117,11 @@ int ScrollbarThemeWin::scrollbarThickness(ScrollbarControlSize) void ScrollbarThemeWin::themeChanged() { - if (haveTheme) - CloseThemeData(scrollbarTheme); + if (!scrollbarTheme) + return; + + CloseThemeData(scrollbarTheme); + scrollbarTheme = 0; } bool ScrollbarThemeWin::invalidateOnMouseEnterExit() @@ -194,6 +187,29 @@ IntRect ScrollbarThemeWin::trackRect(Scrollbar* scrollbar, bool) return IntRect(scrollbar->x(), scrollbar->y() + thickness, thickness, scrollbar->height() - 2 * thickness); } +bool ScrollbarThemeWin::shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent& evt) +{ + return evt.shiftKey() && evt.button() == LeftButton; +} + +bool ScrollbarThemeWin::shouldSnapBackToDragOrigin(Scrollbar* scrollbar, const PlatformMouseEvent& evt) +{ + // Find the rect within which we shouldn't snap, by expanding the track rect + // in both dimensions. + IntRect rect = trackRect(scrollbar); + const bool horz = scrollbar->orientation() == HorizontalScrollbar; + const int thickness = scrollbarThickness(scrollbar->controlSize()); + rect.inflateX((horz ? kOffEndMultiplier : kOffSideMultiplier) * thickness); + rect.inflateY((horz ? kOffSideMultiplier : kOffEndMultiplier) * thickness); + + // Convert the event to local coordinates. + IntPoint mousePosition = scrollbar->convertFromContainingWindow(evt.pos()); + mousePosition.move(scrollbar->x(), scrollbar->y()); + + // We should snap iff the event is outside our calculated rect. + return !rect.contains(mousePosition); +} + void ScrollbarThemeWin::paintTrackBackground(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect) { // Just assume a forward track part. We only paint the track as a single piece when there is no thumb. @@ -354,10 +370,5 @@ void ScrollbarThemeWin::paintThumb(GraphicsContext* context, Scrollbar* scrollba context->releaseWindowsContext(hdc, rect, alphaBlend); } -bool ScrollbarThemeWin::shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent& evt) -{ - return evt.shiftKey() && evt.button() == LeftButton; -} - } diff --git a/WebCore/platform/win/ScrollbarThemeWin.h b/WebCore/platform/win/ScrollbarThemeWin.h index 92e2523..cd2f176 100644 --- a/WebCore/platform/win/ScrollbarThemeWin.h +++ b/WebCore/platform/win/ScrollbarThemeWin.h @@ -50,6 +50,7 @@ protected: virtual IntRect trackRect(Scrollbar*, bool painting = false); virtual bool shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent&); + virtual bool shouldSnapBackToDragOrigin(Scrollbar*, const PlatformMouseEvent&); virtual void paintTrackBackground(GraphicsContext*, Scrollbar*, const IntRect&); virtual void paintTrackPiece(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarPart); diff --git a/WebCore/platform/win/SystemInfo.cpp b/WebCore/platform/win/SystemInfo.cpp new file mode 100644 index 0000000..ba20ddd --- /dev/null +++ b/WebCore/platform/win/SystemInfo.cpp @@ -0,0 +1,50 @@ +/* + * 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. + */ + +#include "config.h" +#include "SystemInfo.h" + +namespace WebCore { + +bool isRunningOnVistaOrLater() +{ + static bool isVistaOrLater; + static bool initialized; + + if (initialized) + return isVistaOrLater; + + initialized = true; + + OSVERSIONINFOEX vi = {0}; + vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&vi)); + + isVistaOrLater = vi.dwMajorVersion >= 6; + + return isVistaOrLater; +} + +} // namespace WebCore diff --git a/WebCore/platform/win/SystemInfo.h b/WebCore/platform/win/SystemInfo.h new file mode 100644 index 0000000..9f2c2a0 --- /dev/null +++ b/WebCore/platform/win/SystemInfo.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 SystemInfo_h +#define SystemInfo_h + +namespace WebCore { + +bool isRunningOnVistaOrLater(); + +} // namespace WebCore + +#endif // SystemInfo_h diff --git a/WebCore/platform/win/WidgetWin.cpp b/WebCore/platform/win/WidgetWin.cpp index 93dbf42..2272027 100644 --- a/WebCore/platform/win/WidgetWin.cpp +++ b/WebCore/platform/win/WidgetWin.cpp @@ -29,10 +29,12 @@ #include "Cursor.h" #include "Document.h" #include "Element.h" -#include "GraphicsContext.h" +#include "FrameView.h" #include "FrameWin.h" +#include "GraphicsContext.h" #include "IntRect.h" -#include "FrameView.h" +#include "Page.h" + #include <winsock2.h> #include <windows.h> @@ -61,17 +63,37 @@ bool ignoreNextSetCursor = false; void Widget::setCursor(const Cursor& cursor) { - // This is set by PluginViewWin so it can ignore set setCursor call made by + // This is set by PluginViewWin so it can ignore the setCursor call made by // EventHandler.cpp. if (ignoreNextSetCursor) { ignoreNextSetCursor = false; return; } - if (HCURSOR c = cursor.impl()->nativeCursor()) { - lastSetCursor = c; - SetCursor(c); + if (!cursor.impl()->nativeCursor()) + return; + + lastSetCursor = cursor.impl()->nativeCursor(); + + ScrollView* view = root(); + if (!view || !view->isFrameView()) { + SetCursor(lastSetCursor); + return; + } + + Frame* frame = static_cast<FrameView*>(view)->frame(); + if (!frame) { + SetCursor(lastSetCursor); + return; + } + + Page* page = frame->page(); + if (!page) { + SetCursor(lastSetCursor); + return; } + + page->chrome()->setCursor(lastSetCursor); } void Widget::paint(GraphicsContext*, const IntRect&) diff --git a/WebCore/platform/wx/KeyboardEventWx.cpp b/WebCore/platform/wx/KeyboardEventWx.cpp index 8be87ac..7f57073 100644 --- a/WebCore/platform/wx/KeyboardEventWx.cpp +++ b/WebCore/platform/wx/KeyboardEventWx.cpp @@ -27,7 +27,6 @@ #include "PlatformKeyboardEvent.h" #include "KeyboardCodes.h" -#include "NotImplemented.h" #include <wx/defs.h> #include <wx/event.h> @@ -163,14 +162,17 @@ static int windowsKeyCodeForKeyEvent(unsigned int keycode) return VK_DECIMAL; // (6E) Decimal key case WXK_DIVIDE: return VK_DIVIDE; // (6F) Divide key - + case WXK_NUMPAD_SEPARATOR: + return VK_SEPARATOR; case WXK_BACK: return VK_BACK; // (08) BACKSPACE key case WXK_TAB: + case WXK_NUMPAD_TAB: return VK_TAB; // (09) TAB key case WXK_CLEAR: return VK_CLEAR; // (0C) CLEAR key + case WXK_NUMPAD_ENTER: case WXK_RETURN: return VK_RETURN; //(0D) Return key case WXK_SHIFT: @@ -204,22 +206,31 @@ static int windowsKeyCodeForKeyEvent(unsigned int keycode) // VK_NONCONVERT (1D) IME nonconvert // VK_ACCEPT (1E) IME accept // VK_MODECHANGE (1F) IME mode change request + case WXK_NUMPAD_SPACE: case WXK_SPACE: return VK_SPACE; // (20) SPACEBAR + case WXK_NUMPAD_PAGEUP: case WXK_PAGEUP: return VK_PRIOR; // (21) PAGE UP key + case WXK_NUMPAD_PAGEDOWN: case WXK_PAGEDOWN: return VK_NEXT; // (22) PAGE DOWN key + case WXK_NUMPAD_END: case WXK_END: return VK_END; // (23) END key + case WXK_NUMPAD_HOME: case WXK_HOME: return VK_HOME; // (24) HOME key + case WXK_NUMPAD_LEFT: case WXK_LEFT: return VK_LEFT; // (25) LEFT ARROW key + case WXK_NUMPAD_UP: case WXK_UP: return VK_UP; // (26) UP ARROW key + case WXK_NUMPAD_RIGHT: case WXK_RIGHT: return VK_RIGHT; // (27) RIGHT ARROW key + case WXK_NUMPAD_DOWN: case WXK_DOWN: return VK_DOWN; // (28) DOWN ARROW key case WXK_SELECT: @@ -228,11 +239,12 @@ static int windowsKeyCodeForKeyEvent(unsigned int keycode) return VK_PRINT; // (2A) PRINT key case WXK_EXECUTE: return VK_EXECUTE;// (2B) EXECUTE key - //dunno on this - //case WXK_PrintScreen: - // return VK_SNAPSHOT; // (2C) PRINT SCREEN key + case WXK_SNAPSHOT: + return VK_SNAPSHOT; // (2C) PRINT SCREEN key + case WXK_NUMPAD_INSERT: case WXK_INSERT: return VK_INSERT; // (2D) INS key + case WXK_NUMPAD_DELETE: case WXK_DELETE: return VK_DELETE; // (2E) DEL key case WXK_HELP: @@ -336,7 +348,15 @@ PlatformKeyboardEvent::PlatformKeyboardEvent(wxKeyEvent& event) if (m_type != Char) m_keyIdentifier = keyIdentifierForWxKeyCode(event.GetKeyCode()); else { - m_text = wxString(event.GetUnicodeKey()); + //ENTER is an editing command processed as a char (only Enter and Tab are) + //unfortunately the unicode key for numpad_enter (370) is NOT what we want here (13) + //The unicode values for normal enter and tab are the same as the ASCII values, thus ok + //Note that I think this a wx bug, as the Character Code is actually 13 when + //numpad_enter is a CHAR event. + if (event.GetKeyCode() == 13 && event.GetUnicodeKey() == wxChar(370)) + m_text = "\r"; + else + m_text = wxString(event.GetUnicodeKey()); m_unmodifiedText = m_text; } m_autoRepeat = false; // FIXME: not correct. diff --git a/WebCore/platform/wx/LoggingWx.cpp b/WebCore/platform/wx/LoggingWx.cpp index 006712c..4d8a437 100644 --- a/WebCore/platform/wx/LoggingWx.cpp +++ b/WebCore/platform/wx/LoggingWx.cpp @@ -26,11 +26,39 @@ #include "config.h" #include "Logging.h" +#include "CString.h" +#include "PlatformString.h" +#include <wtf/Vector.h> + +#include <wx/defs.h> +#include <wx/utils.h> + namespace WebCore { void InitializeLoggingChannelsIfNecessary() { - LogNotYetImplemented.state = WTFLogChannelOn; + static bool haveInitializedLoggingChannels = false; + if (haveInitializedLoggingChannels) + return; + + haveInitializedLoggingChannels = true; + + wxString loggingEnv; + wxGetEnv(wxT("WX_WEBKIT_LOG"), &loggingEnv); + if (loggingEnv == wxEmptyString) + return; + + String wkLoggingEnv = loggingEnv; + Vector<String> logs; + + wkLoggingEnv.split(",", logs); + + for (size_t i = 0; i < logs.size(); ++i) { + WTFLogChannel* channel = getChannelFromName(logs[i]); + + if (channel) + channel->state = WTFLogChannelOn; + } } } diff --git a/WebCore/platform/wx/MouseEventWx.cpp b/WebCore/platform/wx/MouseEventWx.cpp index a02d7ba..4f39598 100644 --- a/WebCore/platform/wx/MouseEventWx.cpp +++ b/WebCore/platform/wx/MouseEventWx.cpp @@ -33,7 +33,7 @@ namespace WebCore { -PlatformMouseEvent::PlatformMouseEvent(const wxMouseEvent& event, const wxPoint& globalPoint) +PlatformMouseEvent::PlatformMouseEvent(const wxMouseEvent& event, const wxPoint& globalPoint, int clickCount) : m_position(event.GetPosition()) , m_globalPosition(globalPoint) , m_shiftKey(event.ShiftDown()) @@ -67,7 +67,7 @@ PlatformMouseEvent::PlatformMouseEvent(const wxMouseEvent& event, const wxPoint& if (m_eventType == MouseEventMoved) m_clickCount = 0; else - m_clickCount = event.ButtonDClick() ? 2 : 1; + m_clickCount = clickCount; m_timestamp = WTF::currentTime(); } diff --git a/WebCore/platform/wx/PopupMenuWx.cpp b/WebCore/platform/wx/PopupMenuWx.cpp index 4563b77..660282c 100644 --- a/WebCore/platform/wx/PopupMenuWx.cpp +++ b/WebCore/platform/wx/PopupMenuWx.cpp @@ -25,7 +25,6 @@ #include "Frame.h" #include "FrameView.h" -#include "NotImplemented.h" #include "PopupMenuClient.h" #include "PlatformString.h" diff --git a/WebCore/platform/wx/RenderThemeWx.cpp b/WebCore/platform/wx/RenderThemeWx.cpp index 9b6dea5..a26416f 100644 --- a/WebCore/platform/wx/RenderThemeWx.cpp +++ b/WebCore/platform/wx/RenderThemeWx.cpp @@ -32,10 +32,10 @@ #include "NotImplemented.h" #include "RenderView.h" -#include "WebKit/wx/WebView.h" +#include <wx/defs.h> +#include <wx/dc.h> #include <wx/dcgraph.h> -#include <wx/defs.h> #include <wx/renderer.h> #include <wx/dcclient.h> #include <wx/scrolwin.h> diff --git a/WebCore/platform/wx/ScrollViewWx.cpp b/WebCore/platform/wx/ScrollViewWx.cpp index 254ac9f..f556894 100644 --- a/WebCore/platform/wx/ScrollViewWx.cpp +++ b/WebCore/platform/wx/ScrollViewWx.cpp @@ -191,12 +191,12 @@ void ScrollView::platformSetScrollPosition(const IntPoint& scrollPoint) if (newScrollOffset.x < 0) newScrollOffset.x = 0; else if (newScrollOffset.x + cRect.width > vRect.width) - newScrollOffset.x = max(0, vRect.width - cRect.width - 1); + newScrollOffset.x = max(0, vRect.width - cRect.width); if (newScrollOffset.y < 0) newScrollOffset.y = 0; else if (newScrollOffset.y + cRect.height > vRect.height) - newScrollOffset.y = max(0, vRect.height - cRect.height - 1); + newScrollOffset.y = max(0, vRect.height - cRect.height); if (newScrollOffset == scrollOffset) return; @@ -291,8 +291,8 @@ void ScrollView::platformSetScrollbarModes() needsAdjust = true; } - if (m_data->vScrollbarMode != horizontalScrollbarMode() ) { - m_data->vScrollbarMode = horizontalScrollbarMode(); + if (m_data->vScrollbarMode != verticalScrollbarMode() ) { + m_data->vScrollbarMode = verticalScrollbarMode(); needsAdjust = true; } diff --git a/WebCore/platform/wx/SharedTimerWx.cpp b/WebCore/platform/wx/SharedTimerWx.cpp index d95457b..b2b22e4 100644 --- a/WebCore/platform/wx/SharedTimerWx.cpp +++ b/WebCore/platform/wx/SharedTimerWx.cpp @@ -26,7 +26,6 @@ #include "config.h" #include "SharedTimer.h" -#include "NotImplemented.h" #include "Widget.h" #include <wtf/Assertions.h> @@ -79,28 +78,10 @@ void setSharedTimerFireTime(double fireTime) wkTimer = new WebKitTimer(); unsigned int intervalInMS = interval * 1000; - if (interval < 0) { -#ifndef NDEBUG - // TODO: We may eventually want to assert here, to track - // what calls are leading to this condition. It seems to happen - // mostly with repeating timers. - fprintf(stderr, "WARNING: setSharedTimerFireTime: fire time is < 0 ms\n"); -#endif - intervalInMS = 0; - } - - // FIXME: We should mimic the Windows port's behavior and add the timer fired - // event to the event queue directly rather than making an artifical delay. - // However, wx won't allow us to assign a simple callback function - we'd have - // to create a fake wxEvtHandler-derived class with a timer event handler - // function. Until there's a better way, this way is at least far less - // hacky. - if (intervalInMS < 10) -#if __WXMSW__ - intervalInMS = 10; -#else + + // sanity check + if (intervalInMS < 1) intervalInMS = 1; -#endif wkTimer->Start(intervalInMS, wxTIMER_ONE_SHOT); } diff --git a/WebCore/platform/wx/TemporaryLinkStubs.cpp b/WebCore/platform/wx/TemporaryLinkStubs.cpp index d8c6046..dfd2ad5 100644 --- a/WebCore/platform/wx/TemporaryLinkStubs.cpp +++ b/WebCore/platform/wx/TemporaryLinkStubs.cpp @@ -97,11 +97,6 @@ DragImageRef Frame::dragImageForSelection() { notImplemented(); return 0; } void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness) { notImplemented(); } -// cookies (we'll need a place to store these -void WebCore::setCookies(Document* document, const KURL& url, const KURL& policyURL, const String& value) { notImplemented(); } -String WebCore::cookies(const Document* document, const KURL& url) { notImplemented(); return String(); } -bool WebCore::cookiesEnabled(const Document* document) { notImplemented(); return false; } - /********************************************************/ /* Completely empty stubs (mostly to allow DRT to run): */ /********************************************************/ diff --git a/WebCore/platform/wx/WidgetWx.cpp b/WebCore/platform/wx/WidgetWx.cpp index 37097fe..bb4fd2a 100644 --- a/WebCore/platform/wx/WidgetWx.cpp +++ b/WebCore/platform/wx/WidgetWx.cpp @@ -45,8 +45,8 @@ Widget::~Widget() void Widget::setFocus() { - if (platformWidget()) - platformWidget()->SetFocus(); + if (PlatformWidget widget = platformWidget()) + widget->SetFocus(); } void Widget::setCursor(const Cursor& cursor) @@ -57,38 +57,43 @@ void Widget::setCursor(const Cursor& cursor) void Widget::show() { - if (platformWidget()) - platformWidget()->Show(); + if (PlatformWidget widget = platformWidget()) + widget->Show(); } void Widget::hide() { - if (platformWidget()) - platformWidget()->Hide(); + if (PlatformWidget widget = platformWidget()) + widget->Hide(); } IntRect Widget::frameRect() const { - if (platformWidget()) - return platformWidget()->GetRect(); + if (PlatformWidget widget = platformWidget()) + return widget->GetRect(); + return m_frame; } void Widget::setFrameRect(const IntRect& rect) { - if (platformWidget()) - platformWidget()->SetSize(rect); + if (PlatformWidget widget = platformWidget()) + widget->SetSize(rect); + m_frame = rect; } void Widget::invalidateRect(const IntRect& r) { - if (platformWidget()) - platformWidget()->RefreshRect(r); + if (PlatformWidget widget = platformWidget()) + widget->RefreshRect(r); } void Widget::paint(GraphicsContext*,const IntRect& r) { + invalidateRect(r); + if (PlatformWidget widget = platformWidget()) + widget->Update(); } } diff --git a/WebCore/platform/wx/wxcode/mac/carbon/fontprops.cpp b/WebCore/platform/wx/wxcode/mac/carbon/fontprops.cpp index 447a3d0..653f142 100644 --- a/WebCore/platform/wx/wxcode/mac/carbon/fontprops.cpp +++ b/WebCore/platform/wx/wxcode/mac/carbon/fontprops.cpp @@ -23,11 +23,17 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" +#include "fontprops.h" + #include <ApplicationServices/ApplicationServices.h> #include <wx/defs.h> #include <wx/gdicmn.h> -#include "fontprops.h" + +#ifdef BUILDING_ON_TIGER +void (*wkGetFontMetrics)(CGFontRef, int* ascent, int* descent, int* lineGap, unsigned* unitsPerEm); +#endif const float smallCapsFontSizeMultiplier = 0.7f; const float contextDPI = 72.0f; @@ -39,7 +45,7 @@ m_ascent(0), m_descent(0), m_lineGap(0), m_lineSpacing(0), m_xHeight(0) CGFontRef cgFont; #ifdef wxOSX_USE_CORE_TEXT && wxOSX_USE_CORE_TEXT - cgFont = CTFontCopyGraphicsFont((CTFontRef)font->MacGetCTFont(), NULL); + cgFont = CTFontCopyGraphicsFont((CTFontRef)font->OSXGetCTFont(), NULL); #else ATSFontRef fontRef; @@ -53,7 +59,7 @@ m_ascent(0), m_descent(0), m_lineGap(0), m_lineSpacing(0), m_xHeight(0) int iAscent; int iDescent; int iLineGap; - float unitsPerEm; + unsigned unitsPerEm; #ifdef BUILDING_ON_TIGER wkGetFontMetrics(cgFont, &iAscent, &iDescent, &iLineGap, &unitsPerEm); #else @@ -76,6 +82,9 @@ m_ascent(0), m_descent(0), m_lineGap(0), m_lineSpacing(0), m_xHeight(0) m_lineSpacing = m_ascent + m_descent + m_lineGap; } + + if (cgFont) + CGFontRelease(cgFont); } 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 6eaa765..e5c60d6 100644 --- a/WebCore/platform/wx/wxcode/mac/carbon/non-kerned-drawing.cpp +++ b/WebCore/platform/wx/wxcode/mac/carbon/non-kerned-drawing.cpp @@ -24,44 +24,95 @@ */ #include "config.h" +#include "FloatSize.h" #include "GlyphBuffer.h" #include "GraphicsContext.h" #include "SimpleFontData.h" +#include <wtf/Vector.h> + +#include <ApplicationServices/ApplicationServices.h> + +#include <dlfcn.h> #include <wx/defs.h> #include <wx/dcclient.h> #include <wx/dcgraph.h> #include <wx/gdicmn.h> -#include <vector> + + +// Unfortunately we need access to a private function to get the character -> glyph conversion needed to +// allow us to use CGContextShowGlyphsWithAdvances +// Note that on < 10.5, the function is called CGFontGetGlyphsForUnicodes, so we need to detect and deal +// with this. +typedef void (*CGFontGetGlyphsForUnicharsPtr)(CGFontRef, const UniChar[], const CGGlyph[], size_t); +static CGFontGetGlyphsForUnicharsPtr CGFontGetGlyphsForUnichars = (CGFontGetGlyphsForUnicharsPtr)dlsym(RTLD_DEFAULT, "CGFontGetGlyphsForUnichars"); namespace WebCore { void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) { -#if USE(WXGC) + graphicsContext->save(); + wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext()); + + wxFont* wxfont = font->getWxFont(); + graphicsContext->setFillColor(graphicsContext->fillColor()); + + CGContextRef cgContext = static_cast<CGContextRef>(dc->GetGraphicsContext()->GetNativeContext()); + + CGFontRef cgFont; + +#ifdef wxOSX_USE_CORE_TEXT && wxOSX_USE_CORE_TEXT + cgFont = CTFontCopyGraphicsFont((CTFontRef)font->OSXGetCTFont(), NULL); #else - wxDC* dc = graphicsContext->platformContext(); + ATSFontRef fontRef; + + fontRef = FMGetATSFontRefFromFont(wxfont->MacGetATSUFontID()); + + if (fontRef) + cgFont = CGFontCreateWithPlatformFont((void*)&fontRef); #endif + + CGContextSetFont(cgContext, cgFont); - wxFont* wxfont = font->getWxFont(); - if (wxfont->IsOk()) - dc->SetFont(*wxfont); - dc->SetTextForeground(color); - - // convert glyphs to wxString - GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from)); - int offset = point.x(); - wxString text = wxEmptyString; - for (unsigned i = 0; i < numGlyphs; i++) { - text = text.Append((wxChar)glyphs[i]); - offset += glyphBuffer.advanceAt(from + i); + CGContextSetFontSize(cgContext, wxfont->GetPointSize()); + + CGFloat red, green, blue, alpha; + graphicsContext->fillColor().getRGBA(red, green, blue, alpha); + CGContextSetRGBFillColor(cgContext, red, green, blue, alpha); + + CGAffineTransform matrix = CGAffineTransformIdentity; + matrix.b = -matrix.b; + matrix.d = -matrix.d; + + CGContextSetTextMatrix(cgContext, matrix); + + CGContextSetTextPosition(cgContext, point.x(), point.y()); + + const FloatSize* advanceSizes = static_cast<const FloatSize*>(glyphBuffer.advances(from)); + int size = glyphBuffer.size() - from; + CGSize sizes[size]; + CGGlyph glyphs[numGlyphs]; + + // if the function doesn't exist, we're probably on tiger and need to grab the + // function under its old name, CGFontGetGlyphsForUnicodes + if (!CGFontGetGlyphsForUnichars) + CGFontGetGlyphsForUnichars = (CGFontGetGlyphsForUnicharsPtr)dlsym(RTLD_DEFAULT, "CGFontGetGlyphsForUnicodes"); + + // Let's make sure we got the function under one name or another! + ASSERT(CGFontGetGlyphsForUnichars); + CGFontGetGlyphsForUnichars(cgFont, glyphBuffer.glyphs(from), glyphs, numGlyphs); + + for (int i = 0; i < size; i++) { + FloatSize fsize = advanceSizes[i]; + sizes[i] = CGSizeMake(fsize.width(), fsize.height()); } - // NOTE: The wx API actually adds the ascent to the y value internally, - // so we have to subtract it from the y point here so that the ascent - // isn't added twice. - dc->DrawText(text, (wxCoord)point.x(), int(point.y() - font->ascent())); + CGContextShowGlyphsWithAdvances(cgContext, glyphs, sizes, numGlyphs); + + if (cgFont) + CGFontRelease(cgFont); + graphicsContext->restore(); } } diff --git a/WebCore/platform/wx/wxcode/win/fontprops.cpp b/WebCore/platform/wx/wxcode/win/fontprops.cpp index 1314691..531db08 100644 --- a/WebCore/platform/wx/wxcode/win/fontprops.cpp +++ b/WebCore/platform/wx/wxcode/win/fontprops.cpp @@ -91,7 +91,7 @@ void GetTextExtent( const wxFont& font, const wxString& str, wxCoord *width, wxC // accounts for under/overhang of the first/last character while we want // just the bounding rect for this string so adjust the width as needed // (using API not available in 2002 SDKs of WinCE) - if ( len > 0 ) + if ( len > 1 ) { ABC width; const wxChar chFirst = *str.begin(); diff --git a/WebCore/platform/wx/wxcode/win/non-kerned-drawing.cpp b/WebCore/platform/wx/wxcode/win/non-kerned-drawing.cpp index 7d1e924..d2513d7 100644 --- a/WebCore/platform/wx/wxcode/win/non-kerned-drawing.cpp +++ b/WebCore/platform/wx/wxcode/win/non-kerned-drawing.cpp @@ -30,6 +30,7 @@ #include <wx/defs.h> #include <wx/dcclient.h> +#include <wx/dcgraph.h> #include <wx/gdicmn.h> #include <vector> |