diff options
Diffstat (limited to 'Source/WebCore/platform')
342 files changed, 9745 insertions, 3146 deletions
diff --git a/Source/WebCore/platform/AsyncFileSystem.h b/Source/WebCore/platform/AsyncFileSystem.h index f5207ce..3570de4 100644 --- a/Source/WebCore/platform/AsyncFileSystem.h +++ b/Source/WebCore/platform/AsyncFileSystem.h @@ -53,6 +53,7 @@ public: enum Type { Temporary, Persistent, + External, }; virtual void stop() { } diff --git a/Source/WebCore/platform/ContentType.cpp b/Source/WebCore/platform/ContentType.cpp index c094d54..b02bc7c 100644 --- a/Source/WebCore/platform/ContentType.cpp +++ b/Source/WebCore/platform/ContentType.cpp @@ -45,11 +45,17 @@ String ContentType::parameter(const String& parameterName) const if (semi != notFound) { size_t start = strippedType.find(parameterName, semi + 1, false); if (start != notFound) { - start = strippedType.find('=', start + 6); + start = strippedType.find('=', start + parameterName.length()); if (start != notFound) { - size_t end = strippedType.find(';', start + 6); - if (end == notFound) - end = strippedType.length(); + size_t quote = strippedType.find('\"', start + 1); + size_t end = strippedType.find('\"', start + 2); + if (quote != notFound && end != notFound) + start = quote; + else { + end = strippedType.find(';', start + 1); + if (end == notFound) + end = strippedType.length(); + } parameterValue = strippedType.substring(start + 1, end - (start + 1)).stripWhiteSpace(); } } diff --git a/Source/WebCore/platform/DefaultLocalizationStrategy.cpp b/Source/WebCore/platform/DefaultLocalizationStrategy.cpp index 1a50c3c..0a7dd42 100644 --- a/Source/WebCore/platform/DefaultLocalizationStrategy.cpp +++ b/Source/WebCore/platform/DefaultLocalizationStrategy.cpp @@ -74,44 +74,44 @@ DefaultLocalizationStrategy::DefaultLocalizationStrategy() String DefaultLocalizationStrategy::inputElementAltText() { - return UI_STRING_KEY("Submit", "Submit (input element)", "alt text for <input> elements with no alt, title, or value"); + return WEB_UI_STRING_KEY("Submit", "Submit (input element)", "alt text for <input> elements with no alt, title, or value"); } String DefaultLocalizationStrategy::resetButtonDefaultLabel() { - return UI_STRING("Reset", "default label for Reset buttons in forms on web pages"); + return WEB_UI_STRING("Reset", "default label for Reset buttons in forms on web pages"); } String DefaultLocalizationStrategy::searchableIndexIntroduction() { - return UI_STRING("This is a searchable index. Enter search keywords: ", + return WEB_UI_STRING("This is a searchable index. Enter search keywords: ", "text that appears at the start of nearly-obsolete web pages in the form of a 'searchable index'"); } String DefaultLocalizationStrategy::submitButtonDefaultLabel() { - return UI_STRING("Submit", "default label for Submit buttons in forms on web pages"); + return WEB_UI_STRING("Submit", "default label for Submit buttons in forms on web pages"); } String DefaultLocalizationStrategy::fileButtonChooseFileLabel() { - return UI_STRING("Choose File", "title for file button used in HTML forms"); + return WEB_UI_STRING("Choose File", "title for file button used in HTML forms"); } String DefaultLocalizationStrategy::fileButtonNoFileSelectedLabel() { - return UI_STRING("no file selected", "text to display in file button used in HTML forms when no file is selected"); + return WEB_UI_STRING("no file selected", "text to display in file button used in HTML forms when no file is selected"); } String DefaultLocalizationStrategy::defaultDetailsSummaryText() { - return UI_STRING("Details", "text to display in <details> tag when it has no <summary> child"); + return WEB_UI_STRING("Details", "text to display in <details> tag when it has no <summary> child"); } #if PLATFORM(MAC) String DefaultLocalizationStrategy::copyImageUnknownFileLabel() { - return UI_STRING("unknown", "Unknown filename"); + return WEB_UI_STRING("unknown", "Unknown filename"); } #endif @@ -119,129 +119,129 @@ String DefaultLocalizationStrategy::copyImageUnknownFileLabel() String DefaultLocalizationStrategy::contextMenuItemTagOpenLinkInNewWindow() { - return UI_STRING("Open Link in New Window", "Open in New Window context menu item"); + return WEB_UI_STRING("Open Link in New Window", "Open in New Window context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagDownloadLinkToDisk() { - return UI_STRING("Download Linked File", "Download Linked File context menu item"); + return WEB_UI_STRING("Download Linked File", "Download Linked File context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagCopyLinkToClipboard() { - return UI_STRING("Copy Link", "Copy Link context menu item"); + return WEB_UI_STRING("Copy Link", "Copy Link context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagOpenImageInNewWindow() { - return UI_STRING("Open Image in New Window", "Open Image in New Window context menu item"); + return WEB_UI_STRING("Open Image in New Window", "Open Image in New Window context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagDownloadImageToDisk() { - return UI_STRING("Download Image", "Download Image context menu item"); + return WEB_UI_STRING("Download Image", "Download Image context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagCopyImageToClipboard() { - return UI_STRING("Copy Image", "Copy Image context menu item"); + return WEB_UI_STRING("Copy Image", "Copy Image context menu item"); } #if PLATFORM(QT) String DefaultLocalizationStrategy::contextMenuItemTagCopyImageUrlToClipboard() { - return UI_STRING("Copy Image Address", "Copy Image Address menu item"); + return WEB_UI_STRING("Copy Image Address", "Copy Image Address menu item"); } #endif String DefaultLocalizationStrategy::contextMenuItemTagOpenVideoInNewWindow() { - return UI_STRING("Open Video in New Window", "Open Video in New Window context menu item"); + return WEB_UI_STRING("Open Video in New Window", "Open Video in New Window context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagOpenAudioInNewWindow() { - return UI_STRING("Open Audio in New Window", "Open Audio in New Window context menu item"); + return WEB_UI_STRING("Open Audio in New Window", "Open Audio in New Window context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagCopyVideoLinkToClipboard() { - return UI_STRING("Copy Video Address", "Copy Video Address Location context menu item"); + return WEB_UI_STRING("Copy Video Address", "Copy Video Address Location context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagCopyAudioLinkToClipboard() { - return UI_STRING("Copy Audio Address", "Copy Audio Address Location context menu item"); + return WEB_UI_STRING("Copy Audio Address", "Copy Audio Address Location context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagToggleMediaControls() { - return UI_STRING("Controls", "Media Controls context menu item"); + return WEB_UI_STRING("Controls", "Media Controls context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagToggleMediaLoop() { - return UI_STRING("Loop", "Media Loop context menu item"); + return WEB_UI_STRING("Loop", "Media Loop context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagEnterVideoFullscreen() { - return UI_STRING("Enter Fullscreen", "Video Enter Fullscreen context menu item"); + return WEB_UI_STRING("Enter Fullscreen", "Video Enter Fullscreen context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagMediaPlay() { - return UI_STRING("Play", "Media Play context menu item"); + return WEB_UI_STRING("Play", "Media Play context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagMediaPause() { - return UI_STRING("Pause", "Media Pause context menu item"); + return WEB_UI_STRING("Pause", "Media Pause context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagMediaMute() { - return UI_STRING("Mute", "Media Mute context menu item"); + return WEB_UI_STRING("Mute", "Media Mute context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagOpenFrameInNewWindow() { - return UI_STRING("Open Frame in New Window", "Open Frame in New Window context menu item"); + return WEB_UI_STRING("Open Frame in New Window", "Open Frame in New Window context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagCopy() { - return UI_STRING("Copy", "Copy context menu item"); + return WEB_UI_STRING("Copy", "Copy context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagGoBack() { - return UI_STRING("Back", "Back context menu item"); + return WEB_UI_STRING("Back", "Back context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagGoForward() { - return UI_STRING("Forward", "Forward context menu item"); + return WEB_UI_STRING("Forward", "Forward context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagStop() { - return UI_STRING("Stop", "Stop context menu item"); + return WEB_UI_STRING("Stop", "Stop context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagReload() { - return UI_STRING("Reload", "Reload context menu item"); + return WEB_UI_STRING("Reload", "Reload context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagCut() { - return UI_STRING("Cut", "Cut context menu item"); + return WEB_UI_STRING("Cut", "Cut context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagPaste() { - return UI_STRING("Paste", "Paste context menu item"); + return WEB_UI_STRING("Paste", "Paste context menu item"); } #if PLATFORM(GTK) @@ -278,218 +278,223 @@ String DefaultLocalizationStrategy::contextMenuItemTagSelectAll() String DefaultLocalizationStrategy::contextMenuItemTagNoGuessesFound() { - return UI_STRING("No Guesses Found", "No Guesses Found context menu item"); + return WEB_UI_STRING("No Guesses Found", "No Guesses Found context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagIgnoreSpelling() { - return UI_STRING("Ignore Spelling", "Ignore Spelling context menu item"); + return WEB_UI_STRING("Ignore Spelling", "Ignore Spelling context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagLearnSpelling() { - return UI_STRING("Learn Spelling", "Learn Spelling context menu item"); + return WEB_UI_STRING("Learn Spelling", "Learn Spelling context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagSearchWeb() { - return UI_STRING("Search in Google", "Search in Google context menu item"); + return WEB_UI_STRING("Search in Google", "Search in Google context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagLookUpInDictionary(const String& selectedString) { #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) || defined(BUILDING_ON_SNOW_LEOPARD) UNUSED_PARAM(selectedString); - return UI_STRING("Look Up in Dictionary", "Look Up in Dictionary context menu item"); + return WEB_UI_STRING("Look Up in Dictionary", "Look Up in Dictionary context menu item"); #else - return UI_STRING("Look Up “<selection>”", "Look Up context menu item with selected word").replace("<selection>", selectedString); +#if USE(CF) + RetainPtr<CFStringRef> selectedCFString(AdoptCF, selectedString.createCFString()); + return formatLocalizedString(WEB_UI_STRING("Look Up “%@”", "Look Up context menu item with selected word"), selectedCFString.get()); +#else + return WEB_UI_STRING("Look Up “<selection>”", "Look Up context menu item with selected word").replace("<selection>", selectedString); +#endif #endif } String DefaultLocalizationStrategy::contextMenuItemTagOpenLink() { - return UI_STRING("Open Link", "Open Link context menu item"); + return WEB_UI_STRING("Open Link", "Open Link context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagIgnoreGrammar() { - return UI_STRING("Ignore Grammar", "Ignore Grammar context menu item"); + return WEB_UI_STRING("Ignore Grammar", "Ignore Grammar context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagSpellingMenu() { - return UI_STRING("Spelling and Grammar", "Spelling and Grammar context sub-menu item"); + return WEB_UI_STRING("Spelling and Grammar", "Spelling and Grammar context sub-menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagShowSpellingPanel(bool show) { if (show) - return UI_STRING("Show Spelling and Grammar", "menu item title"); - return UI_STRING("Hide Spelling and Grammar", "menu item title"); + return WEB_UI_STRING("Show Spelling and Grammar", "menu item title"); + return WEB_UI_STRING("Hide Spelling and Grammar", "menu item title"); } String DefaultLocalizationStrategy::contextMenuItemTagCheckSpelling() { - return UI_STRING("Check Document Now", "Check spelling context menu item"); + return WEB_UI_STRING("Check Document Now", "Check spelling context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagCheckSpellingWhileTyping() { - return UI_STRING("Check Spelling While Typing", "Check spelling while typing context menu item"); + return WEB_UI_STRING("Check Spelling While Typing", "Check spelling while typing context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagCheckGrammarWithSpelling() { - return UI_STRING("Check Grammar With Spelling", "Check grammar with spelling context menu item"); + return WEB_UI_STRING("Check Grammar With Spelling", "Check grammar with spelling context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagFontMenu() { - return UI_STRING("Font", "Font context sub-menu item"); + return WEB_UI_STRING("Font", "Font context sub-menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagBold() { - return UI_STRING("Bold", "Bold context menu item"); + return WEB_UI_STRING("Bold", "Bold context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagItalic() { - return UI_STRING("Italic", "Italic context menu item"); + return WEB_UI_STRING("Italic", "Italic context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagUnderline() { - return UI_STRING("Underline", "Underline context menu item"); + return WEB_UI_STRING("Underline", "Underline context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagOutline() { - return UI_STRING("Outline", "Outline context menu item"); + return WEB_UI_STRING("Outline", "Outline context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagWritingDirectionMenu() { - return UI_STRING("Paragraph Direction", "Paragraph direction context sub-menu item"); + return WEB_UI_STRING("Paragraph Direction", "Paragraph direction context sub-menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagTextDirectionMenu() { - return UI_STRING("Selection Direction", "Selection direction context sub-menu item"); + return WEB_UI_STRING("Selection Direction", "Selection direction context sub-menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagDefaultDirection() { - return UI_STRING("Default", "Default writing direction context menu item"); + return WEB_UI_STRING("Default", "Default writing direction context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagLeftToRight() { - return UI_STRING("Left to Right", "Left to Right context menu item"); + return WEB_UI_STRING("Left to Right", "Left to Right context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagRightToLeft() { - return UI_STRING("Right to Left", "Right to Left context menu item"); + return WEB_UI_STRING("Right to Left", "Right to Left context menu item"); } #if PLATFORM(MAC) String DefaultLocalizationStrategy::contextMenuItemTagSearchInSpotlight() { - return UI_STRING("Search in Spotlight", "Search in Spotlight context menu item"); + return WEB_UI_STRING("Search in Spotlight", "Search in Spotlight context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagShowFonts() { - return UI_STRING("Show Fonts", "Show fonts context menu item"); + return WEB_UI_STRING("Show Fonts", "Show fonts context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagStyles() { - return UI_STRING("Styles...", "Styles context menu item"); + return WEB_UI_STRING("Styles...", "Styles context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagShowColors() { - return UI_STRING("Show Colors", "Show colors context menu item"); + return WEB_UI_STRING("Show Colors", "Show colors context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagSpeechMenu() { - return UI_STRING("Speech", "Speech context sub-menu item"); + return WEB_UI_STRING("Speech", "Speech context sub-menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagStartSpeaking() { - return UI_STRING("Start Speaking", "Start speaking context menu item"); + return WEB_UI_STRING("Start Speaking", "Start speaking context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagStopSpeaking() { - return UI_STRING("Stop Speaking", "Stop speaking context menu item"); + return WEB_UI_STRING("Stop Speaking", "Stop speaking context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagCorrectSpellingAutomatically() { - return UI_STRING("Correct Spelling Automatically", "Correct Spelling Automatically context menu item"); + return WEB_UI_STRING("Correct Spelling Automatically", "Correct Spelling Automatically context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagSubstitutionsMenu() { - return UI_STRING("Substitutions", "Substitutions context sub-menu item"); + return WEB_UI_STRING("Substitutions", "Substitutions context sub-menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagShowSubstitutions(bool show) { if (show) - return UI_STRING("Show Substitutions", "menu item title"); - return UI_STRING("Hide Substitutions", "menu item title"); + return WEB_UI_STRING("Show Substitutions", "menu item title"); + return WEB_UI_STRING("Hide Substitutions", "menu item title"); } String DefaultLocalizationStrategy::contextMenuItemTagSmartCopyPaste() { - return UI_STRING("Smart Copy/Paste", "Smart Copy/Paste context menu item"); + return WEB_UI_STRING("Smart Copy/Paste", "Smart Copy/Paste context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagSmartQuotes() { - return UI_STRING("Smart Quotes", "Smart Quotes context menu item"); + return WEB_UI_STRING("Smart Quotes", "Smart Quotes context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagSmartDashes() { - return UI_STRING("Smart Dashes", "Smart Dashes context menu item"); + return WEB_UI_STRING("Smart Dashes", "Smart Dashes context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagSmartLinks() { - return UI_STRING("Smart Links", "Smart Links context menu item"); + return WEB_UI_STRING("Smart Links", "Smart Links context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagTextReplacement() { - return UI_STRING("Text Replacement", "Text Replacement context menu item"); + return WEB_UI_STRING("Text Replacement", "Text Replacement context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagTransformationsMenu() { - return UI_STRING("Transformations", "Transformations context sub-menu item"); + return WEB_UI_STRING("Transformations", "Transformations context sub-menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagMakeUpperCase() { - return UI_STRING("Make Upper Case", "Make Upper Case context menu item"); + return WEB_UI_STRING("Make Upper Case", "Make Upper Case context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagMakeLowerCase() { - return UI_STRING("Make Lower Case", "Make Lower Case context menu item"); + return WEB_UI_STRING("Make Lower Case", "Make Lower Case context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagCapitalize() { - return UI_STRING("Capitalize", "Capitalize context menu item"); + return WEB_UI_STRING("Capitalize", "Capitalize context menu item"); } String DefaultLocalizationStrategy::contextMenuItemTagChangeBack(const String& replacedString) @@ -502,133 +507,133 @@ String DefaultLocalizationStrategy::contextMenuItemTagChangeBack(const String& r String DefaultLocalizationStrategy::contextMenuItemTagInspectElement() { - return UI_STRING("Inspect Element", "Inspect Element context menu item"); + return WEB_UI_STRING("Inspect Element", "Inspect Element context menu item"); } #endif // ENABLE(CONTEXT_MENUS) String DefaultLocalizationStrategy::searchMenuNoRecentSearchesText() { - return UI_STRING("No recent searches", "Label for only item in menu that appears when clicking on the search field image, when no searches have been performed"); + return WEB_UI_STRING("No recent searches", "Label for only item in menu that appears when clicking on the search field image, when no searches have been performed"); } String DefaultLocalizationStrategy::searchMenuRecentSearchesText() { - return UI_STRING("Recent Searches", "label for first item in the menu that appears when clicking on the search field image, used as embedded menu title"); + return WEB_UI_STRING("Recent Searches", "label for first item in the menu that appears when clicking on the search field image, used as embedded menu title"); } String DefaultLocalizationStrategy::searchMenuClearRecentSearchesText() { - return UI_STRING("Clear Recent Searches", "menu item in Recent Searches menu that empties menu's contents"); + return WEB_UI_STRING("Clear Recent Searches", "menu item in Recent Searches menu that empties menu's contents"); } String DefaultLocalizationStrategy::AXWebAreaText() { - return UI_STRING("HTML content", "accessibility role description for web area"); + return WEB_UI_STRING("HTML content", "accessibility role description for web area"); } String DefaultLocalizationStrategy::AXLinkText() { - return UI_STRING("link", "accessibility role description for link"); + return WEB_UI_STRING("link", "accessibility role description for link"); } String DefaultLocalizationStrategy::AXListMarkerText() { - return UI_STRING("list marker", "accessibility role description for list marker"); + return WEB_UI_STRING("list marker", "accessibility role description for list marker"); } String DefaultLocalizationStrategy::AXImageMapText() { - return UI_STRING("image map", "accessibility role description for image map"); + return WEB_UI_STRING("image map", "accessibility role description for image map"); } String DefaultLocalizationStrategy::AXHeadingText() { - return UI_STRING("heading", "accessibility role description for headings"); + return WEB_UI_STRING("heading", "accessibility role description for headings"); } String DefaultLocalizationStrategy::AXDefinitionListTermText() { - return UI_STRING("term", "term word of a definition"); + return WEB_UI_STRING("term", "term word of a definition"); } String DefaultLocalizationStrategy::AXDefinitionListDefinitionText() { - return UI_STRING("definition", "definition phrase"); + return WEB_UI_STRING("definition", "definition phrase"); } #if PLATFORM(MAC) String DefaultLocalizationStrategy::AXARIAContentGroupText(const String& ariaType) { if (ariaType == "ARIAApplicationAlert") - return UI_STRING("alert", "An ARIA accessibility group that acts as an alert."); + return WEB_UI_STRING("alert", "An ARIA accessibility group that acts as an alert."); if (ariaType == "ARIAApplicationAlertDialog") - return UI_STRING("alert dialog", "An ARIA accessibility group that acts as an alert dialog."); + return WEB_UI_STRING("alert dialog", "An ARIA accessibility group that acts as an alert dialog."); if (ariaType == "ARIAApplicationDialog") - return UI_STRING("dialog", "An ARIA accessibility group that acts as an dialog."); + return WEB_UI_STRING("dialog", "An ARIA accessibility group that acts as an dialog."); if (ariaType == "ARIAApplicationLog") - return UI_STRING("log", "An ARIA accessibility group that acts as a console log."); + return WEB_UI_STRING("log", "An ARIA accessibility group that acts as a console log."); if (ariaType == "ARIAApplicationMarquee") - return UI_STRING("marquee", "An ARIA accessibility group that acts as a marquee."); + return WEB_UI_STRING("marquee", "An ARIA accessibility group that acts as a marquee."); if (ariaType == "ARIAApplicationStatus") - return UI_STRING("application status", "An ARIA accessibility group that acts as a status update."); + return WEB_UI_STRING("application status", "An ARIA accessibility group that acts as a status update."); if (ariaType == "ARIAApplicationTimer") - return UI_STRING("timer", "An ARIA accessibility group that acts as an updating timer."); + return WEB_UI_STRING("timer", "An ARIA accessibility group that acts as an updating timer."); if (ariaType == "ARIADocument") - return UI_STRING("document", "An ARIA accessibility group that acts as a document."); + return WEB_UI_STRING("document", "An ARIA accessibility group that acts as a document."); if (ariaType == "ARIADocumentArticle") - return UI_STRING("article", "An ARIA accessibility group that acts as an article."); + return WEB_UI_STRING("article", "An ARIA accessibility group that acts as an article."); if (ariaType == "ARIADocumentNote") - return UI_STRING("note", "An ARIA accessibility group that acts as a note in a document."); + return WEB_UI_STRING("note", "An ARIA accessibility group that acts as a note in a document."); if (ariaType == "ARIADocumentRegion") - return UI_STRING("region", "An ARIA accessibility group that acts as a distinct region in a document."); + return WEB_UI_STRING("region", "An ARIA accessibility group that acts as a distinct region in a document."); if (ariaType == "ARIALandmarkApplication") - return UI_STRING("application", "An ARIA accessibility group that acts as an application."); + return WEB_UI_STRING("application", "An ARIA accessibility group that acts as an application."); if (ariaType == "ARIALandmarkBanner") - return UI_STRING("banner", "An ARIA accessibility group that acts as a banner."); + return WEB_UI_STRING("banner", "An ARIA accessibility group that acts as a banner."); if (ariaType == "ARIALandmarkComplementary") - return UI_STRING("complementary", "An ARIA accessibility group that acts as a region of complementary information."); + return WEB_UI_STRING("complementary", "An ARIA accessibility group that acts as a region of complementary information."); if (ariaType == "ARIALandmarkContentInfo") - return UI_STRING("content", "An ARIA accessibility group that contains content."); + return WEB_UI_STRING("content", "An ARIA accessibility group that contains content."); if (ariaType == "ARIALandmarkMain") - return UI_STRING("main", "An ARIA accessibility group that is the main portion of the website."); + return WEB_UI_STRING("main", "An ARIA accessibility group that is the main portion of the website."); if (ariaType == "ARIALandmarkNavigation") - return UI_STRING("navigation", "An ARIA accessibility group that contains the main navigation elements of a website."); + return WEB_UI_STRING("navigation", "An ARIA accessibility group that contains the main navigation elements of a website."); if (ariaType == "ARIALandmarkSearch") - return UI_STRING("search", "An ARIA accessibility group that contains a search feature of a website."); + return WEB_UI_STRING("search", "An ARIA accessibility group that contains a search feature of a website."); if (ariaType == "ARIAUserInterfaceTooltip") - return UI_STRING("tooltip", "An ARIA accessibility group that acts as a tooltip."); + return WEB_UI_STRING("tooltip", "An ARIA accessibility group that acts as a tooltip."); if (ariaType == "ARIATabPanel") - return UI_STRING("tab panel", "An ARIA accessibility group that contains the content of a tab."); + return WEB_UI_STRING("tab panel", "An ARIA accessibility group that contains the content of a tab."); if (ariaType == "ARIADocumentMath") - return UI_STRING("math", "An ARIA accessibility group that contains mathematical symbols."); + return WEB_UI_STRING("math", "An ARIA accessibility group that contains mathematical symbols."); return String(); } #endif String DefaultLocalizationStrategy::AXButtonActionVerb() { - return UI_STRING("press", "Verb stating the action that will occur when a button is pressed, as used by accessibility"); + return WEB_UI_STRING("press", "Verb stating the action that will occur when a button is pressed, as used by accessibility"); } String DefaultLocalizationStrategy::AXRadioButtonActionVerb() { - return UI_STRING("select", "Verb stating the action that will occur when a radio button is clicked, as used by accessibility"); + return WEB_UI_STRING("select", "Verb stating the action that will occur when a radio button is clicked, as used by accessibility"); } String DefaultLocalizationStrategy::AXTextFieldActionVerb() { - return UI_STRING("activate", "Verb stating the action that will occur when a text field is selected, as used by accessibility"); + return WEB_UI_STRING("activate", "Verb stating the action that will occur when a text field is selected, as used by accessibility"); } String DefaultLocalizationStrategy::AXCheckedCheckBoxActionVerb() { - return UI_STRING("uncheck", "Verb stating the action that will occur when a checked checkbox is clicked, as used by accessibility"); + return WEB_UI_STRING("uncheck", "Verb stating the action that will occur when a checked checkbox is clicked, as used by accessibility"); } String DefaultLocalizationStrategy::AXUncheckedCheckBoxActionVerb() { - return UI_STRING("check", "Verb stating the action that will occur when an unchecked checkbox is clicked, as used by accessibility"); + return WEB_UI_STRING("check", "Verb stating the action that will occur when an unchecked checkbox is clicked, as used by accessibility"); } String DefaultLocalizationStrategy::AXMenuListActionVerb() @@ -645,27 +650,27 @@ String DefaultLocalizationStrategy::AXMenuListPopupActionVerb() String DefaultLocalizationStrategy::AXLinkActionVerb() { - return UI_STRING("jump", "Verb stating the action that will occur when a link is clicked, as used by accessibility"); + return WEB_UI_STRING("jump", "Verb stating the action that will occur when a link is clicked, as used by accessibility"); } String DefaultLocalizationStrategy::missingPluginText() { - return UI_STRING("Missing Plug-in", "Label text to be used when a plugin is missing"); + return WEB_UI_STRING("Missing Plug-in", "Label text to be used when a plugin is missing"); } String DefaultLocalizationStrategy::crashedPluginText() { - return UI_STRING("Plug-in Failure", "Label text to be used if plugin host process has crashed"); + return WEB_UI_STRING("Plug-in Failure", "Label text to be used if plugin host process has crashed"); } String DefaultLocalizationStrategy::multipleFileUploadText(unsigned numberOfFiles) { - return formatLocalizedString(UI_STRING("%d files", "Label to describe the number of files selected in a file upload control that allows multiple files"), numberOfFiles); + return formatLocalizedString(WEB_UI_STRING("%d files", "Label to describe the number of files selected in a file upload control that allows multiple files"), numberOfFiles); } String DefaultLocalizationStrategy::unknownFileSizeText() { - return UI_STRING("Unknown", "Unknown filesize FTP directory listing item"); + return WEB_UI_STRING("Unknown", "Unknown filesize FTP directory listing item"); } #if PLATFORM(WIN) @@ -688,80 +693,101 @@ String DefaultLocalizationStrategy::allFilesText() String DefaultLocalizationStrategy::keygenMenuItem512() { - return UI_STRING("512 (Low Grade)", "Menu item title for KEYGEN pop-up menu"); + return WEB_UI_STRING("512 (Low Grade)", "Menu item title for KEYGEN pop-up menu"); } String DefaultLocalizationStrategy::keygenMenuItem1024() { - return UI_STRING("1024 (Medium Grade)", "Menu item title for KEYGEN pop-up menu"); + return WEB_UI_STRING("1024 (Medium Grade)", "Menu item title for KEYGEN pop-up menu"); } String DefaultLocalizationStrategy::keygenMenuItem2048() { - return UI_STRING("2048 (High Grade)", "Menu item title for KEYGEN pop-up menu"); + return WEB_UI_STRING("2048 (High Grade)", "Menu item title for KEYGEN pop-up menu"); } String DefaultLocalizationStrategy::keygenKeychainItemName(const String& host) { - return UI_STRING("Key from <hostname>", "Name of keychain key generated by the KEYGEN tag").replace("<hostname>", host); + RetainPtr<CFStringRef> hostCFString(AdoptCF, host.createCFString()); + return formatLocalizedString(WEB_UI_STRING("Key from %@", "Name of keychain key generated by the KEYGEN tag"), hostCFString.get()); } #endif String DefaultLocalizationStrategy::imageTitle(const String& filename, const IntSize& size) { - // FIXME: This should format the numbers correctly. In Mac WebKit, we used +[NSNumberFormatter localizedStringFromNumber:numberStyle:]. - return formatLocalizedString(UI_STRING("<filename> %d×%d pixels", "window title suffix for a standalone image (uses multiplication symbol, not x)"), size.width(), size.height()).replace("<filename>", filename); +#if USE(CF) +#if !defined(BUILDING_ON_LEOPARD) + RetainPtr<CFStringRef> filenameCFString(AdoptCF, filename.createCFString()); + RetainPtr<CFLocaleRef> locale(AdoptCF, CFLocaleCopyCurrent()); + RetainPtr<CFNumberFormatterRef> formatter(AdoptCF, CFNumberFormatterCreate(0, locale.get(), kCFNumberFormatterDecimalStyle)); + + int widthInt = size.width(); + RetainPtr<CFNumberRef> width(AdoptCF, CFNumberCreate(0, kCFNumberIntType, &widthInt)); + RetainPtr<CFStringRef> widthString(AdoptCF, CFNumberFormatterCreateStringWithNumber(0, formatter.get(), width.get())); + + int heightInt = size.height(); + RetainPtr<CFNumberRef> height(AdoptCF, CFNumberCreate(0, kCFNumberIntType, &heightInt)); + RetainPtr<CFStringRef> heightString(AdoptCF, CFNumberFormatterCreateStringWithNumber(0, formatter.get(), height.get())); + + return formatLocalizedString(WEB_UI_STRING("%@ %@×%@ pixels", "window title for a standalone image (uses multiplication symbol, not x)"), filenameCFString.get(), widthString.get(), heightString.get()); +#else + RetainPtr<CFStringRef> filenameCFString(AdoptCF, filename.createCFString()); + return formatLocalizedString(WEB_UI_STRING("%@ %d×%d pixels", "window title for a standalone image (uses multiplication symbol, not x)"), filenameCFString.get(), size.width(), size.height()); +#endif +#else + return formatLocalizedString(WEB_UI_STRING("<filename> %d×%d pixels", "window title for a standalone image (uses multiplication symbol, not x)"), size.width(), size.height()).replace("<filename>", filename); +#endif } String DefaultLocalizationStrategy::mediaElementLoadingStateText() { - return UI_STRING("Loading...", "Media controller status message when the media is loading"); + return WEB_UI_STRING("Loading...", "Media controller status message when the media is loading"); } String DefaultLocalizationStrategy::mediaElementLiveBroadcastStateText() { - return UI_STRING("Live Broadcast", "Media controller status message when watching a live broadcast"); + return WEB_UI_STRING("Live Broadcast", "Media controller status message when watching a live broadcast"); } String DefaultLocalizationStrategy::localizedMediaControlElementString(const String& name) { if (name == "AudioElement") - return UI_STRING("audio element controller", "accessibility role description for audio element controller"); + return WEB_UI_STRING("audio element controller", "accessibility role description for audio element controller"); if (name == "VideoElement") - return UI_STRING("video element controller", "accessibility role description for video element controller"); + return WEB_UI_STRING("video element controller", "accessibility role description for video element controller"); if (name == "MuteButton") - return UI_STRING("mute", "accessibility role description for mute button"); + return WEB_UI_STRING("mute", "accessibility role description for mute button"); if (name == "UnMuteButton") - return UI_STRING("unmute", "accessibility role description for turn mute off button"); + return WEB_UI_STRING("unmute", "accessibility role description for turn mute off button"); if (name == "PlayButton") - return UI_STRING("play", "accessibility role description for play button"); + return WEB_UI_STRING("play", "accessibility role description for play button"); if (name == "PauseButton") - return UI_STRING("pause", "accessibility role description for pause button"); + return WEB_UI_STRING("pause", "accessibility role description for pause button"); if (name == "Slider") - return UI_STRING("movie time", "accessibility role description for timeline slider"); + return WEB_UI_STRING("movie time", "accessibility role description for timeline slider"); if (name == "SliderThumb") - return UI_STRING("timeline slider thumb", "accessibility role description for timeline thumb"); + return WEB_UI_STRING("timeline slider thumb", "accessibility role description for timeline thumb"); if (name == "RewindButton") - return UI_STRING("back 30 seconds", "accessibility role description for seek back 30 seconds button"); + return WEB_UI_STRING("back 30 seconds", "accessibility role description for seek back 30 seconds button"); if (name == "ReturnToRealtimeButton") - return UI_STRING("return to realtime", "accessibility role description for return to real time button"); + return WEB_UI_STRING("return to realtime", "accessibility role description for return to real time button"); if (name == "CurrentTimeDisplay") - return UI_STRING("elapsed time", "accessibility role description for elapsed time display"); + return WEB_UI_STRING("elapsed time", "accessibility role description for elapsed time display"); if (name == "TimeRemainingDisplay") - return UI_STRING("remaining time", "accessibility role description for time remaining display"); + return WEB_UI_STRING("remaining time", "accessibility role description for time remaining display"); if (name == "StatusDisplay") - return UI_STRING("status", "accessibility role description for movie status"); + return WEB_UI_STRING("status", "accessibility role description for movie status"); if (name == "FullscreenButton") - return UI_STRING("fullscreen", "accessibility role description for enter fullscreen button"); + return WEB_UI_STRING("fullscreen", "accessibility role description for enter fullscreen button"); if (name == "SeekForwardButton") - return UI_STRING("fast forward", "accessibility role description for fast forward button"); + return WEB_UI_STRING("fast forward", "accessibility role description for fast forward button"); if (name == "SeekBackButton") - return UI_STRING("fast reverse", "accessibility role description for fast reverse button"); + return WEB_UI_STRING("fast reverse", "accessibility role description for fast reverse button"); if (name == "ShowClosedCaptionsButton") - return UI_STRING("show closed captions", "accessibility role description for show closed captions button"); + return WEB_UI_STRING("show closed captions", "accessibility role description for show closed captions button"); if (name == "HideClosedCaptionsButton") - return UI_STRING("hide closed captions", "accessibility role description for hide closed captions button"); + return WEB_UI_STRING("hide closed captions", "accessibility role description for hide closed captions button"); // FIXME: the ControlsPanel container should never be visible in the accessibility hierarchy. if (name == "ControlsPanel") @@ -774,41 +800,41 @@ String DefaultLocalizationStrategy::localizedMediaControlElementString(const Str String DefaultLocalizationStrategy::localizedMediaControlElementHelpText(const String& name) { if (name == "AudioElement") - return UI_STRING("audio element playback controls and status display", "accessibility role description for audio element controller"); + return WEB_UI_STRING("audio element playback controls and status display", "accessibility role description for audio element controller"); if (name == "VideoElement") - return UI_STRING("video element playback controls and status display", "accessibility role description for video element controller"); + return WEB_UI_STRING("video element playback controls and status display", "accessibility role description for video element controller"); if (name == "MuteButton") - return UI_STRING("mute audio tracks", "accessibility help text for mute button"); + return WEB_UI_STRING("mute audio tracks", "accessibility help text for mute button"); if (name == "UnMuteButton") - return UI_STRING("unmute audio tracks", "accessibility help text for un mute button"); + return WEB_UI_STRING("unmute audio tracks", "accessibility help text for un mute button"); if (name == "PlayButton") - return UI_STRING("begin playback", "accessibility help text for play button"); + return WEB_UI_STRING("begin playback", "accessibility help text for play button"); if (name == "PauseButton") - return UI_STRING("pause playback", "accessibility help text for pause button"); + return WEB_UI_STRING("pause playback", "accessibility help text for pause button"); if (name == "Slider") - return UI_STRING("movie time scrubber", "accessibility help text for timeline slider"); + return WEB_UI_STRING("movie time scrubber", "accessibility help text for timeline slider"); if (name == "SliderThumb") - return UI_STRING("movie time scrubber thumb", "accessibility help text for timeline slider thumb"); + return WEB_UI_STRING("movie time scrubber thumb", "accessibility help text for timeline slider thumb"); if (name == "RewindButton") - return UI_STRING("seek movie back 30 seconds", "accessibility help text for jump back 30 seconds button"); + return WEB_UI_STRING("seek movie back 30 seconds", "accessibility help text for jump back 30 seconds button"); if (name == "ReturnToRealtimeButton") - return UI_STRING("return streaming movie to real time", "accessibility help text for return streaming movie to real time button"); + return WEB_UI_STRING("return streaming movie to real time", "accessibility help text for return streaming movie to real time button"); if (name == "CurrentTimeDisplay") - return UI_STRING("current movie time in seconds", "accessibility help text for elapsed time display"); + return WEB_UI_STRING("current movie time in seconds", "accessibility help text for elapsed time display"); if (name == "TimeRemainingDisplay") - return UI_STRING("number of seconds of movie remaining", "accessibility help text for remaining time display"); + return WEB_UI_STRING("number of seconds of movie remaining", "accessibility help text for remaining time display"); if (name == "StatusDisplay") - return UI_STRING("current movie status", "accessibility help text for movie status display"); + return WEB_UI_STRING("current movie status", "accessibility help text for movie status display"); if (name == "SeekBackButton") - return UI_STRING("seek quickly back", "accessibility help text for fast rewind button"); + return WEB_UI_STRING("seek quickly back", "accessibility help text for fast rewind button"); if (name == "SeekForwardButton") - return UI_STRING("seek quickly forward", "accessibility help text for fast forward button"); + return WEB_UI_STRING("seek quickly forward", "accessibility help text for fast forward button"); if (name == "FullscreenButton") - return UI_STRING("Play movie in fullscreen mode", "accessibility help text for enter fullscreen button"); + return WEB_UI_STRING("Play movie in fullscreen mode", "accessibility help text for enter fullscreen button"); if (name == "ShowClosedCaptionsButton") - return UI_STRING("start displaying closed captions", "accessibility help text for show closed captions button"); + return WEB_UI_STRING("start displaying closed captions", "accessibility help text for show closed captions button"); if (name == "HideClosedCaptionsButton") - return UI_STRING("stop displaying closed captions", "accessibility help text for hide closed captions button"); + return WEB_UI_STRING("stop displaying closed captions", "accessibility help text for hide closed captions button"); ASSERT_NOT_REACHED(); return String(); @@ -817,7 +843,7 @@ String DefaultLocalizationStrategy::localizedMediaControlElementHelpText(const S String DefaultLocalizationStrategy::localizedMediaTimeDescription(float time) { if (!isfinite(time)) - return UI_STRING("indefinite time", "accessibility help text for an indefinite media controller time value"); + return WEB_UI_STRING("indefinite time", "accessibility help text for an indefinite media controller time value"); int seconds = static_cast<int>(fabsf(time)); int days = seconds / (60 * 60 * 24); @@ -826,47 +852,47 @@ String DefaultLocalizationStrategy::localizedMediaTimeDescription(float time) seconds %= 60; if (days) - return formatLocalizedString(UI_STRING("%1$d days %2$d hours %3$d minutes %4$d seconds", "accessibility help text for media controller time value >= 1 day"), days, hours, minutes, seconds); + return formatLocalizedString(WEB_UI_STRING("%1$d days %2$d hours %3$d minutes %4$d seconds", "accessibility help text for media controller time value >= 1 day"), days, hours, minutes, seconds); if (hours) - return formatLocalizedString(UI_STRING("%1$d hours %2$d minutes %3$d seconds", "accessibility help text for media controller time value >= 60 minutes"), hours, minutes, seconds); + return formatLocalizedString(WEB_UI_STRING("%1$d hours %2$d minutes %3$d seconds", "accessibility help text for media controller time value >= 60 minutes"), hours, minutes, seconds); if (minutes) - return formatLocalizedString(UI_STRING("%1$d minutes %2$d seconds", "accessibility help text for media controller time value >= 60 seconds"), minutes, seconds); - return formatLocalizedString(UI_STRING("%1$d seconds", "accessibility help text for media controller time value < 60 seconds"), seconds); + return formatLocalizedString(WEB_UI_STRING("%1$d minutes %2$d seconds", "accessibility help text for media controller time value >= 60 seconds"), minutes, seconds); + return formatLocalizedString(WEB_UI_STRING("%1$d seconds", "accessibility help text for media controller time value < 60 seconds"), seconds); } String DefaultLocalizationStrategy::validationMessageValueMissingText() { - return UI_STRING("value missing", "Validation message for required form control elements that have no value"); + return WEB_UI_STRING("value missing", "Validation message for required form control elements that have no value"); } String DefaultLocalizationStrategy::validationMessageTypeMismatchText() { - return UI_STRING("type mismatch", "Validation message for input form controls with a value not matching type"); + return WEB_UI_STRING("type mismatch", "Validation message for input form controls with a value not matching type"); } String DefaultLocalizationStrategy::validationMessagePatternMismatchText() { - return UI_STRING("pattern mismatch", "Validation message for input form controls requiring a constrained value according to pattern"); + return WEB_UI_STRING("pattern mismatch", "Validation message for input form controls requiring a constrained value according to pattern"); } String DefaultLocalizationStrategy::validationMessageTooLongText() { - return UI_STRING("too long", "Validation message for form control elements with a value longer than maximum allowed length"); + return WEB_UI_STRING("too long", "Validation message for form control elements with a value longer than maximum allowed length"); } String DefaultLocalizationStrategy::validationMessageRangeUnderflowText() { - return UI_STRING("range underflow", "Validation message for input form controls with value lower than allowed minimum"); + return WEB_UI_STRING("range underflow", "Validation message for input form controls with value lower than allowed minimum"); } String DefaultLocalizationStrategy::validationMessageRangeOverflowText() { - return UI_STRING("range overflow", "Validation message for input form controls with value higher than allowed maximum"); + return WEB_UI_STRING("range overflow", "Validation message for input form controls with value higher than allowed maximum"); } String DefaultLocalizationStrategy::validationMessageStepMismatchText() { - return UI_STRING("step mismatch", "Validation message for input form controls with value not respecting the step attribute"); + return WEB_UI_STRING("step mismatch", "Validation message for input form controls with value not respecting the step attribute"); } } // namespace WebCore diff --git a/Source/WebCore/platform/DragData.h b/Source/WebCore/platform/DragData.h index b89748e..5b29610 100644 --- a/Source/WebCore/platform/DragData.h +++ b/Source/WebCore/platform/DragData.h @@ -119,6 +119,9 @@ public: bool canSmartReplace() const; bool containsColor() const; bool containsFiles() const; +#if PLATFORM(MAC) + NSPasteboard *pasteboard() { return m_pasteboard.get(); } +#endif private: IntPoint m_clientPosition; IntPoint m_globalPosition; diff --git a/Source/WebCore/platform/FileSystem.h b/Source/WebCore/platform/FileSystem.h index 49a78e8..418a645 100644 --- a/Source/WebCore/platform/FileSystem.h +++ b/Source/WebCore/platform/FileSystem.h @@ -47,6 +47,11 @@ #endif #endif +#if PLATFORM(WX) +#include <wx/defs.h> +#include <wx/file.h> +#endif + #if USE(CF) || (PLATFORM(QT) && defined(Q_WS_MAC)) typedef struct __CFBundle* CFBundleRef; typedef const struct __CFData* CFDataRef; @@ -72,7 +77,9 @@ typedef struct _GModule GModule; namespace WebCore { // PlatformModule -#if OS(WINDOWS) +#if PLATFORM(GTK) +typedef GModule* PlatformModule; +#elif OS(WINDOWS) typedef HMODULE PlatformModule; #elif PLATFORM(QT) #if defined(Q_WS_MAC) @@ -82,8 +89,6 @@ typedef QLibrary* PlatformModule; #else typedef void* PlatformModule; #endif -#elif PLATFORM(GTK) -typedef GModule* PlatformModule; #elif USE(CF) typedef CFBundleRef PlatformModule; #else @@ -117,6 +122,9 @@ typedef unsigned PlatformModuleVersion; #if PLATFORM(QT) typedef QFile* PlatformFileHandle; const PlatformFileHandle invalidPlatformFileHandle = 0; +#elif PLATFORM(GTK) +typedef GFileIOStream* PlatformFileHandle; +const PlatformFileHandle invalidPlatformFileHandle = 0; #elif OS(WINDOWS) typedef HANDLE PlatformFileHandle; // FIXME: -1 is INVALID_HANDLE_VALUE, defined in <winbase.h>. Chromium tries to @@ -125,8 +133,8 @@ const PlatformFileHandle invalidPlatformFileHandle = reinterpret_cast<HANDLE>(-1 #elif PLATFORM(BREWMP) typedef IFile* PlatformFileHandle; const PlatformFileHandle invalidPlatformFileHandle = 0; -#elif PLATFORM(GTK) -typedef GFileIOStream* PlatformFileHandle; +#elif PLATFORM(WX) +typedef wxFile* PlatformFileHandle; const PlatformFileHandle invalidPlatformFileHandle = 0; #else typedef int PlatformFileHandle; diff --git a/Source/WebCore/platform/FloatConversion.h b/Source/WebCore/platform/FloatConversion.h index 655ab44..fb76833 100644 --- a/Source/WebCore/platform/FloatConversion.h +++ b/Source/WebCore/platform/FloatConversion.h @@ -29,7 +29,7 @@ #ifndef FloatConversion_h #define FloatConversion_h -#if PLATFORM(CG) +#if USE(CG) #include <CoreGraphics/CGBase.h> #endif @@ -44,7 +44,7 @@ namespace WebCore { return static_cast<float>(number); } -#if PLATFORM(CG) +#if USE(CG) template<typename T> CGFloat narrowPrecisionToCGFloat(T); diff --git a/Source/WebCore/platform/KURL.h b/Source/WebCore/platform/KURL.h index 5764494..db2dd42 100644 --- a/Source/WebCore/platform/KURL.h +++ b/Source/WebCore/platform/KURL.h @@ -76,6 +76,12 @@ public: KURL(ParsedURLStringTag, const char*); KURL(ParsedURLStringTag, const String&); KURL(ParsedURLStringTag, const URLString&); +#if USE(GOOGLEURL) + KURL(WTF::HashTableDeletedValueType) : m_url(WTF::HashTableDeletedValue) { } +#else + KURL(WTF::HashTableDeletedValueType) : m_string(WTF::HashTableDeletedValue) { } +#endif + bool isHashTableDeletedValue() const { return string().isHashTableDeletedValue(); } // Resolves the relative URL with the given base URL. If provided, the // TextEncoding is used to encode non-ASCII characers. The base URL can be diff --git a/Source/WebCore/platform/KURLGoogle.cpp b/Source/WebCore/platform/KURLGoogle.cpp index 88120a8..0d11b99 100644 --- a/Source/WebCore/platform/KURLGoogle.cpp +++ b/Source/WebCore/platform/KURLGoogle.cpp @@ -169,6 +169,11 @@ KURLGooglePrivate::KURLGooglePrivate(const url_parse::Parsed& parsed, bool isVal { } +KURLGooglePrivate::KURLGooglePrivate(WTF::HashTableDeletedValueType) + : m_string(WTF::HashTableDeletedValue) +{ +} + // Setters for the data. Using the ASCII version when you know the // data is ASCII will be slightly more efficient. The UTF-8 version // will always be correct if the caller is unsure. diff --git a/Source/WebCore/platform/KURLGooglePrivate.h b/Source/WebCore/platform/KURLGooglePrivate.h index c74a6b4..12427a3 100644 --- a/Source/WebCore/platform/KURLGooglePrivate.h +++ b/Source/WebCore/platform/KURLGooglePrivate.h @@ -48,6 +48,7 @@ namespace WebCore { public: KURLGooglePrivate(); KURLGooglePrivate(const url_parse::Parsed&, bool isValid); + KURLGooglePrivate(WTF::HashTableDeletedValueType); // Initializes the object. This will call through the backend initializer // below. diff --git a/Source/WebCore/platform/KURLHash.h b/Source/WebCore/platform/KURLHash.h index 44a4624..a236508 100644 --- a/Source/WebCore/platform/KURLHash.h +++ b/Source/WebCore/platform/KURLHash.h @@ -50,11 +50,7 @@ namespace WebCore { namespace WTF { - template<> struct HashTraits<WebCore::KURL> : GenericHashTraits<WebCore::KURL> { - static const bool emptyValueIsZero = true; - static void constructDeletedValue(WebCore::KURL& slot) { new (&slot) WebCore::KURL(WebCore::ParsedURLString, WTF::String(HashTableDeletedValue)); } - static bool isDeletedValue(const WebCore::KURL& slot) { return slot.string().isHashTableDeletedValue(); } - }; + template<> struct HashTraits<WebCore::KURL> : SimpleClassHashTraits<WebCore::KURL> { }; } // namespace WTF diff --git a/Source/WebCore/platform/LocalizedStrings.h b/Source/WebCore/platform/LocalizedStrings.h index 3885439..777fcec 100644 --- a/Source/WebCore/platform/LocalizedStrings.h +++ b/Source/WebCore/platform/LocalizedStrings.h @@ -195,8 +195,8 @@ namespace WebCore { String validationMessageStepMismatchText(const String& base, const String& step); -#define UI_STRING(string, description) WebCore::localizedString(string) -#define UI_STRING_KEY(string, key, description) WebCore::localizedString(key) +#define WEB_UI_STRING(string, description) WebCore::localizedString(string) +#define WEB_UI_STRING_KEY(string, key, description) WebCore::localizedString(key) String localizedString(const char* key); diff --git a/Source/WebCore/platform/MIMETypeRegistry.cpp b/Source/WebCore/platform/MIMETypeRegistry.cpp index d0ad985..c334683 100644 --- a/Source/WebCore/platform/MIMETypeRegistry.cpp +++ b/Source/WebCore/platform/MIMETypeRegistry.cpp @@ -33,7 +33,7 @@ #include <wtf/StdLibExtras.h> #include <wtf/text/StringHash.h> -#if PLATFORM(CG) +#if USE(CG) #include "ImageSourceCG.h" #include <ApplicationServices/ApplicationServices.h> #include <wtf/RetainPtr.h> @@ -61,7 +61,7 @@ typedef HashMap<String, Vector<String>*, CaseFoldingHash> MediaMIMETypeMap; static void initializeSupportedImageMIMETypes() { -#if PLATFORM(CG) +#if USE(CG) RetainPtr<CFArrayRef> supportedTypes(AdoptCF, CGImageSourceCopyTypeIdentifiers()); CFIndex count = CFArrayGetCount(supportedTypes.get()); for (CFIndex i = 0; i < count; i++) { @@ -157,7 +157,7 @@ static void initializeSupportedImageMIMETypesForEncoding() { supportedImageMIMETypesForEncoding = new HashSet<String>; -#if PLATFORM(CG) +#if USE(CG) #if PLATFORM(MAC) RetainPtr<CFArrayRef> supportedTypes(AdoptCF, CGImageDestinationCopyTypeIdentifiers()); CFIndex count = CFArrayGetCount(supportedTypes.get()); @@ -187,7 +187,7 @@ static void initializeSupportedImageMIMETypesForEncoding() supportedImageMIMETypesForEncoding->add("image/tiff"); supportedImageMIMETypesForEncoding->add("image/bmp"); supportedImageMIMETypesForEncoding->add("image/ico"); -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) supportedImageMIMETypesForEncoding->add("image/png"); #endif } diff --git a/Source/WebCore/platform/RuntimeApplicationChecks.cpp b/Source/WebCore/platform/RuntimeApplicationChecks.cpp new file mode 100644 index 0000000..bdb44c0 --- /dev/null +++ b/Source/WebCore/platform/RuntimeApplicationChecks.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RuntimeApplicationChecks.h" + +#if USE(CF) +#include <CoreFoundation/CoreFoundation.h> +#include <wtf/RetainPtr.h> +#endif + +#include <wtf/text/WTFString.h> + +namespace WebCore { + +static bool mainBundleIsEqualTo(const String& bundleIdentifierString) +{ +#if USE(CF) + CFBundleRef mainBundle = CFBundleGetMainBundle(); + if (!mainBundle) + return false; + + CFStringRef bundleIdentifier = CFBundleGetIdentifier(mainBundle); + if (!bundleIdentifier) + return false; + + RetainPtr<CFStringRef> bundleIdentifierToCompare(AdoptCF, bundleIdentifierString.createCFString()); + return CFStringCompare(bundleIdentifier, bundleIdentifierToCompare.get(), 0) == kCFCompareEqualTo; +#else + return false; +#endif +} + +bool applicationIsSafari() +{ + // FIXME: For the WebProcess case, ensure that this is Safari's WebProcess. + static bool isSafari = mainBundleIsEqualTo("com.apple.Safari") || mainBundleIsEqualTo("com.apple.WebProcess"); + return isSafari; +} + +bool applicationIsAppleMail() +{ + static bool isAppleMail = mainBundleIsEqualTo("com.apple.mail"); + return isAppleMail; +} + +bool applicationIsMicrosoftMessenger() +{ + static bool isMicrosoftMessenger = mainBundleIsEqualTo("com.microsoft.Messenger"); + return isMicrosoftMessenger; +} + +bool applicationIsAdobeInstaller() +{ + static bool isAdobeInstaller = mainBundleIsEqualTo("com.adobe.Installers.Setup"); + return isAdobeInstaller; +} + +bool applicationIsAOLInstantMessenger() +{ + static bool isAOLInstantMessenger = mainBundleIsEqualTo("com.aol.aim.desktop"); + return isAOLInstantMessenger; +} + +bool applicationIsMicrosoftMyDay() +{ + static bool isMicrosoftMyDay = mainBundleIsEqualTo("com.microsoft.myday"); + return isMicrosoftMyDay; +} + +bool applicationIsMicrosoftOutlook() +{ + static bool isMicrosoftOutlook = mainBundleIsEqualTo("com.microsoft.Outlook"); + return isMicrosoftOutlook; +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/mac/RuntimeApplicationChecks.h b/Source/WebCore/platform/RuntimeApplicationChecks.h index f938048..c2f4ba1 100644 --- a/Source/WebCore/platform/mac/RuntimeApplicationChecks.h +++ b/Source/WebCore/platform/RuntimeApplicationChecks.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2011 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,6 +34,7 @@ bool applicationIsMicrosoftMessenger(); bool applicationIsAdobeInstaller(); bool applicationIsAOLInstantMessenger(); bool applicationIsMicrosoftMyDay(); +bool applicationIsMicrosoftOutlook(); } // namespace WebCore diff --git a/Source/WebCore/platform/ScrollTypes.h b/Source/WebCore/platform/ScrollTypes.h index 1f8e095..62b4645 100644 --- a/Source/WebCore/platform/ScrollTypes.h +++ b/Source/WebCore/platform/ScrollTypes.h @@ -108,6 +108,12 @@ namespace WebCore { ScrollByPixel }; + enum ScrollElasticity { + ScrollElasticityAutomatic, + ScrollElasticityNone, + ScrollElasticityAllowed + }; + enum ScrollbarOrientation { HorizontalScrollbar, VerticalScrollbar }; enum ScrollbarMode { ScrollbarAuto, ScrollbarAlwaysOff, ScrollbarAlwaysOn }; diff --git a/Source/WebCore/platform/ScrollView.cpp b/Source/WebCore/platform/ScrollView.cpp index 58615fb..e79f049 100644 --- a/Source/WebCore/platform/ScrollView.cpp +++ b/Source/WebCore/platform/ScrollView.cpp @@ -28,6 +28,7 @@ #include "AXObjectCache.h" #include "GraphicsContext.h" +#include "GraphicsLayer.h" #include "HostWindow.h" #include "PlatformMouseEvent.h" #include "PlatformWheelEvent.h" @@ -56,6 +57,7 @@ ScrollView::ScrollView() , m_paintsEntireContents(false) , m_clipsRepaints(true) , m_delegatesScrolling(false) + , m_containsScrollableAreaWithOverlayScrollbars(false) { platformInit(); } @@ -873,8 +875,45 @@ void ScrollView::frameRectsChanged() HashSet<RefPtr<Widget> >::const_iterator end = m_children.end(); for (HashSet<RefPtr<Widget> >::const_iterator current = m_children.begin(); current != end; ++current) (*current)->frameRectsChanged(); + positionScrollbarLayers(); } +#if USE(ACCELERATED_COMPOSITING) +static void positionScrollbarLayer(GraphicsLayer* graphicsLayer, Scrollbar* scrollbar) +{ + if (!graphicsLayer || !scrollbar) + return; + graphicsLayer->setDrawsContent(true); + IntRect scrollbarRect = scrollbar->frameRect(); + graphicsLayer->setPosition(scrollbarRect.location()); + if (scrollbarRect.size() != graphicsLayer->size()) + graphicsLayer->setNeedsDisplay(); + graphicsLayer->setSize(scrollbarRect.size()); +} + +static void positionScrollCornerLayer(GraphicsLayer* graphicsLayer, const IntRect& cornerRect) +{ + if (!graphicsLayer) + return; + graphicsLayer->setDrawsContent(!cornerRect.isEmpty()); + graphicsLayer->setPosition(cornerRect.location()); + if (cornerRect.size() != graphicsLayer->size()) + graphicsLayer->setNeedsDisplay(); + graphicsLayer->setSize(cornerRect.size()); +} +#endif + + +void ScrollView::positionScrollbarLayers() +{ +#if USE(ACCELERATED_COMPOSITING) + positionScrollbarLayer(layerForHorizontalScrollbar(), horizontalScrollbar()); + positionScrollbarLayer(layerForVerticalScrollbar(), verticalScrollbar()); + positionScrollCornerLayer(layerForScrollCorner(), scrollCornerRect()); +#endif +} + + void ScrollView::repaintContentRectangle(const IntRect& rect, bool now) { IntRect paintRect = rect; @@ -919,6 +958,11 @@ IntRect ScrollView::scrollCornerRect() const return cornerRect; } +bool ScrollView::isScrollCornerVisible() const +{ + return !scrollCornerRect().isEmpty(); +} + void ScrollView::updateScrollCorner() { } @@ -928,13 +972,30 @@ void ScrollView::paintScrollCorner(GraphicsContext* context, const IntRect& corn ScrollbarTheme::nativeTheme()->paintScrollCorner(this, context, cornerRect); } +void ScrollView::invalidateScrollCornerRect(const IntRect& rect) +{ + invalidateRect(rect); +} + void ScrollView::paintScrollbars(GraphicsContext* context, const IntRect& rect) { - if (m_horizontalScrollbar) + if (m_horizontalScrollbar +#if USE(ACCELERATED_COMPOSITING) + && !layerForHorizontalScrollbar() +#endif + ) m_horizontalScrollbar->paint(context, rect); - if (m_verticalScrollbar) + if (m_verticalScrollbar +#if USE(ACCELERATED_COMPOSITING) + && !layerForVerticalScrollbar() +#endif + ) m_verticalScrollbar->paint(context, rect); +#if USE(ACCELERATED_COMPOSITING) + if (layerForScrollCorner()) + return; +#endif paintScrollCorner(context, scrollCornerRect()); } @@ -955,6 +1016,9 @@ void ScrollView::paint(GraphicsContext* context, const IntRect& rect) return; notifyPageThatContentAreaWillPaint(); + + // If we encounter any overlay scrollbars as we paint, this will be set to true. + m_containsScrollableAreaWithOverlayScrollbars = false; IntRect documentDirtyRect = rect; documentDirtyRect.intersect(frameRect()); diff --git a/Source/WebCore/platform/ScrollView.h b/Source/WebCore/platform/ScrollView.h index bff77d5..558aee2 100644 --- a/Source/WebCore/platform/ScrollView.h +++ b/Source/WebCore/platform/ScrollView.h @@ -63,6 +63,7 @@ public: virtual void setScrollOffset(const IntPoint&); virtual void didCompleteRubberBand(const IntSize&) const; virtual void notifyPageThatContentAreaWillPaint() const; + virtual bool isScrollCornerVisible() const; // NOTE: This should only be called by the overriden setScrollOffset from ScrollableArea. virtual void scrollTo(const IntSize& newOffset); @@ -85,6 +86,8 @@ public: virtual Scrollbar* verticalScrollbar() const { return m_verticalScrollbar.get(); } bool isScrollViewScrollbar(const Widget* child) const { return horizontalScrollbar() == child || verticalScrollbar() == child; } + void positionScrollbarLayers(); + // Functions for setting and retrieving the scrolling mode in each axis (horizontal/vertical). The mode has values of // AlwaysOff, AlwaysOn, and Auto. AlwaysOff means never show a scrollbar, AlwaysOn means always show a scrollbar. // Auto means show a scrollbar only when one is needed. @@ -183,6 +186,9 @@ public: IntSize overhangAmount() const; + void cacheCurrentScrollPosition() { m_cachedScrollPosition = scrollPosition(); } + IntPoint cachedScrollPosition() const { return m_cachedScrollPosition; } + // Functions for scrolling the view. void setScrollPosition(const IntPoint&); void scrollBy(const IntSize& s) { return setScrollPosition(scrollPosition() + s); } @@ -278,12 +284,17 @@ public: virtual bool isPointInScrollbarCorner(const IntPoint&); virtual bool scrollbarCornerPresent() const; + virtual IntRect scrollCornerRect() const; + virtual void paintScrollCorner(GraphicsContext*, const IntRect& cornerRect); virtual IntRect convertFromScrollbarToContainingView(const Scrollbar*, const IntRect&) const; virtual IntRect convertFromContainingViewToScrollbar(const Scrollbar*, const IntRect&) const; virtual IntPoint convertFromScrollbarToContainingView(const Scrollbar*, const IntPoint&) const; virtual IntPoint convertFromContainingViewToScrollbar(const Scrollbar*, const IntPoint&) const; + bool containsScrollableAreaWithOverlayScrollbars() const { return m_containsScrollableAreaWithOverlayScrollbars; } + void setContainsScrollableAreaWithOverlayScrollbars(bool contains) { m_containsScrollableAreaWithOverlayScrollbars = contains; } + protected: ScrollView(); @@ -303,9 +314,8 @@ protected: void setHasHorizontalScrollbar(bool); void setHasVerticalScrollbar(bool); - IntRect scrollCornerRect() const; virtual void updateScrollCorner(); - virtual void paintScrollCorner(GraphicsContext*, const IntRect& cornerRect); + virtual void invalidateScrollCornerRect(const IntRect&); // Scroll the content by blitting the pixels. virtual bool scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect); @@ -338,6 +348,7 @@ private: IntRect m_actualVisibleContentRect; IntSize m_scrollOffset; // FIXME: Would rather store this as a position, but we will wait to make this change until more code is shared. + IntPoint m_cachedScrollPosition; IntSize m_fixedLayoutSize; IntSize m_contentsSize; @@ -355,6 +366,8 @@ private: bool m_clipsRepaints; bool m_delegatesScrolling; + bool m_containsScrollableAreaWithOverlayScrollbars; + IntSize m_boundsSize; void init(); diff --git a/Source/WebCore/platform/ScrollableArea.cpp b/Source/WebCore/platform/ScrollableArea.cpp index 34cec9e..2b49427 100644 --- a/Source/WebCore/platform/ScrollableArea.cpp +++ b/Source/WebCore/platform/ScrollableArea.cpp @@ -32,6 +32,8 @@ #include "config.h" #include "ScrollableArea.h" +#include "GraphicsContext.h" +#include "GraphicsLayer.h" #include "FloatPoint.h" #include "PlatformWheelEvent.h" #include "ScrollAnimator.h" @@ -44,6 +46,8 @@ ScrollableArea::ScrollableArea() : m_scrollAnimator(ScrollAnimator::create(this)) , m_constrainsScrollingToContentEdge(true) , m_inLiveResize(false) + , m_verticalScrollElasticity(ScrollElasticityNone) + , m_horizontalScrollElasticity(ScrollElasticityNone) { } @@ -194,4 +198,33 @@ bool ScrollableArea::hasOverlayScrollbars() const || (horizontalScrollbar() && horizontalScrollbar()->isOverlayScrollbar()); } +void ScrollableArea::invalidateScrollbar(Scrollbar* scrollbar, const IntRect& rect) +{ +#if USE(ACCELERATED_COMPOSITING) + if (scrollbar == horizontalScrollbar()) { + if (GraphicsLayer* graphicsLayer = layerForHorizontalScrollbar()) { + graphicsLayer->setNeedsDisplay(); + return; + } + } else if (scrollbar == verticalScrollbar()) { + if (GraphicsLayer* graphicsLayer = layerForVerticalScrollbar()) { + graphicsLayer->setNeedsDisplay(); + return; + } + } +#endif + invalidateScrollbarRect(scrollbar, rect); +} + +void ScrollableArea::invalidateScrollCorner() +{ +#if USE(ACCELERATED_COMPOSITING) + if (GraphicsLayer* graphicsLayer = layerForScrollCorner()) { + graphicsLayer->setNeedsDisplay(); + return; + } +#endif + invalidateScrollCornerRect(scrollCornerRect()); +} + } // namespace WebCore diff --git a/Source/WebCore/platform/ScrollableArea.h b/Source/WebCore/platform/ScrollableArea.h index d08de00..cc63595 100644 --- a/Source/WebCore/platform/ScrollableArea.h +++ b/Source/WebCore/platform/ScrollableArea.h @@ -33,9 +33,13 @@ namespace WebCore { class FloatPoint; +class GraphicsContext; class PlatformGestureEvent; class PlatformWheelEvent; class ScrollAnimator; +#if USE(ACCELERATED_COMPOSITING) +class GraphicsLayer; +#endif class ScrollableArea { public: @@ -57,6 +61,12 @@ public: bool constrainsScrollingToContentEdge() const { return m_constrainsScrollingToContentEdge; } void setConstrainsScrollingToContentEdge(bool constrainsScrollingToContentEdge) { m_constrainsScrollingToContentEdge = constrainsScrollingToContentEdge; } + void setVerticalScrollElasticity(ScrollElasticity scrollElasticity) { m_verticalScrollElasticity = scrollElasticity; } + ScrollElasticity verticalScrollElasticity() const { return m_verticalScrollElasticity; } + + void setHorizontalScrollElasticity(ScrollElasticity scrollElasticity) { m_horizontalScrollElasticity = scrollElasticity; } + ScrollElasticity horizontalScrollElasticity() const { return m_horizontalScrollElasticity; } + bool inLiveResize() const { return m_inLiveResize; } void willStartLiveResize(); void willEndLiveResize(); @@ -71,11 +81,13 @@ public: ScrollAnimator* scrollAnimator() const { return m_scrollAnimator.get(); } const IntPoint& scrollOrigin() const { return m_scrollOrigin; } + virtual bool isActive() const = 0; virtual int scrollSize(ScrollbarOrientation) const = 0; virtual int scrollPosition(Scrollbar*) const = 0; - virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&) = 0; - virtual bool isActive() const = 0; - virtual bool scrollbarCornerPresent() const = 0; + void invalidateScrollbar(Scrollbar*, const IntRect&); + virtual bool isScrollCornerVisible() const = 0; + virtual IntRect scrollCornerRect() const = 0; + void invalidateScrollCorner(); virtual void getTickmarks(Vector<IntRect>&) const { } // This function should be overriden by subclasses to perform the actual @@ -130,7 +142,19 @@ private: bool m_inLiveResize; + ScrollElasticity m_verticalScrollElasticity; + ScrollElasticity m_horizontalScrollElasticity; + protected: + virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&) = 0; + virtual void invalidateScrollCornerRect(const IntRect&) = 0; + +#if USE(ACCELERATED_COMPOSITING) + virtual GraphicsLayer* layerForHorizontalScrollbar() const { return 0; } + virtual GraphicsLayer* layerForVerticalScrollbar() const { return 0; } + virtual GraphicsLayer* layerForScrollCorner() const { return 0; } +#endif + // There are 8 possible combinations of writing mode and direction. Scroll origin will be non-zero in the x or y axis // if there is any reversed direction or writing-mode. The combinations are: // writing-mode / direction scrollOrigin.x() set scrollOrigin.y() set diff --git a/Source/WebCore/platform/Scrollbar.cpp b/Source/WebCore/platform/Scrollbar.cpp index ba00ab0..e59b763 100644 --- a/Source/WebCore/platform/Scrollbar.cpp +++ b/Source/WebCore/platform/Scrollbar.cpp @@ -456,8 +456,9 @@ void Scrollbar::invalidateRect(const IntRect& rect) { if (suppressInvalidation()) return; + if (m_scrollableArea) - m_scrollableArea->invalidateScrollbarRect(this, rect); + m_scrollableArea->invalidateScrollbar(this, rect); } IntRect Scrollbar::convertToContainingView(const IntRect& localRect) const diff --git a/Source/WebCore/platform/Scrollbar.h b/Source/WebCore/platform/Scrollbar.h index 267eada..161f51e 100644 --- a/Source/WebCore/platform/Scrollbar.h +++ b/Source/WebCore/platform/Scrollbar.h @@ -146,7 +146,7 @@ protected: ScrollbarOrientation m_orientation; ScrollbarControlSize m_controlSize; ScrollbarTheme* m_theme; - + int m_visibleSize; int m_totalSize; float m_currentPos; diff --git a/Source/WebCore/platform/ScrollbarThemeComposite.cpp b/Source/WebCore/platform/ScrollbarThemeComposite.cpp index 26f1494..d9f2662 100644 --- a/Source/WebCore/platform/ScrollbarThemeComposite.cpp +++ b/Source/WebCore/platform/ScrollbarThemeComposite.cpp @@ -95,7 +95,7 @@ bool ScrollbarThemeComposite::paint(Scrollbar* scrollbar, GraphicsContext* graph scrollMask |= BackTrackPart; if (damageRect.intersects(endTrackRect)) scrollMask |= ForwardTrackPart; - } + } #if PLATFORM(WIN) // FIXME: This API makes the assumption that the custom scrollbar's metrics will match diff --git a/Source/WebCore/platform/SecureTextInput.cpp b/Source/WebCore/platform/SecureTextInput.cpp index bebb37e..06e1c86 100644 --- a/Source/WebCore/platform/SecureTextInput.cpp +++ b/Source/WebCore/platform/SecureTextInput.cpp @@ -10,49 +10,34 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" + +// FIXME: This should be moved to WebKit, because browser process needs to track secure input state anyway to manipulate input contexts. +#if PLATFORM(CHROMIUM) && OS(DARWIN) #include "SecureTextInput.h" -#if USE(CARBON_SECURE_INPUT_MODE) #import <Carbon/Carbon.h> -#endif namespace WebCore { -#if USE(CARBON_SECURE_INPUT_MODE) - -#ifdef BUILDING_ON_TIGER -const short enableRomanKeyboardsOnly = -23; -#endif - void enableSecureTextInput() { if (IsSecureEventInputEnabled()) return; EnableSecureEventInput(); -#ifdef BUILDING_ON_TIGER - KeyScript(enableRomanKeyboardsOnly); -#else - // WebKit substitutes nil for input context when in password field, which corresponds to null TSMDocument. So, there is - // no need to call TSMGetActiveDocument(), which may return an incorrect result when selection hasn't been yet updated - // after focusing a node. - CFArrayRef inputSources = TISCreateASCIICapableInputSourceList(); - TSMSetDocumentProperty(0, kTSMDocumentEnabledInputSourcesPropertyTag, sizeof(CFArrayRef), &inputSources); - CFRelease(inputSources); -#endif } void disableSecureTextInput() @@ -60,13 +45,8 @@ void disableSecureTextInput() if (!IsSecureEventInputEnabled()) return; DisableSecureEventInput(); -#ifdef BUILDING_ON_TIGER - KeyScript(smKeyEnableKybds); -#else - TSMRemoveDocumentProperty(0, kTSMDocumentEnabledInputSourcesPropertyTag); -#endif } -#endif // USE(CARBON_SECURE_INPUT_MODE) - } // namespace WebCore + +#endif // PLATFORM(CHROMIUM) && OS(DARWIN) diff --git a/Source/WebCore/platform/SecureTextInput.h b/Source/WebCore/platform/SecureTextInput.h index c55981e..f1fc083 100644 --- a/Source/WebCore/platform/SecureTextInput.h +++ b/Source/WebCore/platform/SecureTextInput.h @@ -40,7 +40,7 @@ namespace WebCore { void enableSecureTextInput(); void disableSecureTextInput(); -#if !USE(CARBON_SECURE_INPUT_MODE) +#if !(PLATFORM(CHROMIUM) && OS(DARWIN)) inline void enableSecureTextInput() { } inline void disableSecureTextInput() { } #endif diff --git a/Source/WebCore/platform/TreeShared.h b/Source/WebCore/platform/TreeShared.h index 9e27c5e..2888ebf 100644 --- a/Source/WebCore/platform/TreeShared.h +++ b/Source/WebCore/platform/TreeShared.h @@ -109,11 +109,7 @@ public: bool m_inRemovedLastRefFunction; #endif -private: -#ifndef NDEBUG - friend void adopted<>(TreeShared<T>*); -#endif - +protected: virtual void removedLastRef() { #ifndef NDEBUG @@ -122,6 +118,11 @@ private: delete this; } +private: +#ifndef NDEBUG + friend void adopted<>(TreeShared<T>*); +#endif + int m_refCount; T* m_parent; #ifndef NDEBUG diff --git a/Source/WebCore/platform/audio/FFTFrame.cpp b/Source/WebCore/platform/audio/FFTFrame.cpp index d9979d9..fbb5dfe 100644 --- a/Source/WebCore/platform/audio/FFTFrame.cpp +++ b/Source/WebCore/platform/audio/FFTFrame.cpp @@ -32,6 +32,10 @@ #include "FFTFrame.h" +#ifndef NDEBUG +#include <stdio.h> +#endif + #include <wtf/Complex.h> #include <wtf/MathExtras.h> #include <wtf/OwnPtr.h> diff --git a/Source/WebCore/platform/audio/FFTFrameStub.cpp b/Source/WebCore/platform/audio/FFTFrameStub.cpp index c76c0e2..5494cd0 100644 --- a/Source/WebCore/platform/audio/FFTFrameStub.cpp +++ b/Source/WebCore/platform/audio/FFTFrameStub.cpp @@ -79,6 +79,10 @@ void FFTFrame::doInverseFFT(float* data) ASSERT_NOT_REACHED(); } +void FFTFrame::initialize() +{ +} + void FFTFrame::cleanup() { ASSERT_NOT_REACHED(); diff --git a/Source/WebCore/platform/audio/HRTFDatabaseLoader.cpp b/Source/WebCore/platform/audio/HRTFDatabaseLoader.cpp index 4368d22..4fcce31 100644 --- a/Source/WebCore/platform/audio/HRTFDatabaseLoader.cpp +++ b/Source/WebCore/platform/audio/HRTFDatabaseLoader.cpp @@ -120,6 +120,14 @@ bool HRTFDatabaseLoader::isLoaded() const return m_hrtfDatabase.get(); } + +void HRTFDatabaseLoader::waitForLoaderThreadCompletion() +{ + ASSERT(!isMainThread()); + ASSERT(m_databaseLoaderThread); + waitForThreadCompletion(m_databaseLoaderThread, 0); +} + HRTFDatabase* HRTFDatabaseLoader::defaultHRTFDatabase() { if (!s_loader) diff --git a/Source/WebCore/platform/audio/HRTFDatabaseLoader.h b/Source/WebCore/platform/audio/HRTFDatabaseLoader.h index 72002c5..6dc02a6 100644 --- a/Source/WebCore/platform/audio/HRTFDatabaseLoader.h +++ b/Source/WebCore/platform/audio/HRTFDatabaseLoader.h @@ -46,11 +46,18 @@ public: // Must be called from the main thread. static PassRefPtr<HRTFDatabaseLoader> createAndLoadAsynchronouslyIfNecessary(double sampleRate); + // Returns the singleton HRTFDatabaseLoader. + static HRTFDatabaseLoader* loader() { return s_loader; } + // Both constructor and destructor must be called from the main thread. ~HRTFDatabaseLoader(); // Returns true once the default database has been completely loaded. bool isLoaded() const; + + // May not be called on the main thread. + // This is so a different background thread may synchronize with the loader thread. + void waitForLoaderThreadCompletion(); HRTFDatabase* database() { return m_hrtfDatabase.get(); } diff --git a/Source/WebCore/platform/audio/SincResampler.h b/Source/WebCore/platform/audio/SincResampler.h index 92adb95..62339b3 100644 --- a/Source/WebCore/platform/audio/SincResampler.h +++ b/Source/WebCore/platform/audio/SincResampler.h @@ -40,7 +40,7 @@ public: // scaleFactor == sourceSampleRate / destinationSampleRate // kernelSize can be adjusted for quality (higher is better) // numberOfKernelOffsets is used for interpolation and is the number of sub-sample kernel shifts. - SincResampler(double scaleFactor, unsigned kernelSize = 64, unsigned numberOfKernelOffsets = 32); + SincResampler(double scaleFactor, unsigned kernelSize = 32, unsigned numberOfKernelOffsets = 32); // Processes numberOfSourceFrames from source to produce numberOfSourceFrames / scaleFactor frames in destination. void process(float* source, float* destination, unsigned numberOfSourceFrames); diff --git a/Source/WebCore/platform/audio/fftw/FFTFrameFFTW.cpp b/Source/WebCore/platform/audio/fftw/FFTFrameFFTW.cpp index 878ed9f..1a344a6 100644 --- a/Source/WebCore/platform/audio/fftw/FFTFrameFFTW.cpp +++ b/Source/WebCore/platform/audio/fftw/FFTFrameFFTW.cpp @@ -29,6 +29,8 @@ #if ENABLE(WEB_AUDIO) +#if !OS(DARWIN) && USE(WEBAUDIO_FFTW) + #include "FFTFrame.h" #include <wtf/MathExtras.h> @@ -298,4 +300,6 @@ fftwf_plan FFTFrame::fftwPlanForSize(unsigned fftSize, Direction direction, } // namespace WebCore +#endif // !OS(DARWIN) && USE(WEBAUDIO_FFTW) + #endif // ENABLE(WEB_AUDIO) diff --git a/Source/WebCore/platform/audio/mkl/FFTFrameMKL.cpp b/Source/WebCore/platform/audio/mkl/FFTFrameMKL.cpp index 3ac6b36..6bf2c1e 100644 --- a/Source/WebCore/platform/audio/mkl/FFTFrameMKL.cpp +++ b/Source/WebCore/platform/audio/mkl/FFTFrameMKL.cpp @@ -30,6 +30,8 @@ #if ENABLE(WEB_AUDIO) +#if !OS(DARWIN) && USE(WEBAUDIO_MKL) + #include "FFTFrame.h" #include "mkl_vml.h" @@ -172,7 +174,7 @@ void FFTFrame::doFFT(float* data) { // Compute Forward transform. MKL_LONG status = DftiComputeForward(m_handle, data, m_complexData.data()); - ASSERT(DftiErrorClass(status, DFTI_NO_ERROR)); + ASSERT_UNUSED(status, DftiErrorClass(status, DFTI_NO_ERROR)); // De-interleave to separate real and complex arrays. FIXME: // figure out if it's possible to get MKL to use split-complex @@ -197,7 +199,7 @@ void FFTFrame::doInverseFFT(float* data) // Compute backward transform. MKL_LONG status = DftiComputeBackward(m_handle, interleavedData, data); - ASSERT(DftiErrorClass(status, DFTI_NO_ERROR)); + ASSERT_UNUSED(status, DftiErrorClass(status, DFTI_NO_ERROR)); } void FFTFrame::initialize() @@ -212,7 +214,7 @@ void FFTFrame::cleanup() for (int i = 0; i < kMaxFFTPow2Size; ++i) { if (descriptorHandles[i]) { MKL_LONG status = DftiFreeDescriptor(&descriptorHandles[i]); - ASSERT(DftiErrorClass(status, DFTI_NO_ERROR)); + ASSERT_UNUSED(status, DftiErrorClass(status, DFTI_NO_ERROR)); } } @@ -261,4 +263,6 @@ DFTI_DESCRIPTOR_HANDLE FFTFrame::descriptorHandleForSize(unsigned fftSize) } // namespace WebCore +#endif // !OS(DARWIN) && USE(WEBAUDIO_MKL) + #endif // ENABLE(WEB_AUDIO) diff --git a/Source/WebCore/platform/chromium/ClipboardMimeTypes.cpp b/Source/WebCore/platform/chromium/ClipboardMimeTypes.cpp index 27e68ff..94ce27d 100644 --- a/Source/WebCore/platform/chromium/ClipboardMimeTypes.cpp +++ b/Source/WebCore/platform/chromium/ClipboardMimeTypes.cpp @@ -41,5 +41,6 @@ const char mimeTypeURL[] = "url"; const char mimeTypeTextURIList[] = "text/uri-list"; const char mimeTypeDownloadURL[] = "downloadurl"; const char mimeTypeFiles[] = "Files"; +const char mimeTypeImagePng[] = "image/png"; } // namespace WebCore diff --git a/Source/WebCore/platform/chromium/ClipboardMimeTypes.h b/Source/WebCore/platform/chromium/ClipboardMimeTypes.h index 31e2d3e..3e4ab50 100644 --- a/Source/WebCore/platform/chromium/ClipboardMimeTypes.h +++ b/Source/WebCore/platform/chromium/ClipboardMimeTypes.h @@ -41,6 +41,7 @@ extern const char mimeTypeURL[]; extern const char mimeTypeTextURIList[]; extern const char mimeTypeDownloadURL[]; extern const char mimeTypeFiles[]; +extern const char mimeTypeImagePng[]; } // namespace WebCore diff --git a/Source/WebCore/platform/chromium/DataTransferItemChromium.cpp b/Source/WebCore/platform/chromium/DataTransferItemChromium.cpp index 7857336..24b498e 100644 --- a/Source/WebCore/platform/chromium/DataTransferItemChromium.cpp +++ b/Source/WebCore/platform/chromium/DataTransferItemChromium.cpp @@ -33,9 +33,11 @@ #if ENABLE(DATA_TRANSFER_ITEMS) +#include "Blob.h" #include "Clipboard.h" #include "ClipboardMimeTypes.h" #include "PlatformBridge.h" +#include "SharedBuffer.h" #include "StringCallback.h" namespace WebCore { @@ -88,6 +90,8 @@ void DataTransferItemChromium::getAsString(PassRefPtr<StringCallback> callback) callback->scheduleCallback(m_context, m_data); return; } + + ASSERT(m_source == PasteboardSource); // This is ugly but there's no real alternative. if (m_type == mimeTypeTextPlain) { callback->scheduleCallback(m_context, PlatformBridge::clipboardReadPlainText(PasteboardPrivate::StandardBuffer)); @@ -103,6 +107,33 @@ void DataTransferItemChromium::getAsString(PassRefPtr<StringCallback> callback) ASSERT_NOT_REACHED(); } +PassRefPtr<Blob> DataTransferItemChromium::getAsFile() +{ + if (m_source == InternalSource) + return 0; + + ASSERT(m_source == PasteboardSource); + if (m_type == mimeTypeImagePng) { + // FIXME: This is pretty inefficient. We copy the data from the browser + // to the renderer. We then place it in a blob in WebKit, which + // registers it and copies it *back* to the browser. When a consumer + // wants to read the data, we then copy the data back into the renderer. + // https://bugs.webkit.org/show_bug.cgi?id=58107 has been filed to track + // improvements to this code (in particular, add a registerClipboardBlob + // method to the blob registry; that way the data is only copied over + // into the renderer when it's actually read, not when the blob is + // initially constructed). + RefPtr<SharedBuffer> data = PlatformBridge::clipboardReadImage(PasteboardPrivate::StandardBuffer); + RefPtr<RawData> rawData = RawData::create(); + rawData->mutableData()->append(data->data(), data->size()); + OwnPtr<BlobData> blobData = BlobData::create(); + blobData->appendData(rawData, 0, -1); + blobData->setContentType(mimeTypeImagePng); + return Blob::create(blobData.release(), data->size()); + } + return 0; +} + } // namespace WebCore #endif // ENABLE(DATA_TRANSFER_ITEMS) diff --git a/Source/WebCore/platform/chromium/DataTransferItemChromium.h b/Source/WebCore/platform/chromium/DataTransferItemChromium.h index 77f74f2..66be96e 100644 --- a/Source/WebCore/platform/chromium/DataTransferItemChromium.h +++ b/Source/WebCore/platform/chromium/DataTransferItemChromium.h @@ -51,6 +51,7 @@ public: virtual String type() const; virtual void getAsString(PassRefPtr<StringCallback>); + virtual PassRefPtr<Blob> getAsFile(); private: enum DataSource { diff --git a/Source/WebCore/platform/chromium/PlatformBridge.h b/Source/WebCore/platform/chromium/PlatformBridge.h index 1c3ccbd..3a04617 100644 --- a/Source/WebCore/platform/chromium/PlatformBridge.h +++ b/Source/WebCore/platform/chromium/PlatformBridge.h @@ -98,6 +98,7 @@ public: static String clipboardReadPlainText(PasteboardPrivate::ClipboardBuffer); static void clipboardReadHTML(PasteboardPrivate::ClipboardBuffer, String*, KURL*); + static PassRefPtr<SharedBuffer> clipboardReadImage(PasteboardPrivate::ClipboardBuffer); // Only the clipboardRead functions take a buffer argument because // Chromium currently uses a different technique to write to alternate diff --git a/Source/WebCore/platform/chromium/PopupMenuChromium.cpp b/Source/WebCore/platform/chromium/PopupMenuChromium.cpp index e83ebe4..af97ecf 100644 --- a/Source/WebCore/platform/chromium/PopupMenuChromium.cpp +++ b/Source/WebCore/platform/chromium/PopupMenuChromium.cpp @@ -571,10 +571,10 @@ void PopupContainer::refresh(const IntRect& targetControlRect) location.move(0, targetControlRect.height()); listBox()->updateFromElement(); - // Store the original height to check if we need to request the location. - int originalHeight = height(); + // Store the original size to check if we need to request the location. + IntSize originalSize = size(); IntRect widgetRect = layoutAndCalculateWidgetRect(targetControlRect.height(), location); - if (originalHeight != widgetRect.height()) + if (originalSize != widgetRect.size()) setFrameRect(widgetRect); invalidate(); diff --git a/Source/WebCore/platform/efl/RenderThemeEfl.cpp b/Source/WebCore/platform/efl/RenderThemeEfl.cpp index 439e377..3ce50e3 100644 --- a/Source/WebCore/platform/efl/RenderThemeEfl.cpp +++ b/Source/WebCore/platform/efl/RenderThemeEfl.cpp @@ -34,6 +34,7 @@ #include "NotImplemented.h" #include "PaintInfo.h" #include "Page.h" +#include "PlatformContextCairo.h" #include "RenderBox.h" #include "RenderObject.h" #include "RenderProgress.h" @@ -605,6 +606,8 @@ const char* RenderThemeEfl::edjeGroupFromFormType(FormType type) const #if ENABLE(VIDEO) W("mediacontrol/playpause_button"), W("mediacontrol/mute_button"), + W("mediacontrol/seekforward_button"), + W("mediacontrol/seekbackward_button"), #endif #undef W 0 @@ -1075,7 +1078,11 @@ bool RenderThemeEfl::emitMediaButtonSignal(FormType formType, MediaControlElemen edje_object_signal_emit(entry->o, "mute", ""); else if (mediaElementType == MediaUnMuteButton) edje_object_signal_emit(entry->o, "sound", ""); - else + else if (mediaElementType == MediaSeekForwardButton) + edje_object_signal_emit(entry->o, "seekforward", ""); + else if (mediaElementType == MediaSeekBackButton) + edje_object_signal_emit(entry->o, "seekbackward", ""); + else return false; return true; @@ -1106,35 +1113,49 @@ bool RenderThemeEfl::paintMediaMuteButton(RenderObject* object, const PaintInfo& HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode); - if (!emitMediaButtonSignal(MediaMuteUnMuteButton, mediaElement->muted() ? MediaMuteButton : MediaUnMuteButton, rect)) + if (!emitMediaButtonSignal(MuteUnMuteButton, mediaElement->muted() ? MediaMuteButton : MediaUnMuteButton, rect)) return false; - return paintThemePart(object, MediaMuteUnMuteButton, info, rect); + return paintThemePart(object, MuteUnMuteButton, info, rect); } bool RenderThemeEfl::paintMediaPlayButton(RenderObject* object, const PaintInfo& info, const IntRect& rect) { Node* node = object->node(); - if (!node) + if (!node || !node->isMediaControlElement()) return false; MediaControlPlayButtonElement* button = static_cast<MediaControlPlayButtonElement*>(node); - if (!emitMediaButtonSignal(MediaPlayPauseButton, button->displayType(), rect)) + if (!emitMediaButtonSignal(PlayPauseButton, button->displayType(), rect)) return false; - return paintThemePart(object, MediaPlayPauseButton, info, rect); + return paintThemePart(object, PlayPauseButton, info, rect); } bool RenderThemeEfl::paintMediaSeekBackButton(RenderObject* object, const PaintInfo& info, const IntRect& rect) { - notImplemented(); - return false; + Node* node = object->node(); + if (!node || !node->isMediaControlElement()) + return 0; + + MediaControlSeekButtonElement* button = static_cast<MediaControlSeekButtonElement*>(node); + if (!emitMediaButtonSignal(SeekBackwardButton, button->displayType(), rect)) + return false; + + return paintThemePart(object, SeekBackwardButton, info, rect); } bool RenderThemeEfl::paintMediaSeekForwardButton(RenderObject* object, const PaintInfo& info, const IntRect& rect) { - notImplemented(); - return false; + Node* node = object->node(); + if (!node || !node->isMediaControlElement()) + return 0; + + MediaControlSeekButtonElement* button = static_cast<MediaControlSeekButtonElement*>(node); + if (!emitMediaButtonSignal(SeekForwardButton, button->displayType(), rect)) + return false; + + return paintThemePart(object, SeekForwardButton, info, rect); } bool RenderThemeEfl::paintMediaSliderTrack(RenderObject* object, const PaintInfo& info, const IntRect& rect) diff --git a/Source/WebCore/platform/efl/RenderThemeEfl.h b/Source/WebCore/platform/efl/RenderThemeEfl.h index fe8e2d2..054f91d 100644 --- a/Source/WebCore/platform/efl/RenderThemeEfl.h +++ b/Source/WebCore/platform/efl/RenderThemeEfl.h @@ -59,8 +59,10 @@ enum FormType { // KEEP IN SYNC WITH edjeGroupFromFormType() SliderVertical, SliderHorizontal, #if ENABLE(VIDEO) - MediaPlayPauseButton, - MediaMuteUnMuteButton, + PlayPauseButton, + MuteUnMuteButton, + SeekForwardButton, + SeekBackwardButton, #endif FormTypeLast }; diff --git a/Source/WebCore/platform/graphics/ANGLEWebKitBridge.h b/Source/WebCore/platform/graphics/ANGLEWebKitBridge.h index 7bddbf4..a9d2238 100644 --- a/Source/WebCore/platform/graphics/ANGLEWebKitBridge.h +++ b/Source/WebCore/platform/graphics/ANGLEWebKitBridge.h @@ -26,11 +26,15 @@ #ifndef ANGLEWebKitBridge_h #define ANGLEWebKitBridge_h -#include "ANGLE/ShaderLang.h" #include "PlatformString.h" - #include <wtf/text/CString.h> +#if !PLATFORM(GTK) +#include "ANGLE/ShaderLang.h" +#else +#include "ShaderLang.h" +#endif + namespace WebCore { enum ANGLEShaderType { diff --git a/Source/WebCore/platform/graphics/BitmapImage.cpp b/Source/WebCore/platform/graphics/BitmapImage.cpp index 6027f34..7cdb43d 100644 --- a/Source/WebCore/platform/graphics/BitmapImage.cpp +++ b/Source/WebCore/platform/graphics/BitmapImage.cpp @@ -103,6 +103,7 @@ void BitmapImage::destroyDecodedDataIfNecessary(bool destroyAll) void BitmapImage::destroyMetadataAndNotify(int framesCleared) { m_isSolidColor = false; + m_checkedForSolidColor = false; invalidatePlatformData(); int deltaBytes = framesCleared * -frameBytes(m_size); diff --git a/Source/WebCore/platform/graphics/BitmapImage.h b/Source/WebCore/platform/graphics/BitmapImage.h index c8cf0ab..8d9cd94 100644 --- a/Source/WebCore/platform/graphics/BitmapImage.h +++ b/Source/WebCore/platform/graphics/BitmapImage.h @@ -53,11 +53,11 @@ namespace WebCore { struct FrameData; } -// This complicated-looking declaration tells the FrameData Vector that it should copy without -// invoking our constructor or destructor. This allows us to have a vector even for a struct -// that's not copyable. namespace WTF { - template<> struct VectorTraits<WebCore::FrameData> : public SimpleClassVectorTraits {}; + // FIXME: This declaration gives FrameData a default constructor that zeroes + // all its data members, even though FrameData's default constructor defined + // below does not zero all its data members. One of these must be wrong! + template<> struct VectorTraits<WebCore::FrameData> : public SimpleClassVectorTraits { }; } namespace WebCore { @@ -139,8 +139,9 @@ public: virtual CFDataRef getTIFFRepresentation(); #endif -#if PLATFORM(CG) +#if USE(CG) virtual CGImageRef getCGImageRef(); + virtual CGImageRef getFirstCGImageRefOfSize(const IntSize&); #endif #if PLATFORM(WIN) || (PLATFORM(QT) && OS(WINDOWS)) @@ -160,6 +161,14 @@ public: #endif virtual NativeImagePtr nativeImageForCurrentFrame() { return frameAtIndex(currentFrame()); } + bool frameHasAlphaAtIndex(size_t); + +#if !ASSERT_DISABLED + bool notSolidColor() + { + return size().width() != 1 || size().height() != 1 || frameCount() > 1; + } +#endif protected: enum RepetitionCountStatus { @@ -190,7 +199,6 @@ protected: NativeImagePtr frameAtIndex(size_t); bool frameIsCompleteAtIndex(size_t); float frameDurationAtIndex(size_t); - bool frameHasAlphaAtIndex(size_t); // Decodes and caches a frame. Never accessed except internally. void cacheFrame(size_t index); diff --git a/Source/WebCore/platform/graphics/Color.h b/Source/WebCore/platform/graphics/Color.h index 05d9554..02ec005 100644 --- a/Source/WebCore/platform/graphics/Color.h +++ b/Source/WebCore/platform/graphics/Color.h @@ -30,7 +30,7 @@ #include <wtf/Forward.h> #include <wtf/unicode/Unicode.h> -#if PLATFORM(CG) +#if USE(CG) #include "ColorSpace.h" typedef struct CGColor* CGColorRef; #endif @@ -143,7 +143,7 @@ public: operator wxColour() const; #endif -#if PLATFORM(CG) +#if USE(CG) Color(CGColorRef); #endif @@ -191,7 +191,7 @@ inline bool operator!=(const Color& a, const Color& b) Color colorFromPremultipliedARGB(unsigned); unsigned premultipliedARGBFromColor(const Color&); -#if PLATFORM(CG) +#if USE(CG) CGColorRef cachedCGColor(const Color&, ColorSpace); #endif diff --git a/Source/WebCore/platform/graphics/ContextShadow.h b/Source/WebCore/platform/graphics/ContextShadow.h index 850d489..87acee0 100644 --- a/Source/WebCore/platform/graphics/ContextShadow.h +++ b/Source/WebCore/platform/graphics/ContextShadow.h @@ -34,7 +34,7 @@ #include "IntRect.h" #include <wtf/RefCounted.h> -#if PLATFORM(CAIRO) +#if USE(CAIRO) typedef struct _cairo cairo_t; typedef struct _cairo_surface cairo_surface_t; #elif PLATFORM(QT) @@ -49,7 +49,7 @@ namespace WebCore { class AffineTransform; class GraphicsContext; -#if PLATFORM(CAIRO) +#if USE(CAIRO) typedef cairo_surface_t* PlatformImage; typedef cairo_t* PlatformContext; #elif PLATFORM(QT) @@ -116,7 +116,7 @@ public: void setShadowsIgnoreTransforms(bool enable) { m_shadowsIgnoreTransforms = enable; } bool shadowsIgnoreTransforms() const { return m_shadowsIgnoreTransforms; } -#if PLATFORM(CAIRO) +#if USE(CAIRO) void drawRectShadow(GraphicsContext* context, const IntRect& rect, const IntSize& topLeftRadius = IntSize(), const IntSize& topRightRadius = IntSize(), const IntSize& bottomLeftRadius = IntSize(), const IntSize& bottomRightRadius = IntSize()); #endif #if PLATFORM(QT) @@ -135,7 +135,7 @@ private: void blurLayerImage(unsigned char*, const IntSize& imageSize, int stride); IntRect calculateLayerBoundingRect(GraphicsContext*, const FloatRect& layerArea, const IntRect& clipRect); -#if PLATFORM(CAIRO) +#if USE(CAIRO) void drawRectShadowWithoutTiling(GraphicsContext*, const IntRect& shadowRect, const IntSize& topLeftRadius, const IntSize& topRightRadius, const IntSize& bottomLeftRadius, const IntSize& bottomRightRadius, float alpha); #endif }; diff --git a/Source/WebCore/platform/graphics/DashArray.h b/Source/WebCore/platform/graphics/DashArray.h index 46b84a4..0516584 100644 --- a/Source/WebCore/platform/graphics/DashArray.h +++ b/Source/WebCore/platform/graphics/DashArray.h @@ -28,9 +28,9 @@ #include <wtf/Vector.h> -#if PLATFORM(CG) +#if USE(CG) typedef Vector<CGFloat> DashArray; -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) typedef Vector<double> DashArray; #else typedef Vector<float> DashArray; diff --git a/Source/WebCore/platform/graphics/Extensions3D.h b/Source/WebCore/platform/graphics/Extensions3D.h index 5d5a5b7..fee1133 100644 --- a/Source/WebCore/platform/graphics/Extensions3D.h +++ b/Source/WebCore/platform/graphics/Extensions3D.h @@ -66,6 +66,11 @@ public: // extension names for which supports returns true. virtual void ensureEnabled(const String&) = 0; + // Takes full name of extension: for example, "GL_EXT_texture_format_BGRA8888". + // Checks to see whether the given extension is actually enabled (see ensureEnabled). + // Has no other side-effects. + virtual bool isEnabled(const String&) = 0; + enum ExtensionsEnumType { // GL_EXT_texture_format_BGRA8888 enums BGRA_EXT = 0x80E1, diff --git a/Source/WebCore/platform/graphics/FloatPoint.cpp b/Source/WebCore/platform/graphics/FloatPoint.cpp index 226ae71..abe9b86 100644 --- a/Source/WebCore/platform/graphics/FloatPoint.cpp +++ b/Source/WebCore/platform/graphics/FloatPoint.cpp @@ -31,6 +31,7 @@ #include "TransformationMatrix.h" #include "FloatConversion.h" #include "IntPoint.h" +#include <limits> #include <math.h> namespace WebCore { @@ -73,4 +74,43 @@ FloatPoint FloatPoint::narrowPrecision(double x, double y) return FloatPoint(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)); } +float findSlope(const FloatPoint& p1, const FloatPoint& p2, float& c) +{ + if (p2.x() == p1.x()) + return std::numeric_limits<float>::infinity(); + + // y = mx + c + float slope = (p2.y() - p1.y()) / (p2.x() - p1.x()); + c = p1.y() - slope * p1.x(); + return slope; +} + +bool findIntersection(const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& d1, const FloatPoint& d2, FloatPoint& intersection) +{ + float pOffset = 0; + float pSlope = findSlope(p1, p2, pOffset); + + float dOffset = 0; + float dSlope = findSlope(d1, d2, dOffset); + + if (dSlope == pSlope) + return false; + + if (pSlope == std::numeric_limits<float>::infinity()) { + intersection.setX(p1.x()); + intersection.setY(dSlope * intersection.x() + dOffset); + return true; + } + if (dSlope == std::numeric_limits<float>::infinity()) { + intersection.setX(d1.x()); + intersection.setY(pSlope * intersection.x() + pOffset); + return true; + } + + // Find x at intersection, where ys overlap; x = (c' - c) / (m - m') + intersection.setX((dOffset - pOffset) / (pSlope - dSlope)); + intersection.setY(pSlope * intersection.x() + pOffset); + return true; +} + } diff --git a/Source/WebCore/platform/graphics/FloatPoint.h b/Source/WebCore/platform/graphics/FloatPoint.h index c4b2943..fd73c69 100644 --- a/Source/WebCore/platform/graphics/FloatPoint.h +++ b/Source/WebCore/platform/graphics/FloatPoint.h @@ -31,7 +31,7 @@ #include "IntPoint.h" #include <wtf/MathExtras.h> -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) typedef struct CGPoint CGPoint; #endif @@ -109,7 +109,7 @@ public: return m_x * m_x + m_y * m_y; } -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) FloatPoint(const CGPoint&); operator CGPoint() const; #endif @@ -202,6 +202,11 @@ inline IntPoint roundedIntPoint(const FloatPoint& p) return IntPoint(static_cast<int>(roundf(p.x())), static_cast<int>(roundf(p.y()))); } +float findSlope(const FloatPoint& p1, const FloatPoint& p2, float& c); + +// Find point where lines through the two pairs of points intersect. Returns false if the lines don't intersect. +bool findIntersection(const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& d1, const FloatPoint& d2, FloatPoint& intersection); + } #endif diff --git a/Source/WebCore/platform/graphics/FloatRect.cpp b/Source/WebCore/platform/graphics/FloatRect.cpp index 36f3d3a..165ef76 100644 --- a/Source/WebCore/platform/graphics/FloatRect.cpp +++ b/Source/WebCore/platform/graphics/FloatRect.cpp @@ -30,8 +30,8 @@ #include "FloatConversion.h" #include "IntRect.h" #include <algorithm> -#include <limits> #include <math.h> +#include <wtf/MathExtras.h> using std::max; using std::min; @@ -97,6 +97,24 @@ void FloatRect::unite(const FloatRect& other) setLocationAndSizeFromEdges(l, t, r, b); } +void FloatRect::uniteIfNonZero(const FloatRect& other) +{ + // Handle empty special cases first. + if (!other.width() && !other.height()) + return; + if (!width() && !height()) { + *this = other; + return; + } + + float left = min(x(), other.x()); + float top = min(y(), other.y()); + float right = max(maxX(), other.maxX()); + float bottom = max(maxY(), other.maxY()); + + setLocationAndSizeFromEdges(left, top, right, bottom); +} + void FloatRect::scale(float sx, float sy) { m_location.setX(x() * sx); @@ -182,6 +200,7 @@ IntRect enclosingIntRect(const FloatRect& rect) float top = floorf(rect.y()); float width = ceilf(rect.maxX()) - left; float height = ceilf(rect.maxY()) - top; + return IntRect(safeFloatToInt(left), safeFloatToInt(top), safeFloatToInt(width), safeFloatToInt(height)); } diff --git a/Source/WebCore/platform/graphics/FloatRect.h b/Source/WebCore/platform/graphics/FloatRect.h index bd23476..493c068 100644 --- a/Source/WebCore/platform/graphics/FloatRect.h +++ b/Source/WebCore/platform/graphics/FloatRect.h @@ -29,7 +29,7 @@ #include "FloatPoint.h" -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) typedef struct CGRect CGRect; #endif @@ -59,7 +59,7 @@ class BRect; struct SkRect; #endif -#if PLATFORM(CAIRO) +#if USE(CAIRO) typedef struct _cairo_rectangle cairo_rectangle_t; #endif @@ -112,6 +112,7 @@ public: void intersect(const FloatRect&); void unite(const FloatRect&); + void uniteIfNonZero(const FloatRect&); // Note, this doesn't match what IntRect::contains(IntPoint&) does; the int version // is really checking for containment of 1x1 rect, but that doesn't make sense with floats. @@ -136,7 +137,7 @@ public: void fitToPoints(const FloatPoint& p0, const FloatPoint& p1, const FloatPoint& p2); void fitToPoints(const FloatPoint& p0, const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& p3); -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) FloatRect(const CGRect&); operator CGRect() const; #endif @@ -172,7 +173,7 @@ public: operator VGRect() const; #endif -#if PLATFORM(CAIRO) +#if USE(CAIRO) FloatRect(const cairo_rectangle_t&); operator cairo_rectangle_t() const; #endif diff --git a/Source/WebCore/platform/graphics/FloatSize.h b/Source/WebCore/platform/graphics/FloatSize.h index 160fc9a..1485c71 100644 --- a/Source/WebCore/platform/graphics/FloatSize.h +++ b/Source/WebCore/platform/graphics/FloatSize.h @@ -31,7 +31,7 @@ #include "IntSize.h" #include <wtf/MathExtras.h> -#if PLATFORM(CG) || (PLATFORM(WX) && OS(DARWIN)) +#if USE(CG) || (PLATFORM(WX) && OS(DARWIN)) || USE(SKIA_ON_MAC_CHROME) typedef struct CGSize CGSize; #endif @@ -89,7 +89,7 @@ public: return m_width * m_width + m_height * m_height; } -#if PLATFORM(CG) || (PLATFORM(WX) && OS(DARWIN)) +#if USE(CG) || (PLATFORM(WX) && OS(DARWIN)) || USE(SKIA_ON_MAC_CHROME) explicit FloatSize(const CGSize&); // don't do this implicitly since it's lossy operator CGSize() const; #endif @@ -148,6 +148,11 @@ inline IntSize roundedIntSize(const FloatSize& p) return IntSize(static_cast<int>(roundf(p.width())), static_cast<int>(roundf(p.height()))); } +inline IntSize expandedIntSize(const FloatSize& p) +{ + return IntSize(clampToInteger(ceilf(p.width())), clampToInteger(ceilf(p.height()))); +} + } // namespace WebCore #endif // FloatSize_h diff --git a/Source/WebCore/platform/graphics/Font.h b/Source/WebCore/platform/graphics/Font.h index 554f8a0..beafdc7 100644 --- a/Source/WebCore/platform/graphics/Font.h +++ b/Source/WebCore/platform/graphics/Font.h @@ -203,7 +203,8 @@ public: FontSelector* fontSelector() const; static bool treatAsSpace(UChar c) { return c == ' ' || c == '\t' || c == '\n' || c == noBreakSpace; } - static bool treatAsZeroWidthSpace(UChar c) { return c < 0x20 || (c >= 0x7F && c < 0xA0) || c == softHyphen || (c >= 0x200c && c <= 0x200f) || (c >= 0x202a && c <= 0x202e) || c == objectReplacementCharacter; } + static bool treatAsZeroWidthSpace(UChar c) { return treatAsZeroWidthSpaceInComplexScript(c) || c == 0x200c || c == 0x200d; } + static bool treatAsZeroWidthSpaceInComplexScript(UChar c) { return c < 0x20 || (c >= 0x7F && c < 0xA0) || c == softHyphen || (c >= 0x200e && c <= 0x200f) || (c >= 0x202a && c <= 0x202e) || c == zeroWidthNoBreakSpace || c == objectReplacementCharacter; } static bool canReceiveTextEmphasis(UChar32 c); static inline UChar normalizeSpaces(UChar character) diff --git a/Source/WebCore/platform/graphics/FontCache.cpp b/Source/WebCore/platform/graphics/FontCache.cpp index 8c5edfe..d64878b 100644 --- a/Source/WebCore/platform/graphics/FontCache.cpp +++ b/Source/WebCore/platform/graphics/FontCache.cpp @@ -121,22 +121,7 @@ struct FontPlatformDataCacheKeyHash { static const bool safeToCompareToEmptyOrDeleted = true; }; -struct FontPlatformDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformDataCacheKey> { - static const bool emptyValueIsZero = true; - static const FontPlatformDataCacheKey& emptyValue() - { - DEFINE_STATIC_LOCAL(FontPlatformDataCacheKey, key, (nullAtom)); - return key; - } - static void constructDeletedValue(FontPlatformDataCacheKey& slot) - { - new (&slot) FontPlatformDataCacheKey(HashTableDeletedValue); - } - static bool isDeletedValue(const FontPlatformDataCacheKey& value) - { - return value.isHashTableDeletedValue(); - } -}; +struct FontPlatformDataCacheKeyTraits : WTF::SimpleClassHashTraits<FontPlatformDataCacheKey> { }; typedef HashMap<FontPlatformDataCacheKey, FontPlatformData*, FontPlatformDataCacheKeyHash, FontPlatformDataCacheKeyTraits> FontPlatformDataCache; diff --git a/Source/WebCore/platform/graphics/FontMetrics.h b/Source/WebCore/platform/graphics/FontMetrics.h index 89c5545..367f004 100644 --- a/Source/WebCore/platform/graphics/FontMetrics.h +++ b/Source/WebCore/platform/graphics/FontMetrics.h @@ -96,6 +96,11 @@ public: int lineGap() const { return lroundf(m_lineGap); } int lineSpacing() const { return lroundf(m_lineSpacing); } + bool hasIdenticalAscentDescentAndLineGap(const FontMetrics& other) const + { + return ascent() == other.ascent() && descent() == other.descent() && lineGap() == other.lineGap(); + } + private: friend class SimpleFontData; diff --git a/Source/WebCore/platform/graphics/FontPlatformData.h b/Source/WebCore/platform/graphics/FontPlatformData.h index 5981c16..a32215d 100644 --- a/Source/WebCore/platform/graphics/FontPlatformData.h +++ b/Source/WebCore/platform/graphics/FontPlatformData.h @@ -51,7 +51,7 @@ #include "RefCountedGDIHandle.h" #endif -#if PLATFORM(CAIRO) +#if USE(CAIRO) #include "HashFunctions.h" #include <cairo.h> #endif @@ -86,7 +86,7 @@ typedef const struct __CTFont* CTFontRef; typedef struct HFONT__* HFONT; #endif -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) typedef struct CGFont* CGFontRef; #if OS(DARWIN) #ifndef BUILDING_ON_TIGER @@ -119,9 +119,9 @@ public: #elif OS(DARWIN) , m_font(hashTableDeletedFontValue()) #endif -#if PLATFORM(CG) && (defined(BUILDING_ON_TIGER) || PLATFORM(WIN)) +#if USE(CG) && (defined(BUILDING_ON_TIGER) || PLATFORM(WIN)) , m_cgFont(0) -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) , m_scaledFont(hashTableDeletedFontValue()) #endif , m_isColorBitmapFont(false) @@ -141,9 +141,9 @@ public: #if OS(DARWIN) , m_font(0) #endif -#if PLATFORM(CG) && (defined(BUILDING_ON_TIGER) || PLATFORM(WIN)) +#if USE(CG) && (defined(BUILDING_ON_TIGER) || PLATFORM(WIN)) , m_cgFont(0) -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) , m_scaledFont(0) #endif , m_isColorBitmapFont(false) @@ -166,9 +166,9 @@ public: #if OS(DARWIN) , m_font(0) #endif -#if PLATFORM(CG) && (defined(BUILDING_ON_TIGER) || PLATFORM(WIN)) +#if USE(CG) && (defined(BUILDING_ON_TIGER) || PLATFORM(WIN)) , m_cgFont(0) -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) , m_scaledFont(0) #endif , m_isColorBitmapFont(false) @@ -181,6 +181,7 @@ public: #if OS(DARWIN) FontPlatformData(NSFont*, float size, bool syntheticBold = false, bool syntheticOblique = false, FontOrientation = Horizontal, TextOrientation = TextOrientationVerticalRight, FontWidthVariant = RegularWidth); +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) FontPlatformData(CGFontRef cgFont, float size, bool syntheticBold, bool syntheticOblique, FontOrientation orientation, TextOrientation textOrientation, FontWidthVariant widthVariant) : m_syntheticBold(syntheticBold) @@ -195,13 +196,14 @@ public: { } #endif +#endif #if PLATFORM(WIN) FontPlatformData(HFONT, float size, bool syntheticBold, bool syntheticOblique, bool useGDI); -#if PLATFORM(CG) +#if USE(CG) FontPlatformData(HFONT, CGFontRef, float size, bool syntheticBold, bool syntheticOblique, bool useGDI); #endif #endif -#if PLATFORM(CAIRO) +#if USE(CAIRO) FontPlatformData(cairo_font_face_t*, float size, bool bold, bool italic); #endif @@ -215,7 +217,7 @@ public: void setFont(NSFont*); #endif -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) #if OS(DARWIN) #ifndef BUILDING_ON_TIGER CGFontRef cgFont() const { return m_cgFont.get(); } @@ -243,19 +245,21 @@ public: void setOrientation(FontOrientation orientation) { m_orientation = orientation; } -#if PLATFORM(CAIRO) +#if USE(CAIRO) cairo_scaled_font_t* scaledFont() const { return m_scaledFont; } #endif unsigned hash() const { -#if PLATFORM(WIN) && !PLATFORM(CAIRO) +#if PLATFORM(WIN) && !USE(CAIRO) return m_font ? m_font->hash() : 0; #elif OS(DARWIN) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) ASSERT(m_font || !m_cgFont); +#endif uintptr_t hashCodes[3] = { (uintptr_t)m_font, m_widthVariant, m_textOrientation << 3 | m_orientation << 2 | m_syntheticBold << 1 | m_syntheticOblique }; return StringHasher::hashMemory<sizeof(hashCodes)>(hashCodes); -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) return PtrHash<cairo_scaled_font_t*>::hash(m_scaledFont); #endif } @@ -276,11 +280,11 @@ public: bool isHashTableDeletedValue() const { -#if PLATFORM(WIN) && !PLATFORM(CAIRO) +#if PLATFORM(WIN) && !USE(CAIRO) return m_font.isHashTableDeletedValue(); #elif OS(DARWIN) return m_font == hashTableDeletedFontValue(); -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) return m_scaledFont == hashTableDeletedFontValue(); #endif } @@ -307,7 +311,7 @@ private: void platformDataInit(HFONT, float size, HDC, WCHAR* faceName); #endif -#if PLATFORM(CAIRO) +#if USE(CAIRO) static cairo_scaled_font_t* hashTableDeletedFontValue() { return reinterpret_cast<cairo_scaled_font_t*>(-1); } #endif @@ -326,7 +330,7 @@ private: RefPtr<RefCountedGDIHandle<HFONT> > m_font; #endif -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) #if PLATFORM(WIN) RetainPtr<CGFontRef> m_cgFont; #else @@ -339,7 +343,7 @@ private: #endif #endif -#if PLATFORM(CAIRO) +#if USE(CAIRO) cairo_scaled_font_t* m_scaledFont; #endif diff --git a/Source/WebCore/platform/graphics/FontSelector.h b/Source/WebCore/platform/graphics/FontSelector.h index 156bf10..e18161b 100644 --- a/Source/WebCore/platform/graphics/FontSelector.h +++ b/Source/WebCore/platform/graphics/FontSelector.h @@ -33,6 +33,7 @@ namespace WebCore { class FontData; class FontDescription; +class FontSelectorClient; class FontSelector : public RefCounted<FontSelector> { public: @@ -40,6 +41,16 @@ public: virtual FontData* getFontData(const FontDescription&, const AtomicString& familyName) = 0; virtual void fontCacheInvalidated() { } + + virtual void registerForInvalidationCallbacks(FontSelectorClient*) = 0; + virtual void unregisterForInvalidationCallbacks(FontSelectorClient*) = 0; +}; + +class FontSelectorClient { +public: + virtual ~FontSelectorClient() { } + + virtual void fontsNeedUpdate(FontSelector*) = 0; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/GlyphBuffer.h b/Source/WebCore/platform/graphics/GlyphBuffer.h index 7aac1e3..f5216a9 100644 --- a/Source/WebCore/platform/graphics/GlyphBuffer.h +++ b/Source/WebCore/platform/graphics/GlyphBuffer.h @@ -34,11 +34,11 @@ #include <wtf/UnusedParam.h> #include <wtf/Vector.h> -#if PLATFORM(CG) || (PLATFORM(WX) && OS(DARWIN)) +#if USE(CG) || (PLATFORM(WX) && OS(DARWIN)) || USE(SKIA_ON_MAC_CHROME) #include <ApplicationServices/ApplicationServices.h> #endif -#if PLATFORM(CAIRO) || (PLATFORM(WX) && defined(__WXGTK__)) +#if USE(CAIRO) || (PLATFORM(WX) && defined(__WXGTK__)) #include <cairo.h> #endif @@ -47,7 +47,7 @@ namespace WebCore { typedef unsigned short Glyph; class SimpleFontData; -#if PLATFORM(CAIRO) +#if USE(CAIRO) // FIXME: Why does Cairo use such a huge struct instead of just an offset into an array? typedef cairo_glyph_t GlyphBufferGlyph; #elif OS(WINCE) @@ -58,7 +58,7 @@ typedef Glyph GlyphBufferGlyph; // CG uses CGSize instead of FloatSize so that the result of advances() // can be passed directly to CGContextShowGlyphsWithAdvances in FontMac.mm -#if PLATFORM(CG) || (PLATFORM(WX) && OS(DARWIN)) +#if USE(CG) || (PLATFORM(WX) && OS(DARWIN)) || USE(SKIA_ON_MAC_CHROME) typedef CGSize GlyphBufferAdvance; #elif OS(WINCE) // There is no cross-platform code that uses the height of GlyphBufferAdvance, @@ -113,7 +113,7 @@ public: Glyph glyphAt(int index) const { -#if PLATFORM(CAIRO) +#if USE(CAIRO) return m_glyphs[index].index; #else return m_glyphs[index]; @@ -122,7 +122,7 @@ public: float advanceAt(int index) const { -#if PLATFORM(CG) || (PLATFORM(WX) && OS(DARWIN)) +#if USE(CG) || (PLATFORM(WX) && OS(DARWIN)) || USE(SKIA_ON_MAC_CHROME) return m_advances[index].width; #elif OS(WINCE) return m_advances[index]; @@ -145,7 +145,7 @@ public: { m_fontData.append(font); -#if PLATFORM(CAIRO) +#if USE(CAIRO) cairo_glyph_t cairoGlyph; cairoGlyph.index = glyph; m_glyphs.append(cairoGlyph); @@ -153,7 +153,7 @@ public: m_glyphs.append(glyph); #endif -#if PLATFORM(CG) || (PLATFORM(WX) && OS(DARWIN)) +#if USE(CG) || (PLATFORM(WX) && OS(DARWIN)) || USE(SKIA_ON_MAC_CHROME) CGSize advance = { width, 0 }; m_advances.append(advance); #elif OS(WINCE) @@ -176,7 +176,7 @@ public: void add(Glyph glyph, const SimpleFontData* font, GlyphBufferAdvance advance) { m_fontData.append(font); -#if PLATFORM(CAIRO) +#if USE(CAIRO) cairo_glyph_t cairoGlyph; cairoGlyph.index = glyph; m_glyphs.append(cairoGlyph); @@ -192,7 +192,7 @@ public: { ASSERT(!isEmpty()); GlyphBufferAdvance& lastAdvance = m_advances.last(); -#if PLATFORM(CG) || (PLATFORM(WX) && OS(DARWIN)) +#if USE(CG) || (PLATFORM(WX) && OS(DARWIN)) || USE(SKIA_ON_MAC_CHROME) lastAdvance.width += width; #elif OS(WINCE) lastAdvance += width; diff --git a/Source/WebCore/platform/graphics/GlyphPageTreeNode.cpp b/Source/WebCore/platform/graphics/GlyphPageTreeNode.cpp index e7ed193..951cf56 100644 --- a/Source/WebCore/platform/graphics/GlyphPageTreeNode.cpp +++ b/Source/WebCore/platform/graphics/GlyphPageTreeNode.cpp @@ -191,6 +191,9 @@ void GlyphPageTreeNode::initializePage(const FontData* fontData, unsigned pageNu } else if (start == (objectReplacementCharacter & ~(GlyphPage::size - 1))) { // Object replacement character must not render at all. buffer[objectReplacementCharacter - start] = zeroWidthSpace; + } else if (start == (zeroWidthNoBreakSpace & ~(GlyphPage::size - 1))) { + // ZWNBS/BOM must not render at all. + buffer[zeroWidthNoBreakSpace - start] = zeroWidthSpace; } } else { bufferLength = GlyphPage::size * 2; diff --git a/Source/WebCore/platform/graphics/Gradient.cpp b/Source/WebCore/platform/graphics/Gradient.cpp index 783e552..4edb4bd 100644 --- a/Source/WebCore/platform/graphics/Gradient.cpp +++ b/Source/WebCore/platform/graphics/Gradient.cpp @@ -221,7 +221,11 @@ void Gradient::setGradientSpaceTransform(const AffineTransform& gradientSpaceTra setPlatformGradientSpaceTransform(gradientSpaceTransformation); } +<<<<<<< HEAD #if !(USE(SKIA) && !PLATFORM(ANDROID)) && !PLATFORM(CAIRO) +======= +#if !USE(SKIA) && !USE(CAIRO) +>>>>>>> WebKit.org at r84325 void Gradient::setPlatformGradientSpaceTransform(const AffineTransform&) { } diff --git a/Source/WebCore/platform/graphics/Gradient.h b/Source/WebCore/platform/graphics/Gradient.h index acc6125..7595896 100644 --- a/Source/WebCore/platform/graphics/Gradient.h +++ b/Source/WebCore/platform/graphics/Gradient.h @@ -35,7 +35,7 @@ #include <wtf/PassRefPtr.h> #include <wtf/Vector.h> -#if PLATFORM(CG) +#if USE(CG) typedef struct CGContext* CGContextRef; @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE class QGradient; QT_END_NAMESPACE typedef QGradient* PlatformGradient; -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) typedef struct _cairo_pattern cairo_pattern_t; typedef cairo_pattern_t* PlatformGradient; #elif USE(SKIA) @@ -146,7 +146,7 @@ namespace WebCore { void setPlatformGradientSpaceTransform(const AffineTransform& gradientSpaceTransformation); -#if PLATFORM(CG) +#if USE(CG) void paint(CGContextRef); void paint(GraphicsContext*); #endif diff --git a/Source/WebCore/platform/graphics/GraphicsContext.cpp b/Source/WebCore/platform/graphics/GraphicsContext.cpp index fa3280e..ddaf938 100644 --- a/Source/WebCore/platform/graphics/GraphicsContext.cpp +++ b/Source/WebCore/platform/graphics/GraphicsContext.cpp @@ -148,7 +148,7 @@ void GraphicsContext::setLegacyShadow(const FloatSize& offset, float blur, const m_state.shadowBlur = blur; m_state.shadowColor = color; m_state.shadowColorSpace = colorSpace; -#if PLATFORM(CG) +#if USE(CG) m_state.shadowsUseLegacyRadius = true; #endif setPlatformShadow(offset, blur, color, colorSpace); @@ -397,7 +397,11 @@ void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const F if (paintingDisabled()) return; + // FIXME: This ownership should be reversed. We should pass BidiRunList + // to BidiResolver in createBidiRunsForLine. BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver; + BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs(); + WTF::Unicode::Direction paragraphDirection = run.ltr() ? WTF::Unicode::LeftToRight : WTF::Unicode::RightToLeft; bidiResolver.setStatus(BidiStatus(paragraphDirection, paragraphDirection, paragraphDirection, BidiContext::create(run.ltr() ? 0 : 1, paragraphDirection, run.directionalOverride()))); @@ -405,11 +409,11 @@ void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const F bidiResolver.setPosition(TextRunIterator(&run, 0)); bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length())); - if (!bidiResolver.runCount()) + if (!bidiRuns.runCount()) return; FloatPoint currPoint = point; - BidiCharacterRun* bidiRun = bidiResolver.firstRun(); + BidiCharacterRun* bidiRun = bidiRuns.firstRun(); while (bidiRun) { TextRun subrun = run; @@ -425,7 +429,7 @@ void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const F currPoint.move(font.width(subrun), 0); } - bidiResolver.deleteRuns(); + bidiRuns.deleteRuns(); } void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const FloatPoint& point, int h, const Color& backgroundColor, ColorSpace colorSpace, int from, int to) @@ -563,7 +567,7 @@ void GraphicsContext::addRoundedRectClip(const RoundedIntRect& rect) return; Path path; - path.addRoundedRect(rect.rect(), rect.radii().topLeft(), rect.radii().topRight(), rect.radii().bottomLeft(), rect.radii().bottomRight()); + path.addRoundedRect(rect); clip(path); } @@ -573,7 +577,7 @@ void GraphicsContext::clipOutRoundedRect(const RoundedIntRect& rect) return; Path path; - path.addRoundedRect(rect.rect(), rect.radii().topLeft(), rect.radii().topRight(), rect.radii().bottomLeft(), rect.radii().bottomRight()); + path.addRoundedRect(rect); clipOut(path); } @@ -584,7 +588,7 @@ void GraphicsContext::clipToImageBuffer(ImageBuffer* buffer, const FloatRect& re buffer->clip(this, rect); } -#if !PLATFORM(CG) +#if !USE(CG) IntRect GraphicsContext::clipBounds() const { ASSERT_NOT_REACHED(); @@ -617,7 +621,7 @@ void GraphicsContext::fillRoundedRect(const RoundedIntRect& rect, const Color& c fillRoundedRect(rect.rect(), rect.radii().topLeft(), rect.radii().topRight(), rect.radii().bottomLeft(), rect.radii().bottomRight(), color, colorSpace); } -#if !PLATFORM(CG) +#if !USE(CG) void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const RoundedIntRect& roundedHoleRect, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) @@ -627,7 +631,7 @@ void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const Rounded path.addRect(rect); if (!roundedHoleRect.radii().isZero()) - path.addRoundedRect(roundedHoleRect.rect(), roundedHoleRect.radii().topLeft(), roundedHoleRect.radii().topRight(), roundedHoleRect.radii().bottomLeft(), roundedHoleRect.radii().bottomRight()); + path.addRoundedRect(roundedHoleRect); else path.addRect(roundedHoleRect.rect()); @@ -674,7 +678,11 @@ void GraphicsContext::setPlatformStrokePattern(Pattern*) } #endif +<<<<<<< HEAD #if !PLATFORM(CG) && !(USE(SKIA) && !PLATFORM(ANDROID)) +======= +#if !USE(CG) && !USE(SKIA) +>>>>>>> WebKit.org at r84325 // Implement this if you want to go ahead and push the drawing mode into your native context // immediately. void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode) @@ -682,13 +690,17 @@ void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode) } #endif +<<<<<<< HEAD #if !PLATFORM(QT) && !PLATFORM(CAIRO) && !(USE(SKIA) && !PLATFORM(ANDROID)) && !PLATFORM(HAIKU) && !PLATFORM(OPENVG) +======= +#if !PLATFORM(QT) && !USE(CAIRO) && !USE(SKIA) && !PLATFORM(HAIKU) && !PLATFORM(OPENVG) +>>>>>>> WebKit.org at r84325 void GraphicsContext::setPlatformStrokeStyle(StrokeStyle) { } #endif -#if !PLATFORM(CG) +#if !USE(CG) void GraphicsContext::setPlatformShouldSmoothFonts(bool) { } diff --git a/Source/WebCore/platform/graphics/GraphicsContext.h b/Source/WebCore/platform/graphics/GraphicsContext.h index c555a5f..2b41c2e 100644 --- a/Source/WebCore/platform/graphics/GraphicsContext.h +++ b/Source/WebCore/platform/graphics/GraphicsContext.h @@ -37,9 +37,9 @@ #include <wtf/Noncopyable.h> #include <wtf/PassOwnPtr.h> -#if PLATFORM(CG) +#if USE(CG) typedef struct CGContext PlatformGraphicsContext; -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) namespace WebCore { class ContextShadow; class PlatformContextCairo; @@ -99,8 +99,9 @@ typedef void PlatformGraphicsContext; #endif #if PLATFORM(WIN) +#include "DIBPixelData.h" typedef struct HDC__* HDC; -#if !PLATFORM(CG) +#if !USE(CG) // UInt8 is defined in CoreFoundation/CFBase.h typedef unsigned char UInt8; #endif @@ -161,7 +162,7 @@ namespace WebCore { GraphicsContextState() : strokeThickness(0) , shadowBlur(0) -#if PLATFORM(CAIRO) +#if USE(CAIRO) , globalAlpha(1) #endif , textDrawingMode(TextModeFill) @@ -177,7 +178,7 @@ namespace WebCore { , shouldSmoothFonts(true) , paintingDisabled(false) , shadowsIgnoreTransforms(false) -#if PLATFORM(CG) +#if USE(CG) // Core Graphics incorrectly renders shadows with radius > 8px (<rdar://problem/8103442>), // but we need to preserve this buggy behavior for canvas and -webkit-box-shadow. , shadowsUseLegacyRadius(false) @@ -196,7 +197,7 @@ namespace WebCore { float strokeThickness; float shadowBlur; -#if PLATFORM(CAIRO) +#if USE(CAIRO) float globalAlpha; #endif TextDrawingModeFlags textDrawingMode; @@ -218,7 +219,7 @@ namespace WebCore { bool shouldSmoothFonts : 1; bool paintingDisabled : 1; bool shadowsIgnoreTransforms : 1; -#if PLATFORM(CG) +#if USE(CG) bool shadowsUseLegacyRadius : 1; #endif }; @@ -270,7 +271,7 @@ namespace WebCore { const GraphicsContextState& state() const; -#if PLATFORM(CG) +#if USE(CG) void applyStrokePattern(); void applyFillPattern(); void drawPath(const Path&); @@ -383,7 +384,11 @@ namespace WebCore { void drawBidiText(const Font&, const TextRun&, const FloatPoint&); void drawHighlightForText(const Font&, const TextRun&, const FloatPoint&, int h, const Color& backgroundColor, ColorSpace, int from = 0, int to = -1); - FloatRect roundToDevicePixels(const FloatRect&); + enum RoundingMode { + RoundAllSides, + RoundOriginAndDimensions + }; + FloatRect roundToDevicePixels(const FloatRect&, RoundingMode = RoundAllSides); void drawLineForText(const FloatPoint&, float width, bool printing); enum TextCheckingLineStyle { @@ -420,7 +425,7 @@ namespace WebCore { void setMiterLimit(float); void setAlpha(float); -#if PLATFORM(CAIRO) +#if USE(CAIRO) float getAlpha(); #endif @@ -486,18 +491,17 @@ namespace WebCore { ~WindowsBitmap(); HDC hdc() const { return m_hdc; } - UInt8* buffer() const { return m_bitmapBuffer; } - unsigned bufferLength() const { return m_bitmapBufferLength; } - IntSize size() const { return m_size; } - unsigned bytesPerRow() const { return m_bytesPerRow; } + UInt8* buffer() const { return m_pixelData.buffer(); } + unsigned bufferLength() const { return m_pixelData.bufferLength(); } + const IntSize& size() const { return m_pixelData.size(); } + unsigned bytesPerRow() const { return m_pixelData.bytesPerRow(); } + unsigned short bitsPerPixel() const { return m_pixelData.bitsPerPixel(); } + const DIBPixelData& windowsDIB() const { return m_pixelData; } private: HDC m_hdc; HBITMAP m_bitmap; - UInt8* m_bitmapBuffer; - unsigned m_bitmapBufferLength; - IntSize m_size; - unsigned m_bytesPerRow; + DIBPixelData m_pixelData; }; WindowsBitmap* createWindowsBitmap(IntSize); @@ -521,13 +525,12 @@ namespace WebCore { void takeOwnershipOfPlatformContext(); #endif -#if PLATFORM(QT) || PLATFORM(CAIRO) +#if PLATFORM(QT) || USE(CAIRO) ContextShadow* contextShadow(); #endif -#if PLATFORM(CAIRO) +#if USE(CAIRO) GraphicsContext(cairo_t*); - void pushImageMask(cairo_surface_t*, const FloatRect&); #endif #if PLATFORM(GTK) diff --git a/Source/WebCore/platform/graphics/GraphicsContext3D.h b/Source/WebCore/platform/graphics/GraphicsContext3D.h index 351b445..80226cf 100644 --- a/Source/WebCore/platform/graphics/GraphicsContext3D.h +++ b/Source/WebCore/platform/graphics/GraphicsContext3D.h @@ -43,8 +43,11 @@ #undef VERSION #endif -#if PLATFORM(MAC) +#if PLATFORM(MAC) || PLATFORM(GTK) #include "ANGLEWebKitBridge.h" +#endif + +#if PLATFORM(MAC) #include <OpenGL/OpenGL.h> #include <wtf/RetainPtr.h> #ifdef __OBJC__ @@ -73,7 +76,7 @@ typedef void* PlatformGraphicsContext3D; const PlatformGraphicsContext3D NullPlatformGraphicsContext3D = 0; const Platform3DObject NullPlatform3DObject = 0; -#if PLATFORM(CG) +#if USE(CG) #include <CoreGraphics/CGContext.h> #endif @@ -81,12 +84,15 @@ namespace WebCore { class CanvasRenderingContext; class DrawingBuffer; class Extensions3D; -#if PLATFORM(MAC) +#if PLATFORM(MAC) || PLATFORM(GTK) class Extensions3DOpenGL; #endif class HostWindow; class Image; class ImageData; +#if USE(CAIRO) +class PlatformContextCairo; +#endif struct ActiveInfo { String name; @@ -95,7 +101,7 @@ struct ActiveInfo { }; // FIXME: ideally this would be used on all platforms. -#if PLATFORM(CHROMIUM) || PLATFORM(QT) +#if PLATFORM(CHROMIUM) || PLATFORM(QT) || PLATFORM(GTK) class GraphicsContext3DInternal; #endif @@ -465,6 +471,9 @@ public: #if USE(ACCELERATED_COMPOSITING) PlatformLayer* platformLayer() const; #endif +#elif PLATFORM(GTK) + PlatformGraphicsContext3D platformGraphicsContext3D(); + Platform3DObject platformTexture() const { return m_texture; } #else PlatformGraphicsContext3D platformGraphicsContext3D() const { return NullPlatformGraphicsContext3D; } Platform3DObject platformTexture() const { return NullPlatform3DObject; } @@ -476,7 +485,7 @@ public: PassRefPtr<DrawingBuffer> createDrawingBuffer(const IntSize& = IntSize()); -#if PLATFORM(MAC) || PLATFORM(CHROMIUM) +#if PLATFORM(MAC) || PLATFORM(CHROMIUM) || PLATFORM(GTK) // With multisampling on, blit from multisampleFBO to regular FBO. void prepareTexture(); #endif @@ -753,9 +762,12 @@ public: void reshape(int width, int height); -#if PLATFORM(CG) +#if USE(CG) void paintToCanvas(const unsigned char* imagePixels, int imageWidth, int imageHeight, int canvasWidth, int canvasHeight, CGContextRef context); +#elif PLATFORM(GTK) + void paintToCanvas(const unsigned char* imagePixels, int imageWidth, int imageHeight, + int canvasWidth, int canvasHeight, PlatformContextCairo* context); #endif void markContextChanged(); @@ -769,6 +781,8 @@ public: bool paintsIntoCanvasBuffer() const { return true; } #elif PLATFORM(CHROMIUM) bool paintsIntoCanvasBuffer() const; +#elif PLATFORM(GTK) + bool paintsIntoCanvasBuffer() const { return true; } #else bool paintsIntoCanvasBuffer() const { return false; } #endif @@ -859,7 +873,7 @@ public: AlphaOp alphaOp, void* destinationData); -#if PLATFORM(MAC) +#if PLATFORM(MAC) || PLATFORM(GTK) // Take into account the user's requested context creation attributes, // in particular stencil and antialias, and determine which could or // could not be honored based on the capabilities of the OpenGL @@ -874,6 +888,11 @@ public: int m_currentWidth, m_currentHeight; #if PLATFORM(MAC) + CGLContextObj m_contextObj; + RetainPtr<WebGLLayer> m_webGLLayer; +#endif + +#if PLATFORM(MAC) || PLATFORM(GTK) typedef struct { String source; String log; @@ -889,8 +908,6 @@ public: Attributes m_attrs; Vector<Vector<float> > m_vertexArray; - CGLContextObj m_contextObj; - RetainPtr<WebGLLayer> m_webGLLayer; GC3Duint m_texture, m_compositorTexture; GC3Duint m_fbo; GC3Duint m_depthStencilBuffer; @@ -912,7 +929,7 @@ public: #endif // FIXME: ideally this would be used on all platforms. -#if PLATFORM(CHROMIUM) || PLATFORM(QT) +#if PLATFORM(CHROMIUM) || PLATFORM(QT) || PLATFORM(GTK) friend class GraphicsContext3DInternal; OwnPtr<GraphicsContext3DInternal> m_internal; #endif diff --git a/Source/WebCore/platform/graphics/Image.cpp b/Source/WebCore/platform/graphics/Image.cpp index 3096680..11da0ab 100644 --- a/Source/WebCore/platform/graphics/Image.cpp +++ b/Source/WebCore/platform/graphics/Image.cpp @@ -36,7 +36,7 @@ #include <math.h> #include <wtf/StdLibExtras.h> -#if PLATFORM(CG) +#if USE(CG) #include <CoreFoundation/CoreFoundation.h> #endif diff --git a/Source/WebCore/platform/graphics/Image.h b/Source/WebCore/platform/graphics/Image.h index 3c5e7fd..834a0d3 100644 --- a/Source/WebCore/platform/graphics/Image.h +++ b/Source/WebCore/platform/graphics/Image.h @@ -45,7 +45,7 @@ class NSImage; #endif #endif -#if PLATFORM(CG) +#if USE(CG) struct CGContext; #endif @@ -136,8 +136,9 @@ public: virtual CFDataRef getTIFFRepresentation() { return 0; } #endif -#if PLATFORM(CG) +#if USE(CG) virtual CGImageRef getCGImageRef() { return 0; } + virtual CGImageRef getFirstCGImageRefOfSize(const IntSize&) { return 0; } #endif #if PLATFORM(WIN) diff --git a/Source/WebCore/platform/graphics/ImageBuffer.cpp b/Source/WebCore/platform/graphics/ImageBuffer.cpp index 4a76be4..23b925a 100644 --- a/Source/WebCore/platform/graphics/ImageBuffer.cpp +++ b/Source/WebCore/platform/graphics/ImageBuffer.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "ImageBuffer.h" -#if !PLATFORM(CG) +#if !USE(CG) #include <math.h> @@ -69,4 +69,4 @@ void ImageBuffer::transformColorSpace(ColorSpace srcColorSpace, ColorSpace dstCo } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/ImageBuffer.h b/Source/WebCore/platform/graphics/ImageBuffer.h index 860f574..c184bbe 100644 --- a/Source/WebCore/platform/graphics/ImageBuffer.h +++ b/Source/WebCore/platform/graphics/ImageBuffer.h @@ -41,10 +41,6 @@ #include <wtf/PassRefPtr.h> #include <wtf/Vector.h> -#if (PLATFORM(MAC) && PLATFORM(CA) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)) -#define WTF_USE_IOSURFACE_CANVAS_BACKING_STORE 1 -#endif - namespace WebCore { class GraphicsContext; @@ -86,6 +82,7 @@ namespace WebCore { GraphicsContext* context() const; + bool isAccelerated() const { return m_accelerateRendering; } bool drawsUsingCopy() const; // If the image buffer has to render using a copied image, it will return true. PassRefPtr<Image> copyImage() const; // Return a new image that is a copy of the buffer. @@ -96,7 +93,7 @@ namespace WebCore { void putPremultipliedImageData(ByteArray*, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint); String toDataURL(const String& mimeType, const double* quality = 0) const; -#if !PLATFORM(CG) +#if !USE(CG) AffineTransform baseTransform() const { return AffineTransform(); } void transformColorSpace(ColorSpace srcColorSpace, ColorSpace dstColorSpace); void platformTransformColorSpace(const Vector<int>&); @@ -122,7 +119,7 @@ namespace WebCore { bool m_accelerateRendering; OwnPtr<GraphicsContext> m_context; -#if !PLATFORM(CG) +#if !USE(CG) Vector<int> m_linearRgbLUT; Vector<int> m_deviceRgbLUT; #endif @@ -132,7 +129,7 @@ namespace WebCore { ImageBuffer(const IntSize&, ColorSpace colorSpace, RenderingMode renderingMode, bool& success); }; -#if PLATFORM(CG) || USE(SKIA) +#if USE(CG) || USE(SKIA) String ImageDataToDataURL(const ImageData& input, const String& mimeType, const double* quality); #endif diff --git a/Source/WebCore/platform/graphics/ImageBufferData.h b/Source/WebCore/platform/graphics/ImageBufferData.h new file mode 100644 index 0000000..670a10f --- /dev/null +++ b/Source/WebCore/platform/graphics/ImageBufferData.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if USE(CG) +#include "ImageBufferDataCG.h" +#elif USE(CAIRO) +#include "ImageBufferDataCairo.h" +#elif PLATFORM(QT) +#include "ImageBufferDataQt.h" +#elif USE(SKIA) +#include "ImageBufferDataSkia.h" +#elif PLATFORM(HAIKU) +#include "ImageBufferDataHaiku.h" +#elif OS(WINCE) +#include "ImageBufferDataWince.h" +#elif PLATFORM(WX) +#include "ImageBufferDataWx.h" +#endif diff --git a/Source/WebCore/platform/graphics/ImageSource.h b/Source/WebCore/platform/graphics/ImageSource.h index 5ece15b..8dcc9a2 100644 --- a/Source/WebCore/platform/graphics/ImageSource.h +++ b/Source/WebCore/platform/graphics/ImageSource.h @@ -34,7 +34,7 @@ #if PLATFORM(WX) class wxBitmap; class wxGraphicsBitmap; -#elif PLATFORM(CG) +#elif USE(CG) typedef struct CGImageSource* CGImageSourceRef; typedef struct CGImage* CGImageRef; typedef const struct __CFData* CFDataRef; @@ -43,7 +43,7 @@ typedef const struct __CFData* CFDataRef; QT_BEGIN_NAMESPACE class QPixmap; QT_END_NAMESPACE -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) struct _cairo_surface; typedef struct _cairo_surface cairo_surface_t; #elif USE(SKIA) @@ -68,7 +68,7 @@ class IntPoint; class IntSize; class SharedBuffer; -#if PLATFORM(CG) +#if USE(CG) #if USE(WEBKIT_IMAGE_DECODERS) class ImageDecoder; typedef ImageDecoder* NativeImageSourcePtr; @@ -107,7 +107,7 @@ typedef wxGraphicsBitmap* NativeImagePtr; #else typedef wxBitmap* NativeImagePtr; #endif -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) typedef cairo_surface_t* NativeImagePtr; #elif USE(SKIA) typedef WebCore::NativeImageSkia* NativeImagePtr; diff --git a/Source/WebCore/platform/graphics/IntPoint.h b/Source/WebCore/platform/graphics/IntPoint.h index d27906b..46d49eb 100644 --- a/Source/WebCore/platform/graphics/IntPoint.h +++ b/Source/WebCore/platform/graphics/IntPoint.h @@ -32,7 +32,7 @@ #include <QDataStream> #endif -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) typedef struct CGPoint CGPoint; #endif @@ -114,7 +114,7 @@ public: return IntPoint(m_y, m_x); } -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) explicit IntPoint(const CGPoint&); // don't do this implicitly since it's lossy operator CGPoint() const; #endif diff --git a/Source/WebCore/platform/graphics/IntRect.cpp b/Source/WebCore/platform/graphics/IntRect.cpp index 7591c41..9507406 100644 --- a/Source/WebCore/platform/graphics/IntRect.cpp +++ b/Source/WebCore/platform/graphics/IntRect.cpp @@ -96,6 +96,27 @@ void IntRect::unite(const IntRect& other) m_size.setHeight(b - t); } +void IntRect::uniteIfNonZero(const IntRect& other) +{ + // Handle empty special cases first. + if (!other.width() && !other.height()) + return; + if (!width() && !height()) { + *this = other; + return; + } + + int left = min(x(), other.x()); + int top = min(y(), other.y()); + int right = max(maxX(), other.maxX()); + int bottom = max(maxY(), other.maxY()); + + m_location.setX(left); + m_location.setY(top); + m_size.setWidth(right - left); + m_size.setHeight(bottom - top); +} + void IntRect::scale(float s) { m_location.setX((int)(x() * s)); diff --git a/Source/WebCore/platform/graphics/IntRect.h b/Source/WebCore/platform/graphics/IntRect.h index c413e7a..d2b348b 100644 --- a/Source/WebCore/platform/graphics/IntRect.h +++ b/Source/WebCore/platform/graphics/IntRect.h @@ -29,7 +29,7 @@ #include "IntPoint.h" #include <wtf/Vector.h> -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) typedef struct CGRect CGRect; #endif @@ -133,6 +133,11 @@ public: setHeight(std::max(0, height() + delta)); } + IntPoint minXMinYCorner() const { return m_location; } // typically topLeft + IntPoint maxXMinYCorner() const { return IntPoint(m_location.x() + m_size.width(), m_location.y()); } // typically topRight + IntPoint minXMaxYCorner() const { return IntPoint(m_location.x(), m_location.y() + m_size.height()); } // typically bottomLeft + IntPoint maxXMaxYCorner() const { return IntPoint(m_location.x() + m_size.width(), m_location.y() + m_size.height()); } // typically bottomRight + bool intersects(const IntRect&) const; bool contains(const IntRect&) const; @@ -144,6 +149,7 @@ public: void intersect(const IntRect&); void unite(const IntRect&); + void uniteIfNonZero(const IntRect&); void inflateX(int dx) { @@ -182,7 +188,7 @@ public: operator Eina_Rectangle() const; #endif -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) operator CGRect() const; #endif @@ -228,7 +234,7 @@ inline bool operator!=(const IntRect& a, const IntRect& b) return a.location() != b.location() || a.size() != b.size(); } -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) IntRect enclosingIntRect(const CGRect&); #endif diff --git a/Source/WebCore/platform/graphics/IntSize.h b/Source/WebCore/platform/graphics/IntSize.h index 9db2224..8cfabf5 100644 --- a/Source/WebCore/platform/graphics/IntSize.h +++ b/Source/WebCore/platform/graphics/IntSize.h @@ -26,7 +26,7 @@ #ifndef IntSize_h #define IntSize_h -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) typedef struct CGSize CGSize; #endif @@ -109,7 +109,7 @@ public: return IntSize(m_height, m_width); } -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) explicit IntSize(const CGSize&); // don't do this implicitly since it's lossy operator CGSize() const; #endif diff --git a/Source/WebCore/platform/graphics/MediaPlayer.cpp b/Source/WebCore/platform/graphics/MediaPlayer.cpp index 03004b6..a7e4b90 100644 --- a/Source/WebCore/platform/graphics/MediaPlayer.cpp +++ b/Source/WebCore/platform/graphics/MediaPlayer.cpp @@ -792,11 +792,12 @@ void MediaPlayer::networkStateChanged() // If more than one media engine is installed and this one failed before finding metadata, // let the next engine try. if (m_private->networkState() >= FormatError - && m_private->readyState() < HaveMetadata - && installedMediaEngines().size() > 1 - && bestMediaEngineForTypeAndCodecs(m_contentMIMEType, m_contentTypeCodecs, m_currentMediaEngine)) { + && m_private->readyState() < HaveMetadata + && installedMediaEngines().size() > 1) { + if ( m_contentMIMEType.isEmpty() || bestMediaEngineForTypeAndCodecs(m_contentMIMEType, m_contentTypeCodecs, m_currentMediaEngine)) { m_reloadTimer.startOneShot(0); return; + } } if (m_mediaPlayerClient) m_mediaPlayerClient->mediaPlayerNetworkStateChanged(this); @@ -858,6 +859,12 @@ void MediaPlayer::playbackStateChanged() m_mediaPlayerClient->mediaPlayerPlaybackStateChanged(this); } +void MediaPlayer::firstVideoFrameAvailable() +{ + if (m_mediaPlayerClient) + m_mediaPlayerClient->mediaPlayerFirstVideoFrameAvailable(this); +} + } #endif diff --git a/Source/WebCore/platform/graphics/MediaPlayer.h b/Source/WebCore/platform/graphics/MediaPlayer.h index ff304ea..41cb6d2 100644 --- a/Source/WebCore/platform/graphics/MediaPlayer.h +++ b/Source/WebCore/platform/graphics/MediaPlayer.h @@ -143,6 +143,10 @@ public: virtual void mediaPlayerEngineUpdated(MediaPlayer*) { } + // The first frame of video is available to render. A media engine need only make this callback if the + // first frame is not available immediately when prepareForRendering is called. + virtual void mediaPlayerFirstVideoFrameAvailable(MediaPlayer*) { } + #if USE(ACCELERATED_COMPOSITING) // whether the rendering system can accelerate the display of this MediaPlayer. virtual bool mediaPlayerRenderingCanBeAccelerated(MediaPlayer*) { return false; } @@ -262,6 +266,7 @@ public: void rateChanged(); void playbackStateChanged(); void durationChanged(); + void firstVideoFrameAvailable(); void repaint(); diff --git a/Source/WebCore/platform/graphics/Path.cpp b/Source/WebCore/platform/graphics/Path.cpp index f7aedbe..da09c76 100644 --- a/Source/WebCore/platform/graphics/Path.cpp +++ b/Source/WebCore/platform/graphics/Path.cpp @@ -188,4 +188,9 @@ void Path::addRoundedRect(const FloatRect& rect, const FloatSize& topLeftRadius, closeSubpath(); } +void Path::addRoundedRect(const RoundedIntRect& r) +{ + addRoundedRect(r.rect(), r.radii().topLeft(), r.radii().topRight(), r.radii().bottomLeft(), r.radii().bottomRight()); +} + } diff --git a/Source/WebCore/platform/graphics/Path.h b/Source/WebCore/platform/graphics/Path.h index c2ca576..9c07247 100644 --- a/Source/WebCore/platform/graphics/Path.h +++ b/Source/WebCore/platform/graphics/Path.h @@ -28,10 +28,11 @@ #ifndef Path_h #define Path_h +#include "RoundedIntRect.h" #include <wtf/FastAllocBase.h> #include <wtf/Forward.h> -#if PLATFORM(CG) +#if USE(CG) typedef struct CGPath PlatformPath; #elif PLATFORM(OPENVG) namespace WebCore { @@ -44,7 +45,7 @@ typedef QPainterPath PlatformPath; #elif PLATFORM(WX) && USE(WXGC) class wxGraphicsPath; typedef wxGraphicsPath PlatformPath; -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) namespace WebCore { class CairoPath; } @@ -137,6 +138,7 @@ namespace WebCore { void addEllipse(const FloatRect&); void addRoundedRect(const FloatRect&, const FloatSize& roundingRadii); void addRoundedRect(const FloatRect&, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius); + void addRoundedRect(const RoundedIntRect&); void translate(const FloatSize&); diff --git a/Source/WebCore/platform/graphics/Pattern.h b/Source/WebCore/platform/graphics/Pattern.h index c88f2fb..1d0b0f8 100644 --- a/Source/WebCore/platform/graphics/Pattern.h +++ b/Source/WebCore/platform/graphics/Pattern.h @@ -35,10 +35,10 @@ #include <wtf/RefCounted.h> #include <wtf/RefPtr.h> -#if PLATFORM(CG) +#if USE(CG) typedef struct CGPattern* CGPatternRef; typedef CGPatternRef PlatformPatternPtr; -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) #include <cairo.h> typedef cairo_pattern_t* PlatformPatternPtr; #elif USE(SKIA) diff --git a/Source/WebCore/platform/graphics/RoundedIntRect.cpp b/Source/WebCore/platform/graphics/RoundedIntRect.cpp index 4e80c9a..e919c4f 100644 --- a/Source/WebCore/platform/graphics/RoundedIntRect.cpp +++ b/Source/WebCore/platform/graphics/RoundedIntRect.cpp @@ -30,6 +30,8 @@ #include "IntRect.h" #include <algorithm> +using namespace std; + namespace WebCore { bool RoundedIntRect::Radii::isZero() const @@ -60,17 +62,17 @@ void RoundedIntRect::Radii::scale(float factor) void RoundedIntRect::Radii::expand(int topWidth, int bottomWidth, int leftWidth, int rightWidth) { - m_topLeft.setWidth(std::max(0, m_topLeft.width() + leftWidth)); - m_topLeft.setHeight(std::max(0, m_topLeft.height() + topWidth)); + m_topLeft.setWidth(max(0, m_topLeft.width() + leftWidth)); + m_topLeft.setHeight(max(0, m_topLeft.height() + topWidth)); - m_topRight.setWidth(std::max(0, m_topRight.width() + rightWidth)); - m_topRight.setHeight(std::max(0, m_topRight.height() + topWidth)); + m_topRight.setWidth(max(0, m_topRight.width() + rightWidth)); + m_topRight.setHeight(max(0, m_topRight.height() + topWidth)); - m_bottomLeft.setWidth(std::max(0, m_bottomLeft.width() + leftWidth)); - m_bottomLeft.setHeight(std::max(0, m_bottomLeft.height() + bottomWidth)); + m_bottomLeft.setWidth(max(0, m_bottomLeft.width() + leftWidth)); + m_bottomLeft.setHeight(max(0, m_bottomLeft.height() + bottomWidth)); - m_bottomRight.setWidth(std::max(0, m_bottomRight.width() + rightWidth)); - m_bottomRight.setHeight(std::max(0, m_bottomRight.height() + bottomWidth)); + m_bottomRight.setWidth(max(0, m_bottomRight.width() + rightWidth)); + m_bottomRight.setHeight(max(0, m_bottomRight.height() + bottomWidth)); } void RoundedIntRect::Radii::includeLogicalEdges(const RoundedIntRect::Radii& edges, bool isHorizontal, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) @@ -138,4 +140,12 @@ void RoundedIntRect::excludeLogicalEdges(bool isHorizontal, bool excludeLogicalL m_radii.excludeLogicalEdges(isHorizontal, excludeLogicalLeftEdge, excludeLogicalRightEdge); } +bool RoundedIntRect::isRenderable() const +{ + return m_radii.topLeft().width() + m_radii.topRight().width() <= m_rect.width() + && m_radii.bottomLeft().width() + m_radii.bottomRight().width() <= m_rect.width() + && m_radii.topLeft().height() + m_radii.topRight().height() <= m_rect.height() + && m_radii.bottomLeft().height() + m_radii.bottomRight().height() <= m_rect.height(); +} + } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/RoundedIntRect.h b/Source/WebCore/platform/graphics/RoundedIntRect.h index c3c972f..74ee892 100644 --- a/Source/WebCore/platform/graphics/RoundedIntRect.h +++ b/Source/WebCore/platform/graphics/RoundedIntRect.h @@ -93,11 +93,24 @@ public: void includeLogicalEdges(const Radii& edges, bool isHorizontal, bool includeLogicalLeftEdge, bool includeLogicalRightEdge); void excludeLogicalEdges(bool isHorizontal, bool excludeLogicalLeftEdge, bool excludeLogicalRightEdge); + bool isRenderable() const; + private: IntRect m_rect; Radii m_radii; }; +inline bool operator==(const RoundedIntRect::Radii& a, const RoundedIntRect::Radii& b) +{ + return a.topLeft() == b.topLeft() && a.topRight() == b.topRight() && a.bottomLeft() == b.bottomLeft() && a.bottomRight() == b.bottomRight(); +} + +inline bool operator==(const RoundedIntRect& a, const RoundedIntRect& b) +{ + return a.rect() == b.rect() && a.radii() == b.radii(); +} + + } // namespace WebCore #endif // RoundedIntRect_h diff --git a/Source/WebCore/platform/graphics/ShadowBlur.cpp b/Source/WebCore/platform/graphics/ShadowBlur.cpp index 0df51a4..2f25221 100644 --- a/Source/WebCore/platform/graphics/ShadowBlur.cpp +++ b/Source/WebCore/platform/graphics/ShadowBlur.cpp @@ -54,6 +54,8 @@ class ScratchBuffer { public: ScratchBuffer() : m_purgeTimer(this, &ScratchBuffer::timerFired) + , m_lastRadius(0) + , m_lastWasInset(false) #if !ASSERT_DISABLED , m_bufferInUse(false) #endif @@ -77,6 +79,41 @@ public: return m_imageBuffer.get(); } + void setLastShadowValues(float radius, const Color& color, ColorSpace colorSpace, const FloatRect& shadowRect, const RoundedIntRect::Radii& radii) + { + m_lastWasInset = false; + m_lastRadius = radius; + m_lastColor = color; + m_lastColorSpace = colorSpace; + m_lastShadowRect = shadowRect; + m_lastRadii = radii; + } + + void setLastInsetShadowValues(float radius, const Color& color, ColorSpace colorSpace, const FloatRect& bounds, const FloatRect& shadowRect, const RoundedIntRect::Radii& radii) + { + m_lastWasInset = true; + m_lastInsetBounds = bounds; + m_lastRadius = radius; + m_lastColor = color; + m_lastColorSpace = colorSpace; + m_lastShadowRect = shadowRect; + m_lastRadii = radii; + } + + bool matchesLastShadow(float radius, const Color& color, ColorSpace colorSpace, const FloatRect& shadowRect, const RoundedIntRect::Radii& radii) const + { + if (m_lastWasInset) + return false; + return m_lastRadius == radius && m_lastColor == color && m_lastColorSpace == colorSpace && shadowRect == m_lastShadowRect && radii == m_lastRadii; + } + + bool matchesLastInsetShadow(float radius, const Color& color, ColorSpace colorSpace, const FloatRect& bounds, const FloatRect& shadowRect, const RoundedIntRect::Radii& radii) const + { + if (!m_lastWasInset) + return false; + return m_lastRadius == radius && m_lastColor == color && m_lastColorSpace == colorSpace && m_lastInsetBounds == bounds && shadowRect == m_lastShadowRect && radii == m_lastRadii; + } + void scheduleScratchBufferPurge() { #if !ASSERT_DISABLED @@ -100,10 +137,20 @@ private: void clearScratchBuffer() { m_imageBuffer = 0; + m_lastRadius = 0; } OwnPtr<ImageBuffer> m_imageBuffer; Timer<ScratchBuffer> m_purgeTimer; + + FloatRect m_lastInsetBounds; + FloatRect m_lastShadowRect; + RoundedIntRect::Radii m_lastRadii; + Color m_lastColor; + ColorSpace m_lastColorSpace; + float m_lastRadius; + bool m_lastWasInset; + #if !ASSERT_DISABLED bool m_bufferInUse; #endif @@ -147,14 +194,7 @@ static const int blurSumShift = 15; void ShadowBlur::blurLayerImage(unsigned char* imageData, const IntSize& size, int rowStride) { - const int channels[4] = -#if CPU(BIG_ENDIAN) - { 0, 3, 2, 0 }; -#elif CPU(MIDDLE_ENDIAN) - { 1, 2, 3, 1 }; -#else - { 3, 0, 1, 3 }; -#endif + const int channels[4] = { 3, 0, 1, 3 }; int diameter; if (m_shadowsIgnoreTransforms) @@ -356,40 +396,10 @@ IntRect ShadowBlur::calculateLayerBoundingRect(GraphicsContext* context, const F return enclosingIntRect(layerRect); } -GraphicsContext* ShadowBlur::beginShadowLayer(GraphicsContext* graphicsContext, const IntRect& layerRect) -{ - adjustBlurRadius(graphicsContext); - - // Don't paint if we are totally outside the clip region. - if (layerRect.isEmpty()) - return 0; - - m_layerImage = ScratchBuffer::shared().getScratchBuffer(layerRect.size()); - GraphicsContext* layerContext = m_layerImage->context(); - - layerContext->save(); // Balanced by restore() in endShadowLayer(). - - // Always clear the surface first. FIXME: we could avoid the clear on first allocation. - // Add a pixel to avoid later edge aliasing when rotated. - layerContext->clearRect(FloatRect(0, 0, m_layerSize.width() + 1, m_layerSize.height() + 1)); - layerContext->translate(m_layerContextTranslation); - - return layerContext; -} - -void ShadowBlur::endShadowLayer(GraphicsContext* graphicsContext) +void ShadowBlur::drawShadowBuffer(GraphicsContext* graphicsContext) { if (!m_layerImage) return; - - m_layerImage->context()->restore(); - - if (m_type == BlurShadow) { - IntRect blurRect = enclosingIntRect(FloatRect(FloatPoint(), m_layerSize)); - RefPtr<ByteArray> layerData = m_layerImage->getUnmultipliedImageData(blurRect); - blurLayerImage(layerData->data(), blurRect.size(), blurRect.width() * 4); - m_layerImage->putUnmultipliedImageData(layerData.get(), blurRect.size(), blurRect, IntPoint()); - } graphicsContext->save(); @@ -406,11 +416,6 @@ void ShadowBlur::endShadowLayer(GraphicsContext* graphicsContext) graphicsContext->fillRect(FloatRect(m_layerOrigin, m_sourceRect.size())); graphicsContext->restore(); - - m_layerImage = 0; - - // Schedule a purge of the scratch buffer. We do not need to destroy the surface. - ScratchBuffer::shared().scheduleScratchBufferPurge(); } static void computeSliceSizesFromRadii(int twiceRadius, const RoundedIntRect::Radii& radii, int& leftSlice, int& rightSlice, int& topSlice, int& bottomSlice) @@ -442,6 +447,8 @@ void ShadowBlur::drawRectShadow(GraphicsContext* graphicsContext, const FloatRec if (layerRect.isEmpty()) return; + adjustBlurRadius(graphicsContext); + // drawRectShadowWithTiling does not work with rotations. // https://bugs.webkit.org/show_bug.cgi?id=45042 if (!graphicsContext->getCTM().isIdentityOrTranslationOrFlipped() || m_type != BlurShadow) { @@ -466,6 +473,8 @@ void ShadowBlur::drawInsetShadow(GraphicsContext* graphicsContext, const FloatRe if (layerRect.isEmpty()) return; + adjustBlurRadius(graphicsContext); + // drawInsetShadowWithTiling does not work with rotations. // https://bugs.webkit.org/show_bug.cgi?id=45042 if (!graphicsContext->getCTM().isIdentityOrTranslationOrFlipped() || m_type != BlurShadow) { @@ -486,34 +495,81 @@ void ShadowBlur::drawInsetShadow(GraphicsContext* graphicsContext, const FloatRe void ShadowBlur::drawRectShadowWithoutTiling(GraphicsContext* graphicsContext, const FloatRect& shadowedRect, const RoundedIntRect::Radii& radii, const IntRect& layerRect) { - GraphicsContext* shadowContext = beginShadowLayer(graphicsContext, layerRect); - if (!shadowContext) + m_layerImage = ScratchBuffer::shared().getScratchBuffer(layerRect.size()); + if (!m_layerImage) return; - Path path; - path.addRoundedRect(shadowedRect, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight()); + FloatRect bufferRelativeShadowedRect = shadowedRect; + bufferRelativeShadowedRect.move(m_layerContextTranslation); + if (!ScratchBuffer::shared().matchesLastShadow(m_blurRadius, Color::black, ColorSpaceDeviceRGB, bufferRelativeShadowedRect, radii)) { + GraphicsContext* shadowContext = m_layerImage->context(); + shadowContext->save(); + + // Add a pixel to avoid later edge aliasing when rotated. + shadowContext->clearRect(FloatRect(0, 0, m_layerSize.width() + 1, m_layerSize.height() + 1)); + shadowContext->translate(m_layerContextTranslation); + shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); + if (radii.isZero()) + shadowContext->fillRect(shadowedRect); + else { + Path path; + path.addRoundedRect(shadowedRect, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight()); + shadowContext->fillPath(path); + } + + blurShadowBuffer(expandedIntSize(m_layerSize)); - shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); - shadowContext->fillPath(path); + shadowContext->restore(); + + ScratchBuffer::shared().setLastShadowValues(m_blurRadius, Color::black, ColorSpaceDeviceRGB, bufferRelativeShadowedRect, radii); + } - endShadowLayer(graphicsContext); + drawShadowBuffer(graphicsContext); + m_layerImage = 0; + ScratchBuffer::shared().scheduleScratchBufferPurge(); } void ShadowBlur::drawInsetShadowWithoutTiling(GraphicsContext* graphicsContext, const FloatRect& rect, const FloatRect& holeRect, const RoundedIntRect::Radii& holeRadii, const IntRect& layerRect) { - GraphicsContext* shadowContext = beginShadowLayer(graphicsContext, layerRect); - if (!shadowContext) + m_layerImage = ScratchBuffer::shared().getScratchBuffer(layerRect.size()); + if (!m_layerImage) return; - Path path; - path.addRect(rect); - path.addRoundedRect(holeRect, holeRadii.topLeft(), holeRadii.topRight(), holeRadii.bottomLeft(), holeRadii.bottomRight()); + FloatRect bufferRelativeRect = rect; + bufferRelativeRect.move(m_layerContextTranslation); + + FloatRect bufferRelativeHoleRect = holeRect; + bufferRelativeHoleRect.move(m_layerContextTranslation); - shadowContext->setFillRule(RULE_EVENODD); - shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); - shadowContext->fillPath(path); + if (!ScratchBuffer::shared().matchesLastInsetShadow(m_blurRadius, Color::black, ColorSpaceDeviceRGB, bufferRelativeRect, bufferRelativeHoleRect, holeRadii)) { + GraphicsContext* shadowContext = m_layerImage->context(); + shadowContext->save(); - endShadowLayer(graphicsContext); + // Add a pixel to avoid later edge aliasing when rotated. + shadowContext->clearRect(FloatRect(0, 0, m_layerSize.width() + 1, m_layerSize.height() + 1)); + shadowContext->translate(m_layerContextTranslation); + + Path path; + path.addRect(rect); + if (holeRadii.isZero()) + path.addRect(holeRect); + else + path.addRoundedRect(holeRect, holeRadii.topLeft(), holeRadii.topRight(), holeRadii.bottomLeft(), holeRadii.bottomRight()); + + shadowContext->setFillRule(RULE_EVENODD); + shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); + shadowContext->fillPath(path); + + blurShadowBuffer(expandedIntSize(m_layerSize)); + + shadowContext->restore(); + + ScratchBuffer::shared().setLastInsetShadowValues(m_blurRadius, Color::black, ColorSpaceDeviceRGB, bufferRelativeRect, bufferRelativeHoleRect, holeRadii); + } + + drawShadowBuffer(graphicsContext); + m_layerImage = 0; + ScratchBuffer::shared().scheduleScratchBufferPurge(); } /* @@ -557,23 +613,35 @@ void ShadowBlur::drawInsetShadowWithTiling(GraphicsContext* graphicsContext, con const float twiceRadius = roundedRadius * 2; m_layerImage = ScratchBuffer::shared().getScratchBuffer(templateSize); + if (!m_layerImage) + return; // Draw the rectangle with hole. FloatRect templateBounds(0, 0, templateSize.width(), templateSize.height()); FloatRect templateHole = FloatRect(roundedRadius, roundedRadius, templateSize.width() - twiceRadius, templateSize.height() - twiceRadius); - Path path; - path.addRect(templateBounds); - path.addRoundedRect(templateHole, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight()); - // Draw shadow into a new ImageBuffer. - GraphicsContext* shadowContext = m_layerImage->context(); - shadowContext->save(); - shadowContext->clearRect(templateBounds); - shadowContext->setFillRule(RULE_EVENODD); - shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); - shadowContext->fillPath(path); - blurAndColorShadowBuffer(templateSize); - shadowContext->restore(); + if (!ScratchBuffer::shared().matchesLastInsetShadow(m_blurRadius, m_color, m_colorSpace, templateBounds, templateHole, radii)) { + // Draw shadow into a new ImageBuffer. + GraphicsContext* shadowContext = m_layerImage->context(); + shadowContext->save(); + shadowContext->clearRect(templateBounds); + shadowContext->setFillRule(RULE_EVENODD); + shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); + + Path path; + path.addRect(templateBounds); + if (radii.isZero()) + path.addRect(templateHole); + else + path.addRoundedRect(templateHole, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight()); + + shadowContext->fillPath(path); + + blurAndColorShadowBuffer(templateSize); + shadowContext->restore(); + + ScratchBuffer::shared().setLastInsetShadowValues(m_blurRadius, m_color, m_colorSpace, templateBounds, templateHole, radii); + } FloatRect boundingRect = rect; boundingRect.move(m_offset); @@ -599,7 +667,6 @@ void ShadowBlur::drawInsetShadowWithTiling(GraphicsContext* graphicsContext, con graphicsContext->restore(); m_layerImage = 0; - // Schedule a purge of the scratch buffer. ScratchBuffer::shared().scheduleScratchBufferPurge(); } @@ -612,20 +679,31 @@ void ShadowBlur::drawRectShadowWithTiling(GraphicsContext* graphicsContext, cons const float twiceRadius = roundedRadius * 2; m_layerImage = ScratchBuffer::shared().getScratchBuffer(templateSize); + if (!m_layerImage) + return; - // Draw the rectangle. FloatRect templateShadow = FloatRect(roundedRadius, roundedRadius, templateSize.width() - twiceRadius, templateSize.height() - twiceRadius); - Path path; - path.addRoundedRect(templateShadow, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight()); - // Draw shadow into the ImageBuffer. - GraphicsContext* shadowContext = m_layerImage->context(); - shadowContext->save(); - shadowContext->clearRect(FloatRect(0, 0, templateSize.width(), templateSize.height())); - shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); - shadowContext->fillPath(path); - blurAndColorShadowBuffer(templateSize); - shadowContext->restore(); + if (!ScratchBuffer::shared().matchesLastShadow(m_blurRadius, m_color, m_colorSpace, templateShadow, radii)) { + // Draw shadow into the ImageBuffer. + GraphicsContext* shadowContext = m_layerImage->context(); + shadowContext->save(); + shadowContext->clearRect(FloatRect(0, 0, templateSize.width(), templateSize.height())); + shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); + + if (radii.isZero()) + shadowContext->fillRect(templateShadow); + else { + Path path; + path.addRoundedRect(templateShadow, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight()); + shadowContext->fillPath(path); + } + + blurAndColorShadowBuffer(templateSize); + shadowContext->restore(); + + ScratchBuffer::shared().setLastShadowValues(m_blurRadius, m_color, m_colorSpace, templateShadow, radii); + } FloatRect shadowBounds = shadowedRect; shadowBounds.move(m_offset.width(), m_offset.height()); @@ -636,7 +714,6 @@ void ShadowBlur::drawRectShadowWithTiling(GraphicsContext* graphicsContext, cons graphicsContext->restore(); m_layerImage = 0; - // Schedule a purge of the scratch buffer. ScratchBuffer::shared().scheduleScratchBufferPurge(); } @@ -714,14 +791,20 @@ void ShadowBlur::drawLayerPieces(GraphicsContext* graphicsContext, const FloatRe } +void ShadowBlur::blurShadowBuffer(const IntSize& templateSize) +{ + if (m_type != BlurShadow) + return; + + IntRect blurRect(IntPoint(), templateSize); + RefPtr<ByteArray> layerData = m_layerImage->getUnmultipliedImageData(blurRect); + blurLayerImage(layerData->data(), blurRect.size(), blurRect.width() * 4); + m_layerImage->putUnmultipliedImageData(layerData.get(), blurRect.size(), blurRect, IntPoint()); +} + void ShadowBlur::blurAndColorShadowBuffer(const IntSize& templateSize) { - { - IntRect blurRect(IntPoint(), templateSize); - RefPtr<ByteArray> layerData = m_layerImage->getUnmultipliedImageData(blurRect); - blurLayerImage(layerData->data(), blurRect.size(), blurRect.width() * 4); - m_layerImage->putUnmultipliedImageData(layerData.get(), blurRect.size(), blurRect, IntPoint()); - } + blurShadowBuffer(templateSize); // Mask the image with the shadow color. GraphicsContext* shadowContext = m_layerImage->context(); diff --git a/Source/WebCore/platform/graphics/ShadowBlur.h b/Source/WebCore/platform/graphics/ShadowBlur.h index e52d6dc..4ba8e23 100644 --- a/Source/WebCore/platform/graphics/ShadowBlur.h +++ b/Source/WebCore/platform/graphics/ShadowBlur.h @@ -53,8 +53,7 @@ public: void drawInsetShadow(GraphicsContext*, const FloatRect&, const FloatRect& holeRect, const RoundedIntRect::Radii& holeRadii); private: - GraphicsContext* beginShadowLayer(GraphicsContext*, const IntRect& layerRect); - void endShadowLayer(GraphicsContext*); + void drawShadowBuffer(GraphicsContext*); void adjustBlurRadius(GraphicsContext*); void blurLayerImage(unsigned char*, const IntSize&, int stride); @@ -75,6 +74,7 @@ private: void drawLayerPieces(GraphicsContext*, const FloatRect& shadowBounds, const RoundedIntRect::Radii&, float roundedRadius, const IntSize& templateSize, ShadowDirection); + void blurShadowBuffer(const IntSize& templateSize); void blurAndColorShadowBuffer(const IntSize& templateSize); enum ShadowType { diff --git a/Source/WebCore/platform/graphics/SimpleFontData.h b/Source/WebCore/platform/graphics/SimpleFontData.h index dfb4be3..67e864a 100644 --- a/Source/WebCore/platform/graphics/SimpleFontData.h +++ b/Source/WebCore/platform/graphics/SimpleFontData.h @@ -48,7 +48,7 @@ typedef struct OpaqueATSUStyle* ATSUStyle; #include <usp10.h> #endif -#if PLATFORM(CAIRO) +#if USE(CAIRO) #include <cairo.h> #endif @@ -115,7 +115,7 @@ public: float spaceWidth() const { return m_spaceWidth; } -#if PLATFORM(CG) || PLATFORM(CAIRO) || PLATFORM(WX) +#if USE(CG) || USE(CAIRO) || PLATFORM(WX) || USE(SKIA_ON_MAC_CHROME) float syntheticBoldOffset() const { return m_syntheticBoldOffset; } #endif @@ -252,7 +252,7 @@ private: mutable OwnPtr<DerivedFontData> m_derivedFontData; -#if PLATFORM(CG) || PLATFORM(CAIRO) || PLATFORM(WX) +#if USE(CG) || USE(CAIRO) || PLATFORM(WX) || USE(SKIA_ON_MAC_CHROME) float m_syntheticBoldOffset; #endif diff --git a/Source/WebCore/platform/graphics/WOFFFileFormat.cpp b/Source/WebCore/platform/graphics/WOFFFileFormat.cpp index 80a6dcb..d54f3df 100644 --- a/Source/WebCore/platform/graphics/WOFFFileFormat.cpp +++ b/Source/WebCore/platform/graphics/WOFFFileFormat.cpp @@ -43,7 +43,7 @@ #define ntohs(x) std_ntohs(x) #endif -#if PLATFORM(WIN) +#if OS(WINDOWS) #if CPU(BIG_ENDIAN) #define ntohs(x) ((uint16_t)(x)) #define htons(x) ((uint16_t)(x)) @@ -61,7 +61,7 @@ (((uint32_t)(x) & 0x0000ff00) << 8) | (((uint32_t)(x) & 0x000000ff) << 24))) #define htonl(x) ntohl(x) #endif -#endif // PLATFORM(WIN) +#endif // OS(WINDOWS) namespace WebCore { diff --git a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp index eb96532..681003f 100644 --- a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp +++ b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp @@ -74,6 +74,8 @@ MediaPlayerPrivateAVFoundation::MediaPlayerPrivateAVFoundation(MediaPlayer* play , m_cachedHasVideo(false) , m_cachedHasCaptions(false) , m_ignoreLoadStateChanges(false) + , m_haveReportedFirstVideoFrame(false) + , m_playWhenFramesAvailable(false) { LOG(Media, "MediaPlayerPrivateAVFoundation::MediaPlayerPrivateAVFoundation(%p)", this); } @@ -248,6 +250,25 @@ void MediaPlayerPrivateAVFoundation::prepareToPlay() checkPlayability(); } +void MediaPlayerPrivateAVFoundation::play() +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::play(%p)", this); + + // If the file has video, don't request playback until the first frame of video is ready to display + // or the audio may start playing before we can render video. + if (!m_cachedHasVideo || hasAvailableVideoFrame()) + platformPlay(); + else + m_playWhenFramesAvailable = true; +} + +void MediaPlayerPrivateAVFoundation::pause() +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::pause(%p)", this); + m_playWhenFramesAvailable = false; + platformPause(); +} + void MediaPlayerPrivateAVFoundation::paint(GraphicsContext*, const IntRect&) { // This is the base class, only need to remember that a frame has been drawn. @@ -285,6 +306,8 @@ void MediaPlayerPrivateAVFoundation::setRate(float rate) { LOG(Media, "MediaPlayerPrivateAVFoundation::setRate(%p) - seting to %f", this, rate); m_requestedRate = rate; + + updateRate(); } bool MediaPlayerPrivateAVFoundation::paused() const @@ -464,12 +487,22 @@ void MediaPlayerPrivateAVFoundation::updateStates() if (isReadyForVideoSetup() && currentRenderingMode() != preferredRenderingMode()) setUpVideoRendering(); + if (!m_haveReportedFirstVideoFrame && m_cachedHasVideo && hasAvailableVideoFrame()) { + m_haveReportedFirstVideoFrame = true; + m_player->firstVideoFrameAvailable(); + } + if (m_networkState != oldNetworkState) m_player->networkStateChanged(); if (m_readyState != oldReadyState) m_player->readyStateChanged(); + if (m_playWhenFramesAvailable && hasAvailableVideoFrame()) { + m_playWhenFramesAvailable = false; + platformPlay(); + } + LOG(Media, "MediaPlayerPrivateAVFoundation::updateStates(%p) - exiting with networkState = %i, readyState = %i", this, static_cast<int>(m_networkState), static_cast<int>(m_readyState)); } @@ -566,6 +599,14 @@ void MediaPlayerPrivateAVFoundation::timeChanged(double time) } } +void MediaPlayerPrivateAVFoundation::seekCompleted(bool finished) +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::seekCompleted(%p) - finished = %d", this, finished); + + if (finished) + m_seekTo = invalidTime; +} + void MediaPlayerPrivateAVFoundation::didEnd() { // Hang onto the current time and use it as duration from now on since we are definitely at @@ -629,12 +670,22 @@ void MediaPlayerPrivateAVFoundation::clearMainThreadPendingFlag() void MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(Notification::Type type, double time) { - LOG(Media, "MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(%p) - notification %d", this, static_cast<int>(type)); + scheduleMainThreadNotification(Notification(type, time)); +} + +void MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(Notification::Type type, bool finished) +{ + scheduleMainThreadNotification(Notification(type, finished)); +} + +void MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(Notification notification) +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(%p) - notification %d", this, static_cast<int>(notification.type())); m_queueMutex.lock(); // It is important to always process the properties in the order that we are notified, // so always go through the queue because notifications happen on different threads. - m_queuedNotifications.append(Notification(type, time)); + m_queuedNotifications.append(notification); bool delayDispatch = m_delayCallbacks || !isMainThread(); if (delayDispatch && !m_mainThreadCallPending) { @@ -714,6 +765,9 @@ void MediaPlayerPrivateAVFoundation::dispatchNotification() case Notification::PlayerTimeChanged: timeChanged(notification.time()); break; + case Notification::SeekCompleted: + seekCompleted(notification.finished()); + break; case Notification::AssetMetadataLoaded: metadataLoaded(); break; diff --git a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h index a768ab4..becba61 100644 --- a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h +++ b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h @@ -48,6 +48,7 @@ public: virtual void loadedTimeRangesChanged(); virtual void seekableTimeRangesChanged(); virtual void timeChanged(double); + virtual void seekCompleted(bool); virtual void didEnd(); class Notification { @@ -66,31 +67,45 @@ public: AssetMetadataLoaded, AssetPlayabilityKnown, PlayerRateChanged, - PlayerTimeChanged + PlayerTimeChanged, + SeekCompleted, }; Notification() : m_type(None) , m_time(0) + , m_finished(false) { } Notification(Type type, double time) : m_type(type) , m_time(time) + , m_finished(false) + { + } + + Notification(Type type, bool finished) + : m_type(type) + , m_time(0) + , m_finished(finished) { } Type type() { return m_type; } bool isValid() { return m_type != None; } double time() { return m_time; } + bool finished() { return m_finished; } private: Type m_type; double m_time; + bool m_finished; }; + void scheduleMainThreadNotification(Notification); void scheduleMainThreadNotification(Notification::Type, double time = 0); + void scheduleMainThreadNotification(Notification::Type, bool completed); void dispatchNotification(); void clearMainThreadPendingFlag(); @@ -105,8 +120,8 @@ protected: virtual void prepareToPlay(); virtual PlatformMedia platformMedia() const = 0; - virtual void play() = 0; - virtual void pause() = 0; + virtual void play(); + virtual void pause(); virtual IntSize naturalSize() const; virtual bool hasVideo() const { return m_cachedHasVideo; } @@ -169,7 +184,10 @@ protected: }; virtual AVAssetStatus assetStatus() const = 0; + virtual void platformPlay() = 0; + virtual void platformPause() = 0; virtual void checkPlayability() = 0; + virtual void updateRate() = 0; virtual float rate() const = 0; virtual void seekToTime(float time) = 0; virtual unsigned totalBytes() const = 0; @@ -254,6 +272,8 @@ private: bool m_cachedHasVideo; bool m_cachedHasCaptions; bool m_ignoreLoadStateChanges; + bool m_haveReportedFirstVideoFrame; + bool m_playWhenFramesAvailable; }; } diff --git a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.h b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.h index cc00c15..7f214b8 100644 --- a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.h +++ b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.h @@ -73,8 +73,8 @@ private: virtual PlatformMedia platformMedia() const; - virtual void play(); - virtual void pause(); + virtual void platformPlay(); + virtual void platformPause(); virtual float currentTime() const; virtual void setVolume(float); virtual void setClosedCaptionsVisible(bool); @@ -93,6 +93,7 @@ private: virtual MediaPlayerPrivateAVFoundation::AVAssetStatus assetStatus() const; virtual void checkPlayability(); + virtual void updateRate(); virtual float rate() const; virtual void seekToTime(float time); virtual unsigned totalBytes() const; diff --git a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm index 55eb433..c4efb9f 100644 --- a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm +++ b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm @@ -100,6 +100,7 @@ enum MediaPlayerAVFoundationObservationContext { -(void)playableKnown; -(void)metadataLoaded; -(void)timeChanged:(double)time; +-(void)seekCompleted:(BOOL)finished; -(void)didEnd:(NSNotification *)notification; -(void)observeValueForKeyPath:keyPath ofObject:(id)object change:(NSDictionary *)change context:(MediaPlayerAVFoundationObservationContext)context; @end @@ -200,7 +201,7 @@ void MediaPlayerPrivateAVFoundationObjC::destroyContextVideoRenderer() if (!m_imageGenerator) return; - LOG(Media, "MediaPlayerPrivateAVFoundationObjC::destroyContextVideoRenderer(%p) - destroying", this, m_imageGenerator.get()); + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::destroyContextVideoRenderer(%p) - destroying %p", this, m_imageGenerator.get()); m_imageGenerator = 0; } @@ -213,7 +214,7 @@ void MediaPlayerPrivateAVFoundationObjC::createVideoLayer() if (!m_videoLayer) { m_videoLayer.adoptNS([[AVPlayerLayer alloc] init]); [m_videoLayer.get() setPlayer:m_avPlayer.get()]; - LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createVideoLayer(%p) - returning", this, m_videoLayer.get()); + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createVideoLayer(%p) - returning %p", this, m_videoLayer.get()); } } @@ -327,9 +328,9 @@ MediaPlayerPrivateAVFoundation::ItemStatus MediaPlayerPrivateAVFoundationObjC::p return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusFailed; if ([m_avPlayerItem.get() isPlaybackLikelyToKeepUp]) return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackLikelyToKeepUp; - if ([m_avPlayerItem.get() isPlaybackBufferFull]) + if (buffered()->contain(duration())) return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackBufferFull; - if ([m_avPlayerItem.get() isPlaybackBufferEmpty]) + if (buffered()->contain(currentTime())) return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackBufferEmpty; return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusReadyToPlay; @@ -350,9 +351,9 @@ PlatformLayer* MediaPlayerPrivateAVFoundationObjC::platformLayer() const return m_videoLayer.get(); } -void MediaPlayerPrivateAVFoundationObjC::play() +void MediaPlayerPrivateAVFoundationObjC::platformPlay() { - LOG(Media, "MediaPlayerPrivateAVFoundationObjC::play(%p)", this); + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::platformPlay(%p)", this); if (!metaDataAvailable()) return; @@ -361,9 +362,9 @@ void MediaPlayerPrivateAVFoundationObjC::play() setDelayCallbacks(false); } -void MediaPlayerPrivateAVFoundationObjC::pause() +void MediaPlayerPrivateAVFoundationObjC::platformPause() { - LOG(Media, "MediaPlayerPrivateAVFoundationObjC::pause(%p)", this); + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::platformPause(%p)", this); if (!metaDataAvailable()) return; @@ -408,14 +409,10 @@ void MediaPlayerPrivateAVFoundationObjC::seekToTime(float time) // setCurrentTime generates several event callbacks, update afterwards. setDelayCallbacks(true); - float now = currentTime(); - if (time != now) - [m_avPlayerItem.get() seekToTime:CMTimeMakeWithSeconds(time, 600) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero]; - else { - // Force a call to the "time changed" notifier manually because a seek to the current time is a noop - // so the seek will never seem to complete. - [m_objcObserver.get() timeChanged:now]; - } + WebCoreAVFMovieObserver *observer = m_objcObserver.get(); + [m_avPlayerItem.get() seekToTime:CMTimeMakeWithSeconds(time, 600) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:^(BOOL finished) { + [observer seekCompleted:finished]; + }]; setDelayCallbacks(false); } @@ -437,6 +434,13 @@ void MediaPlayerPrivateAVFoundationObjC::setClosedCaptionsVisible(bool closedCap [m_avPlayer.get() setClosedCaptionDisplayEnabled:closedCaptionsVisible]; } +void MediaPlayerPrivateAVFoundationObjC::updateRate() +{ + setDelayCallbacks(true); + [m_avPlayer.get() setRate:requestedRate()]; + setDelayCallbacks(false); +} + float MediaPlayerPrivateAVFoundationObjC::rate() const { if (!metaDataAvailable()) @@ -621,12 +625,16 @@ void MediaPlayerPrivateAVFoundationObjC::getSupportedTypes(HashSet<String>& supp MediaPlayer::SupportsType MediaPlayerPrivateAVFoundationObjC::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 if it supports an - // extended MIME type until rdar://6220037 is fixed. - if (mimeTypeCache().contains(type)) - return codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported; + if (!mimeTypeCache().contains(type)) + return MediaPlayer::IsNotSupported; + + // The spec says: + // "Implementors are encouraged to return "maybe" unless the type can be confidently established as being supported or not." + if (codecs.isEmpty()) + return MediaPlayer::MayBeSupported; - return MediaPlayer::IsNotSupported; + NSString *typeString = [NSString stringWithFormat:@"%@; codecs=\"%@\"", (NSString *)type, (NSString *)codecs]; + return [AVURLAsset isPlayableExtendedMIMEType:typeString] ? MediaPlayer::IsSupported : MediaPlayer::MayBeSupported;; } bool MediaPlayerPrivateAVFoundationObjC::isAvailable() @@ -758,6 +766,14 @@ NSArray* itemKVOProperties() m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::PlayerTimeChanged, time); } +- (void)seekCompleted:(BOOL)finished +{ + if (!m_callback) + return; + + m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::SeekCompleted, static_cast<bool>(finished)); +} + - (void)didEnd:(NSNotification *)unusedNotification { UNUSED_PARAM(unusedNotification); diff --git a/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp b/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp index 427c7bf..8fb4c9f 100644 --- a/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp +++ b/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp @@ -255,6 +255,7 @@ GraphicsLayerCA::GraphicsLayerCA(GraphicsLayerClient* client) , m_contentsLayerHasBackgroundColor(false) , m_uncommittedChanges(NoChange) , m_contentsScale(1) + , m_allowTiledLayer(true) { m_layer = PlatformCALayer::create(PlatformCALayer::LayerTypeWebLayer, this); @@ -492,6 +493,17 @@ void GraphicsLayerCA::setAcceleratesDrawing(bool acceleratesDrawing) noteLayerPropertyChanged(AcceleratesDrawingChanged); } +void GraphicsLayerCA::setAllowTiledLayer(bool allowTiledLayer) +{ + if (allowTiledLayer == m_allowTiledLayer) + return; + + m_allowTiledLayer = allowTiledLayer; + + // Handling this as a SizeChanged will cause use to switch in or out of tiled layer as needed + noteLayerPropertyChanged(SizeChanged); +} + void GraphicsLayerCA::setBackgroundColor(const Color& color) { if (m_backgroundColorSet && m_backgroundColor == color) @@ -2005,7 +2017,7 @@ FloatSize GraphicsLayerCA::constrainedSize() const bool GraphicsLayerCA::requiresTiledLayer(const FloatSize& size) const { - if (!m_drawsContent) + if (!m_drawsContent || !m_allowTiledLayer) return false; // FIXME: catch zero-size height or width here (or earlier)? diff --git a/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h b/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h index 2c39c0a..3f2d3e4 100644 --- a/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h +++ b/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h @@ -122,6 +122,9 @@ public: virtual void syncCompositingState(); virtual void syncCompositingStateForThisLayerOnly(); + bool allowTiledLayer() const { return m_allowTiledLayer; } + virtual void setAllowTiledLayer(bool b); + protected: virtual void setOpacityInternal(float); @@ -399,6 +402,8 @@ private: float clampedContentsScaleForScale(float) const; float m_contentsScale; + + bool m_allowTiledLayer; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/ca/TransformationMatrixCA.cpp b/Source/WebCore/platform/graphics/ca/TransformationMatrixCA.cpp index 0ef5fd0..e5ff5ba 100644 --- a/Source/WebCore/platform/graphics/ca/TransformationMatrixCA.cpp +++ b/Source/WebCore/platform/graphics/ca/TransformationMatrixCA.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "TransformationMatrix.h" -#if PLATFORM(CA) +#if USE(CA) #include "FloatConversion.h" #include <QuartzCore/CATransform3D.h> @@ -66,4 +66,4 @@ TransformationMatrix::operator CATransform3D() const } -#endif // PLATFORM(CA) +#endif // USE(CA) diff --git a/Source/WebCore/platform/graphics/ca/win/AbstractCACFLayerTreeHost.h b/Source/WebCore/platform/graphics/ca/win/AbstractCACFLayerTreeHost.h new file mode 100644 index 0000000..13c6746 --- /dev/null +++ b/Source/WebCore/platform/graphics/ca/win/AbstractCACFLayerTreeHost.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2009, 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AbstractCACFLayerTreeHost_h +#define AbstractCACFLayerTreeHost_h + +#if USE(ACCELERATED_COMPOSITING) + +#include <wtf/Forward.h> + +namespace WebCore { + +class PlatformCALayer; + +class AbstractCACFLayerTreeHost { +public: + virtual PlatformCALayer* rootLayer() const = 0; + virtual void addPendingAnimatedLayer(PassRefPtr<PlatformCALayer>) = 0; + virtual void layerTreeDidChange() = 0; + virtual void flushPendingLayerChangesNow() = 0; + +protected: + virtual ~AbstractCACFLayerTreeHost() { } +}; + +} + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // AbstractCACFLayerTreeHost_h diff --git a/Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHost.h b/Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHost.h index 6d91a73..507af0f 100644 --- a/Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHost.h +++ b/Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHost.h @@ -28,6 +28,7 @@ #if USE(ACCELERATED_COMPOSITING) +#include "AbstractCACFLayerTreeHost.h" #include "COMPtr.h" #include "Timer.h" @@ -50,9 +51,7 @@ namespace WebCore { class CACFLayerTreeHostClient; class PlatformCALayer; -class CACFLayerTreeHost : public RefCounted<CACFLayerTreeHost> { - friend PlatformCALayer; - +class CACFLayerTreeHost : public RefCounted<CACFLayerTreeHost>, private AbstractCACFLayerTreeHost { public: static PassRefPtr<CACFLayerTreeHost> create(); virtual ~CACFLayerTreeHost(); @@ -66,24 +65,31 @@ public: virtual void paint(); virtual void resize() = 0; void flushPendingGraphicsLayerChangesSoon(); - void flushPendingLayerChangesNow(); + + // AbstractCACFLayerTreeHost + virtual void flushPendingLayerChangesNow(); protected: CACFLayerTreeHost(); CGRect bounds() const; - PlatformCALayer* rootLayer() const; HWND window() const { return m_window; } void notifyAnimationsStarted(); + // AbstractCACFLayerTreeHost + virtual PlatformCALayer* rootLayer() const; + virtual bool createRenderer() = 0; virtual void destroyRenderer(); virtual void contextDidChange(); private: void initialize(); - void addPendingAnimatedLayer(PassRefPtr<PlatformCALayer>); - void layerTreeDidChange(); + + // AbstractCACFLayerTreeHost + virtual void addPendingAnimatedLayer(PassRefPtr<PlatformCALayer>); + virtual void layerTreeDidChange(); + virtual void flushContext() = 0; virtual CFTimeInterval lastCommitTime() const = 0; diff --git a/Source/WebCore/platform/graphics/ca/win/LayerChangesFlusher.cpp b/Source/WebCore/platform/graphics/ca/win/LayerChangesFlusher.cpp index 3fd857b..ec2a9ff 100644 --- a/Source/WebCore/platform/graphics/ca/win/LayerChangesFlusher.cpp +++ b/Source/WebCore/platform/graphics/ca/win/LayerChangesFlusher.cpp @@ -28,8 +28,7 @@ #if USE(ACCELERATED_COMPOSITING) -#include "CACFLayerTreeHost.h" -#include "WebCoreInstanceHandle.h" +#include "AbstractCACFLayerTreeHost.h" #include <wtf/StdLibExtras.h> #include <wtf/Vector.h> @@ -47,7 +46,7 @@ LayerChangesFlusher::LayerChangesFlusher() { } -void LayerChangesFlusher::flushPendingLayerChangesSoon(CACFLayerTreeHost* host) +void LayerChangesFlusher::flushPendingLayerChangesSoon(AbstractCACFLayerTreeHost* host) { if (!m_hostsWithChangesToFlush.add(host).second || m_hook) return; @@ -55,7 +54,7 @@ void LayerChangesFlusher::flushPendingLayerChangesSoon(CACFLayerTreeHost* host) setHook(); } -void LayerChangesFlusher::cancelPendingFlush(CACFLayerTreeHost* host) +void LayerChangesFlusher::cancelPendingFlush(AbstractCACFLayerTreeHost* host) { m_hostsWithChangesToFlush.remove(host); @@ -80,9 +79,8 @@ LRESULT LayerChangesFlusher::hookFired(int code, WPARAM wParam, LPARAM lParam) ASSERT(m_hook); // Calling out to the hosts can cause m_hostsWithChangesToFlush to be modified, so we copy it - // into a Vector first. We have to hold a reference to them because otherwise they could be - // destroyed while we're calling out to them. - Vector<RefPtr<CACFLayerTreeHost> > hosts; + // into a Vector first. + Vector<AbstractCACFLayerTreeHost*> hosts; copyToVector(m_hostsWithChangesToFlush, hosts); m_hostsWithChangesToFlush.clear(); @@ -108,7 +106,7 @@ void LayerChangesFlusher::setHook() DWORD threadID = ::GetCurrentThreadId(); - m_hook = ::SetWindowsHookExW(WH_GETMESSAGE, hookCallback, instanceHandle(), threadID); + m_hook = ::SetWindowsHookExW(WH_GETMESSAGE, hookCallback, 0, threadID); ASSERT_WITH_MESSAGE(m_hook, "::SetWindowsHookExW failed with error %lu", ::GetLastError()); // Post a message to the message queue to prevent ::GetMessage from blocking, which will ensure diff --git a/Source/WebCore/platform/graphics/ca/win/LayerChangesFlusher.h b/Source/WebCore/platform/graphics/ca/win/LayerChangesFlusher.h index 6a98a99..1e7ab31 100644 --- a/Source/WebCore/platform/graphics/ca/win/LayerChangesFlusher.h +++ b/Source/WebCore/platform/graphics/ca/win/LayerChangesFlusher.h @@ -34,15 +34,15 @@ namespace WebCore { -class CACFLayerTreeHost; +class AbstractCACFLayerTreeHost; class LayerChangesFlusher { WTF_MAKE_NONCOPYABLE(LayerChangesFlusher); public: static LayerChangesFlusher& shared(); - void flushPendingLayerChangesSoon(CACFLayerTreeHost*); - void cancelPendingFlush(CACFLayerTreeHost*); + void flushPendingLayerChangesSoon(AbstractCACFLayerTreeHost*); + void cancelPendingFlush(AbstractCACFLayerTreeHost*); private: LayerChangesFlusher(); @@ -53,7 +53,7 @@ private: void setHook(); void removeHook(); - HashSet<CACFLayerTreeHost*> m_hostsWithChangesToFlush; + HashSet<AbstractCACFLayerTreeHost*> m_hostsWithChangesToFlush; HHOOK m_hook; bool m_isCallingHosts; }; diff --git a/Source/WebCore/platform/graphics/ca/win/PlatformCALayerWin.cpp b/Source/WebCore/platform/graphics/ca/win/PlatformCALayerWin.cpp index b5a26f4..5d20928 100644 --- a/Source/WebCore/platform/graphics/ca/win/PlatformCALayerWin.cpp +++ b/Source/WebCore/platform/graphics/ca/win/PlatformCALayerWin.cpp @@ -29,7 +29,7 @@ #include "PlatformCALayer.h" -#include "CACFLayerTreeHost.h" +#include "AbstractCACFLayerTreeHost.h" #include "Font.h" #include "GraphicsContext.h" #include "PlatformCALayerWinInternal.h" @@ -65,14 +65,14 @@ static CFStringRef toCACFFilterType(PlatformCALayer::FilterType type) } } -static CACFLayerTreeHost* layerTreeHostForLayer(const PlatformCALayer* layer) +static AbstractCACFLayerTreeHost* layerTreeHostForLayer(const PlatformCALayer* layer) { - // We need the CACFLayerTreeHost associated with this layer, which is stored in the UserData of the CACFContext + // We need the AbstractCACFLayerTreeHost associated with this layer, which is stored in the UserData of the CACFContext void* userData = wkCACFLayerGetContextUserData(layer->platformLayer()); if (!userData) return 0; - return static_cast<CACFLayerTreeHost*>(userData); + return static_cast<AbstractCACFLayerTreeHost*>(userData); } static PlatformCALayerWinInternal* intern(const PlatformCALayer* layer) @@ -156,7 +156,7 @@ PlatformLayer* PlatformCALayer::platformLayer() const PlatformCALayer* PlatformCALayer::rootLayer() const { - CACFLayerTreeHost* host = layerTreeHostForLayer(this); + AbstractCACFLayerTreeHost* host = layerTreeHostForLayer(this); return host ? host->rootLayer() : 0; } @@ -167,7 +167,7 @@ void PlatformCALayer::setNeedsDisplay(const FloatRect* dirtyRect) void PlatformCALayer::setNeedsCommit() { - CACFLayerTreeHost* host = layerTreeHostForLayer(this); + AbstractCACFLayerTreeHost* host = layerTreeHostForLayer(this); if (host) host->layerTreeDidChange(); } @@ -270,7 +270,7 @@ void PlatformCALayer::addAnimationForKey(const String& key, PlatformCAAnimation* setNeedsCommit(); // Tell the host about it so we can fire the start animation event - CACFLayerTreeHost* host = layerTreeHostForLayer(this); + AbstractCACFLayerTreeHost* host = layerTreeHostForLayer(this); if (host) host->addPendingAnimatedLayer(this); } @@ -283,7 +283,7 @@ void PlatformCALayer::removeAnimationForKey(const String& key) RetainPtr<CFStringRef> s(AdoptCF, key.createCFString()); CACFLayerRemoveAnimation(m_layer.get(), s.get()); - // We don't "remove" a layer from CACFLayerTreeHost when it loses an animation. + // We don't "remove" a layer from AbstractCACFLayerTreeHost when it loses an animation. // There may be other active animations on the layer and if an animation // callback is fired on a layer without any animations no harm is done. diff --git a/Source/WebCore/platform/graphics/ca/win/WKCACFViewLayerTreeHost.cpp b/Source/WebCore/platform/graphics/ca/win/WKCACFViewLayerTreeHost.cpp index e672c2d..c4c3374 100644 --- a/Source/WebCore/platform/graphics/ca/win/WKCACFViewLayerTreeHost.cpp +++ b/Source/WebCore/platform/graphics/ca/win/WKCACFViewLayerTreeHost.cpp @@ -31,6 +31,7 @@ #include "PlatformCALayer.h" #include "SoftLinking.h" #include <wtf/CurrentTime.h> +#include <wtf/Threading.h> typedef struct _CACFLayer* CACFLayerRef; @@ -42,7 +43,13 @@ SOFT_LINK_DEBUG_LIBRARY(WebKitQuartzCoreAdditions) SOFT_LINK_LIBRARY(WebKitQuartzCoreAdditions) #endif -SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewCreate, WKCACFViewRef, __cdecl, (), ()) +enum WKCACFViewDrawingDestination { + kWKCACFViewDrawingDestinationWindow = 0, + kWKCACFViewDrawingDestinationImage, +}; +typedef enum WKCACFViewDrawingDestination WKCACFViewDrawingDestination; + +SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewCreate, WKCACFViewRef, __cdecl, (WKCACFViewDrawingDestination destination), (destination)) SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewSetLayer, void, __cdecl, (WKCACFViewRef view, CACFLayerRef layer), (view, layer)) SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewUpdate, void, __cdecl, (WKCACFViewRef view, HWND window, const CGRect* bounds), (view, window, bounds)) SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewCanDraw, bool, __cdecl, (WKCACFViewRef view), (view)) @@ -63,7 +70,7 @@ PassRefPtr<WKCACFViewLayerTreeHost> WKCACFViewLayerTreeHost::create() } WKCACFViewLayerTreeHost::WKCACFViewLayerTreeHost() - : m_view(AdoptCF, WKCACFViewCreate()) + : m_view(AdoptCF, WKCACFViewCreate(kWKCACFViewDrawingDestinationWindow)) , m_viewNeedsUpdate(true) { } @@ -98,6 +105,12 @@ void WKCACFViewLayerTreeHost::contextDidChangeCallback(WKCACFViewRef view, void* void WKCACFViewLayerTreeHost::contextDidChange() { + // This should only be called on a background thread when no changes have actually + // been committed to the context, eg. when a video frame has been added to an image + // queue, so return without triggering animations etc. + if (!isMainThread()) + return; + // Tell the WKCACFView to start rendering now that we have some contents to render. updateViewIfNeeded(); diff --git a/Source/WebCore/platform/graphics/cairo/CairoPath.h b/Source/WebCore/platform/graphics/cairo/CairoPath.h deleted file mode 100644 index da7affb..0000000 --- a/Source/WebCore/platform/graphics/cairo/CairoPath.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk> - Copyright (C) 2010 Igalia S.L. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - 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 CairoPath_h -#define CairoPath_h - -#include <cairo.h> - -namespace WebCore { - -// This is necessary since cairo_path_fixed_t isn't exposed in Cairo's public API. -class CairoPath { -public: - CairoPath() - { - static cairo_surface_t* pathSurface = cairo_image_surface_create(CAIRO_FORMAT_A8, 1, 1); - m_cr = cairo_create(pathSurface); - } - - ~CairoPath() - { - cairo_destroy(m_cr); - } - - cairo_t* context() { return m_cr; } - -private: - cairo_t* m_cr; -}; - -} // namespace WebCore - -#endif // CairoPath_h diff --git a/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp b/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp index ee159a1..758bce9 100644 --- a/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp +++ b/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp @@ -27,13 +27,13 @@ #include "CairoUtilities.h" #include "AffineTransform.h" -#include "CairoPath.h" #include "Color.h" #include "FloatPoint.h" #include "FloatRect.h" #include "IntRect.h" #include "OwnPtrCairo.h" #include "Path.h" +#include "PlatformPathCairo.h" #include "RefPtrCairo.h" #include <wtf/Vector.h> diff --git a/Source/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp b/Source/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp index 0f90ce4..d968ee9 100644 --- a/Source/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp @@ -42,11 +42,10 @@ using WTF::max; namespace WebCore { -static cairo_surface_t* scratchBuffer = 0; +static RefPtr<cairo_surface_t> gScratchBuffer; static void purgeScratchBuffer() { - cairo_surface_destroy(scratchBuffer); - scratchBuffer = 0; + gScratchBuffer.clear(); } // ContextShadow needs a scratch image as the buffer for the blur filter. @@ -68,20 +67,20 @@ static cairo_surface_t* getScratchBuffer(const IntSize& size) { int width = size.width(); int height = size.height(); - int scratchWidth = scratchBuffer ? cairo_image_surface_get_width(scratchBuffer) : 0; - int scratchHeight = scratchBuffer ? cairo_image_surface_get_height(scratchBuffer) : 0; + int scratchWidth = gScratchBuffer.get() ? cairo_image_surface_get_width(gScratchBuffer.get()) : 0; + int scratchHeight = gScratchBuffer.get() ? cairo_image_surface_get_height(gScratchBuffer.get()) : 0; // We do not need to recreate the buffer if the current buffer is large enough. - if (scratchBuffer && scratchWidth >= width && scratchHeight >= height) - return scratchBuffer; + if (gScratchBuffer.get() && scratchWidth >= width && scratchHeight >= height) + return gScratchBuffer.get(); purgeScratchBuffer(); // Round to the nearest 32 pixels so we do not grow the buffer for similar sized requests. width = (1 + (width >> 5)) << 5; height = (1 + (height >> 5)) << 5; - scratchBuffer = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); - return scratchBuffer; + gScratchBuffer = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height)); + return gScratchBuffer.get(); } PlatformContext ContextShadow::beginShadowLayer(GraphicsContext* context, const FloatRect& layerArea) diff --git a/Source/WebCore/platform/graphics/cairo/DrawErrorUnderline.h b/Source/WebCore/platform/graphics/cairo/DrawErrorUnderline.h index b90bb8c..3a49d5c 100644 --- a/Source/WebCore/platform/graphics/cairo/DrawErrorUnderline.h +++ b/Source/WebCore/platform/graphics/cairo/DrawErrorUnderline.h @@ -21,7 +21,7 @@ * */ -#if PLATFORM(CAIRO) +#if USE(CAIRO) #ifndef DrawErrorUnderline_h #define DrawErrorUnderline_h diff --git a/Source/WebCore/platform/graphics/cairo/GraphicsContext3DCairo.cpp b/Source/WebCore/platform/graphics/cairo/GraphicsContext3DCairo.cpp new file mode 100644 index 0000000..c90d8ab --- /dev/null +++ b/Source/WebCore/platform/graphics/cairo/GraphicsContext3DCairo.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2011 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GraphicsContext3D.h" +#include "PlatformContextCairo.h" + +#if ENABLE(WEBGL) + +#include "Image.h" +#include "RefPtrCairo.h" +#include <cairo.h> +#include <wtf/PassOwnPtr.h> + +namespace WebCore { + +bool GraphicsContext3D::getImageData(Image* image, unsigned int format, unsigned int type, bool premultiplyAlpha, bool ignoreGammaAndColorProfile, Vector<uint8_t>& outputVector) +{ + if (!image) + return false; + // We need this to stay in scope because the native image is just a shallow copy of the data. + ImageSource decoder(premultiplyAlpha ? ImageSource::AlphaPremultiplied : ImageSource::AlphaNotPremultiplied, + ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied); + AlphaOp alphaOp = AlphaDoNothing; + RefPtr<cairo_surface_t> imageSurface; + if (image->data()) { + decoder.setData(image->data(), true); + if (!decoder.frameCount() || !decoder.frameIsCompleteAtIndex(0)) + return false; + imageSurface = decoder.createFrameAtIndex(0); + } else { + imageSurface = image->nativeImageForCurrentFrame(); + if (!premultiplyAlpha) + alphaOp = AlphaDoUnmultiply; + } + + if (!imageSurface) + return false; + + int width = cairo_image_surface_get_width(imageSurface.get()); + int height = cairo_image_surface_get_height(imageSurface.get()); + if (!width || !height) + return false; + + if (cairo_image_surface_get_format(imageSurface.get()) != CAIRO_FORMAT_ARGB32) + return false; + + unsigned int srcUnpackAlignment = 1; + size_t bytesPerRow = cairo_image_surface_get_stride(imageSurface.get()); + size_t bitsPerPixel = 32; + unsigned int padding = bytesPerRow - bitsPerPixel / 8 * width; + if (padding) { + srcUnpackAlignment = padding + 1; + while (bytesPerRow % srcUnpackAlignment) + ++srcUnpackAlignment; + } + + outputVector.resize(width * height * 4); + return packPixels(cairo_image_surface_get_data(imageSurface.get()), SourceFormatBGRA8, + width, height, srcUnpackAlignment, format, type, alphaOp, outputVector.data()); +} + +void GraphicsContext3D::paintToCanvas(const unsigned char* imagePixels, int imageWidth, int imageHeight, int canvasWidth, int canvasHeight, PlatformContextCairo* context) +{ + if (!imagePixels || imageWidth <= 0 || imageHeight <= 0 || canvasWidth <= 0 || canvasHeight <= 0 || !context) + return; + + cairo_t *cr = context->cr(); + context->save(); + + cairo_rectangle(cr, 0, 0, canvasWidth, canvasHeight); + cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); + cairo_paint(cr); + + RefPtr<cairo_surface_t> imageSurface = adoptRef(cairo_image_surface_create_for_data( + const_cast<unsigned char*>(imagePixels), CAIRO_FORMAT_ARGB32, imageWidth, imageHeight, imageWidth * 4)); + + // OpenGL keeps the pixels stored bottom up, so we need to flip the image here. + cairo_translate(cr, 0, imageHeight); + cairo_scale(cr, 1, -1); + + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + cairo_set_source_surface(cr, imageSurface.get(), 0, 0); + cairo_rectangle(cr, 0, 0, canvasWidth, -canvasHeight); + + cairo_fill(cr); + context->restore(); +} + +void GraphicsContext3D::setContextLostCallback(PassOwnPtr<ContextLostCallback>) +{ +} + +} // namespace WebCore + +#endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp index 0fc94df..4cd0844 100644 --- a/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp @@ -32,10 +32,9 @@ #include "config.h" #include "GraphicsContext.h" -#if PLATFORM(CAIRO) +#if USE(CAIRO) #include "AffineTransform.h" -#include "CairoPath.h" #include "CairoUtilities.h" #include "ContextShadow.h" #include "FloatConversion.h" @@ -48,6 +47,7 @@ #include "Path.h" #include "Pattern.h" #include "PlatformContextCairo.h" +#include "PlatformPathCairo.h" #include "RefPtrCairo.h" #include "SimpleFontData.h" #include <cairo.h> @@ -201,8 +201,9 @@ static void strokeCurrentCairoPath(GraphicsContext* context, cairo_t* cairoCont } GraphicsContext::GraphicsContext(cairo_t* cr) + : m_updatingControlTints(false) { - m_data = new GraphicsContextPlatformPrivate(new PlatformContextCairo(cr)); + m_data = new GraphicsContextPlatformPrivateToplevel(new PlatformContextCairo(cr)); } void GraphicsContext::platformInit(PlatformContextCairo* platformContext) @@ -234,24 +235,13 @@ PlatformContextCairo* GraphicsContext::platformContext() const void GraphicsContext::savePlatformState() { - cairo_save(platformContext()->cr()); + platformContext()->save(); m_data->save(); m_data->shadowStack.append(m_data->shadow); - m_data->maskImageStack.append(ImageMaskInformation()); } void GraphicsContext::restorePlatformState() { - cairo_t* cr = platformContext()->cr(); - - const ImageMaskInformation& maskInformation = m_data->maskImageStack.last(); - if (maskInformation.isValid()) { - const FloatRect& maskRect = maskInformation.maskRect(); - cairo_pop_group_to_source(cr); - cairo_mask_surface(cr, maskInformation.maskSurface(), maskRect.x(), maskRect.y()); - } - m_data->maskImageStack.removeLast(); - if (m_data->shadowStack.isEmpty()) m_data->shadow = ContextShadow(); else { @@ -259,7 +249,7 @@ void GraphicsContext::restorePlatformState() m_data->shadowStack.removeLast(); } - cairo_restore(cr); + platformContext()->restore(); m_data->restore(); } @@ -765,7 +755,7 @@ void GraphicsContext::drawLineForTextChecking(const FloatPoint& origin, float wi cairo_restore(cr); } -FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect, RoundingMode) { FloatRect result; double x = frect.x(); @@ -1190,33 +1180,6 @@ InterpolationQuality GraphicsContext::imageInterpolationQuality() const return InterpolationDefault; } -void GraphicsContext::pushImageMask(cairo_surface_t* surface, const FloatRect& rect) -{ - // We must call savePlatformState at least once before we can use image masking, - // since we actually apply the mask in restorePlatformState. - ASSERT(!m_data->maskImageStack.isEmpty()); - m_data->maskImageStack.last().update(surface, rect); - - // Cairo doesn't support the notion of an image clip, so we push a group here - // and then paint it to the surface with an image mask (which is an immediate - // operation) during restorePlatformState. - - // We want to allow the clipped elements to composite with the surface as it - // is now, but they are isolated in another group. To make this work, we're - // going to blit the current surface contents onto the new group once we push it. - cairo_t* cr = platformContext()->cr(); - cairo_surface_t* currentTarget = cairo_get_target(cr); - cairo_surface_flush(currentTarget); - - // Pushing a new group ensures that only things painted after this point are clipped. - cairo_push_group(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - - cairo_set_source_surface(cr, currentTarget, 0, 0); - cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); - cairo_fill(cr); -} - } // namespace WebCore -#endif // PLATFORM(CAIRO) +#endif // USE(CAIRO) diff --git a/Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h b/Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h index 2bc290b..8fd056d 100644 --- a/Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h +++ b/Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h @@ -47,25 +47,6 @@ typedef struct _GdkExposeEvent GdkExposeEvent; namespace WebCore { -// In Cairo image masking is immediate, so to emulate image clipping we must save masking -// details as part of the context state and apply it during platform restore. -class ImageMaskInformation { -public: - void update(cairo_surface_t* maskSurface, const FloatRect& maskRect) - { - m_maskSurface = maskSurface; - m_maskRect = maskRect; - } - - bool isValid() const { return m_maskSurface; } - cairo_surface_t* maskSurface() const { return m_maskSurface.get(); } - const FloatRect& maskRect() const { return m_maskRect; } - -private: - RefPtr<cairo_surface_t> m_maskSurface; - FloatRect m_maskRect; -}; - class GraphicsContextPlatformPrivate { public: GraphicsContextPlatformPrivate(PlatformContextCairo* newPlatformContext) @@ -81,7 +62,7 @@ public: { } - ~GraphicsContextPlatformPrivate() + virtual ~GraphicsContextPlatformPrivate() { } @@ -121,7 +102,6 @@ public: Vector<float> layers; ContextShadow shadow; Vector<ContextShadow> shadowStack; - Vector<ImageMaskInformation> maskImageStack; #if PLATFORM(GTK) GdkEventExpose* expose; @@ -142,7 +122,7 @@ public: { } - ~GraphicsContextPlatformPrivateToplevel() + virtual ~GraphicsContextPlatformPrivateToplevel() { delete platformContext; } diff --git a/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp index 1d5d492..8aa6531 100644 --- a/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp @@ -55,11 +55,10 @@ static inline cairo_surface_t* copySurface(cairo_surface_t* surface) int height = cairo_image_surface_get_height(surface); cairo_surface_t* newsurface = cairo_image_surface_create(format, width, height); - cairo_t* cr = cairo_create(newsurface); - cairo_set_source_surface(cr, surface, 0, 0); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - cairo_paint(cr); - cairo_destroy(cr); + RefPtr<cairo_t> cr = adoptRef(cairo_create(newsurface)); + cairo_set_source_surface(cr.get(), surface, 0, 0); + cairo_set_operator(cr.get(), CAIRO_OPERATOR_SOURCE); + cairo_paint(cr.get()); return newsurface; } @@ -117,7 +116,7 @@ PassRefPtr<Image> ImageBuffer::copyImage() const void ImageBuffer::clip(GraphicsContext* context, const FloatRect& maskRect) const { - context->pushImageMask(m_data.m_surface, maskRect); + context->platformContext()->pushImageMask(m_data.m_surface, maskRect); } void ImageBuffer::draw(GraphicsContext* context, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, diff --git a/Source/WebCore/platform/graphics/cairo/ImageBufferData.h b/Source/WebCore/platform/graphics/cairo/ImageBufferDataCairo.h index 42867d1..5ca7262 100644 --- a/Source/WebCore/platform/graphics/cairo/ImageBufferData.h +++ b/Source/WebCore/platform/graphics/cairo/ImageBufferDataCairo.h @@ -23,9 +23,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ImageBufferData_h -#define ImageBufferData_h - #include "PlatformContextCairo.h" typedef struct _cairo_surface cairo_surface_t; @@ -42,6 +39,4 @@ public: PlatformContextCairo m_platformContext; }; -} // namespace WebCore - -#endif // ImageBufferData_h +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/cairo/ImageCairo.cpp b/Source/WebCore/platform/graphics/cairo/ImageCairo.cpp index d3a52ce..ce7d8b2 100644 --- a/Source/WebCore/platform/graphics/cairo/ImageCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/ImageCairo.cpp @@ -28,7 +28,7 @@ #include "config.h" #include "BitmapImage.h" -#if PLATFORM(CAIRO) +#if USE(CAIRO) #include "AffineTransform.h" #include "CairoUtilities.h" @@ -205,4 +205,4 @@ void BitmapImage::checkForSolidColor() } -#endif // PLATFORM(CAIRO) +#endif // USE(CAIRO) diff --git a/Source/WebCore/platform/graphics/cairo/OpenGLShims.cpp b/Source/WebCore/platform/graphics/cairo/OpenGLShims.cpp new file mode 100644 index 0000000..92d79f9 --- /dev/null +++ b/Source/WebCore/platform/graphics/cairo/OpenGLShims.cpp @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2011 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#if ENABLE(WEBGL) + +#define DISABLE_SHIMS +#include "OpenGLShims.h" + +#include <dlfcn.h> +#include <wtf/text/CString.h> +#include <wtf/text/WTFString.h> + +#define ASSIGN_FUNCTION_TABLE_ENTRY(FunctionName, success) \ + openGLFunctionTable()->FunctionName = reinterpret_cast<FunctionName##Type>(lookupOpenGLFunctionAddress(#FunctionName, success)) + +namespace WebCore { + +typedef void* (*glGetProcAddressType) (const char* procName); +static void* getProcAddress(const char* procName) +{ + static bool initialized = false; + static glGetProcAddressType getProcAddressFunction = 0; + + if (!initialized) { + getProcAddressFunction = reinterpret_cast<glGetProcAddressType>(dlsym(RTLD_DEFAULT, "glXGetProcAddress")); + if (!getProcAddressFunction) + getProcAddressFunction = reinterpret_cast<glGetProcAddressType>(dlsym(RTLD_DEFAULT, "glXGetProcAddressARB")); + } + + if (!getProcAddressFunction) + return dlsym(RTLD_DEFAULT, procName); + return getProcAddressFunction(procName); +} + +static void* lookupOpenGLFunctionAddress(const char* functionName, bool& success) +{ + if (!success) + return 0; + + void* target = getProcAddress(functionName); + if (target) + return target; + + String fullFunctionName(functionName); + fullFunctionName.append("ARB"); + target = getProcAddress(fullFunctionName.utf8().data()); + if (target) + return target; + + fullFunctionName = functionName; + fullFunctionName.append("EXT"); + target = getProcAddress(fullFunctionName.utf8().data()); + + // A null address is still a failure case. + if (!target) + success = false; + + return target; +} + +OpenGLFunctionTable* openGLFunctionTable() +{ + static OpenGLFunctionTable table; + return &table; +} + +bool initializeOpenGLShims() +{ + static bool success = true; + static bool initialized = false; + if (initialized) + return success; + + initialized = true; + ASSIGN_FUNCTION_TABLE_ENTRY(glActiveTexture, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glAttachShader, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glBindAttribLocation, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glBindBuffer, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glBindFramebuffer, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glBindRenderbuffer, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glBlendColor, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glBlendEquation, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glBlendEquationSeparate, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glBlendFuncSeparate, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glBlitFramebuffer, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glBufferData, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glBufferSubData, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glCheckFramebufferStatus, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glCompileShader, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glCreateProgram, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glCreateShader, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glDeleteBuffers, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glDeleteFramebuffers, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glDeleteProgram, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glDeleteRenderbuffers, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glDeleteShader, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glDetachShader, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glDisableVertexAttribArray, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glEnableVertexAttribArray, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glFramebufferRenderbuffer, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glFramebufferTexture2D, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGenBuffers, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGenerateMipmap, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGenFramebuffers, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGenRenderbuffers, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetActiveAttrib, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetActiveUniform, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetAttachedShaders, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetAttribLocation, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetBufferParameteriv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetFramebufferAttachmentParameteriv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetProgramInfoLog, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetProgramiv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetRenderbufferParameteriv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetShaderInfoLog, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetShaderiv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetShaderSource, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetUniformfv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetUniformiv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetUniformLocation, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetVertexAttribfv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetVertexAttribiv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetVertexAttribPointerv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glIsBuffer, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glIsFramebuffer, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glIsProgram, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glIsRenderbuffer, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glIsShader, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glLinkProgram, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glRenderbufferStorage, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glRenderbufferStorageMultisample, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glSampleCoverage, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glShaderSource, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glStencilFuncSeparate, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glStencilMaskSeparate, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glStencilOpSeparate, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform1f, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform1fv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform1i, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform1iv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform2f, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform2fv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform2i, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform2iv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform3f, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform3fv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform3i, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform3iv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform4f, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform4fv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform4i, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform4iv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniformMatrix2fv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniformMatrix3fv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniformMatrix4fv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUseProgram, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glValidateProgram, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glVertexAttrib1f, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glVertexAttrib1fv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glVertexAttrib2f, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glVertexAttrib2fv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glVertexAttrib3f, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glVertexAttrib3fv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glVertexAttrib4f, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glVertexAttrib4fv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glVertexAttribPointer, success); + + if (!success) + LOG_ERROR("Could not initialize OpenGL shims"); + return success; +} + +} // namespace WebCore + +#endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/cairo/OpenGLShims.h b/Source/WebCore/platform/graphics/cairo/OpenGLShims.h new file mode 100644 index 0000000..a431b03 --- /dev/null +++ b/Source/WebCore/platform/graphics/cairo/OpenGLShims.h @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2010 Tieto Corporation. + * Copyright (C) 2011 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <GL/gl.h> + +typedef struct _OpenGLFunctionTable OpenGLFunctionTable; + +namespace WebCore { +bool initializeOpenGLShims(); +OpenGLFunctionTable* openGLFunctionTable(); +} + +typedef void (*glActiveTextureType) (GLenum); +typedef void (*glAttachShaderType) (GLuint, GLuint); +typedef void (*glBindAttribLocationType) (GLuint, GLuint, const char*); +typedef void (*glBindBufferType) (GLenum, GLuint); +typedef void (*glBindFramebufferType) (GLenum, GLuint); +typedef void (*glBindRenderbufferType) (GLenum, GLuint); +typedef void (*glBlendColorType) (GLclampf, GLclampf, GLclampf, GLclampf); +typedef void (*glBlendEquationType) (GLenum); +typedef void (*glBlendEquationSeparateType)(GLenum, GLenum); +typedef void (*glBlendFuncSeparateType)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +typedef void (*glBlitFramebufferType) (GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum); +typedef void (*glBufferDataType) (GLenum, GLsizeiptr, const GLvoid*, GLenum); +typedef void (*glBufferSubDataType) (GLenum, GLintptr, GLsizeiptr, const GLvoid*); +typedef GLenum (*glCheckFramebufferStatusType) (GLenum); +typedef void (*glCompileShaderType) (GLuint); +typedef GLuint (*glCreateProgramType) (); +typedef GLuint (*glCreateShaderType) (GLenum); +typedef void (*glDeleteBuffersType) (GLsizei, const GLuint*); +typedef void (*glDeleteFramebuffersType) (GLsizei n, const GLuint*); +typedef void (*glDeleteProgramType) (GLuint); +typedef void (*glDeleteRenderbuffersType) (GLsizei n, const GLuint*); +typedef void (*glDeleteShaderType) (GLuint); +typedef void (*glDetachShaderType) (GLuint, GLuint); +typedef void (*glDisableVertexAttribArrayType) (GLuint); +typedef void (*glEnableVertexAttribArrayType) (GLuint); +typedef void (*glFramebufferRenderbufferType) (GLenum, GLenum, GLenum, GLuint); +typedef void (*glFramebufferTexture2DType) (GLenum, GLenum, GLenum, GLuint, GLint); +typedef void (*glGenBuffersType) (GLsizei, GLuint*); +typedef void (*glGenerateMipmapType) (GLenum target); +typedef void (*glGenFramebuffersType) (GLsizei, GLuint*); +typedef void (*glGenRenderbuffersType) (GLsizei, GLuint*); +typedef void (*glGetActiveAttribType) (GLuint, GLuint, GLsizei, GLsizei*, GLint*, GLenum*, GLchar*); +typedef void (*glGetActiveUniformType) (GLuint, GLuint, GLsizei, GLsizei*, GLint*, GLenum*, GLchar*); +typedef void (*glGetAttachedShadersType) (GLuint, GLsizei, GLsizei*, GLuint*); +typedef GLint (*glGetAttribLocationType) (GLuint, const char*); +typedef void (*glGetBufferParameterivType) (GLenum, GLenum, GLint*); +typedef void (*glGetFramebufferAttachmentParameterivType) (GLenum, GLenum, GLenum, GLint* params); +typedef void (*glGetProgramInfoLogType) (GLuint, GLsizei, GLsizei*, char*); +typedef void (*glGetProgramivType) (GLuint, GLenum, GLint*); +typedef void (*glGetRenderbufferParameterivType) (GLenum, GLenum, GLint*); +typedef void (*glGetShaderInfoLogType) (GLuint, GLsizei, GLsizei*, char*); +typedef void (*glGetShaderivType) (GLuint, GLenum, GLint*); +typedef void (*glGetShaderSourceType) (GLuint, GLsizei, GLsizei*, char*); +typedef GLint (*glGetUniformLocationType) (GLuint, const char*); +typedef void (*glGetUniformfvType) (GLuint, GLint, GLfloat*); +typedef void (*glGetUniformivType) (GLuint, GLint, GLint*); +typedef void (*glGetVertexAttribfvType) (GLuint, GLenum, GLfloat*); +typedef void (*glGetVertexAttribivType) (GLuint, GLenum, GLint*); +typedef void (*glGetVertexAttribPointervType) (GLuint, GLenum, GLvoid**); +typedef GLboolean (*glIsBufferType) (GLuint); +typedef GLboolean (*glIsFramebufferType) (GLuint); +typedef GLboolean (*glIsProgramType) (GLuint); +typedef GLboolean (*glIsRenderbufferType) (GLuint); +typedef GLboolean (*glIsShaderType) (GLuint); +typedef void (*glLinkProgramType) (GLuint); +typedef void (*glRenderbufferStorageType) (GLenum, GLenum, GLsizei, GLsizei); +typedef void (*glRenderbufferStorageMultisampleType) (GLenum, GLsizei, GLenum, GLsizei, GLsizei); +typedef void (*glSampleCoverageType) (GLclampf, GLboolean); +typedef void (*glShaderSourceType) (GLuint, GLsizei, const char**, const GLint*); +typedef void (*glStencilFuncSeparateType) (GLenum, GLenum, GLint, GLuint); +typedef void (*glStencilMaskSeparateType) (GLenum, GLuint); +typedef void (*glStencilOpSeparateType) (GLenum, GLenum, GLenum, GLenum); +typedef void (*glUniform1fType) (GLint, GLfloat); +typedef void (*glUniform1fvType) (GLint, GLsizei, const GLfloat*); +typedef void (*glUniform1iType) (GLint, GLint); +typedef void (*glUniform1ivType) (GLint, GLsizei, const GLint*); +typedef void (*glUniform2fType) (GLint, GLfloat, GLfloat); +typedef void (*glUniform2fvType) (GLint, GLsizei, const GLfloat*); +typedef void (*glUniform2iType) (GLint, GLint, GLint); +typedef void (*glUniform2ivType) (GLint, GLsizei, const GLint*); +typedef void (*glUniform3fType) (GLint, GLfloat, GLfloat, GLfloat); +typedef void (*glUniform3fvType) (GLint, GLsizei, const GLfloat*); +typedef void (*glUniform3iType) (GLint, GLint, GLint, GLint); +typedef void (*glUniform3ivType) (GLint, GLsizei, const GLint*); +typedef void (*glUniform4fType) (GLint, GLfloat, GLfloat, GLfloat, GLfloat); +typedef void (*glUniform4fvType) (GLint, GLsizei, const GLfloat*); +typedef void (*glUniform4iType) (GLint, GLint, GLint, GLint, GLint); +typedef void (*glUniform4ivType) (GLint, GLsizei, const GLint*); +typedef void (*glUniformMatrix2fvType) (GLint, GLsizei, GLboolean, const GLfloat*); +typedef void (*glUniformMatrix3fvType) (GLint, GLsizei, GLboolean, const GLfloat*); +typedef void (*glUniformMatrix4fvType) (GLint, GLsizei, GLboolean, const GLfloat*); +typedef void (*glUseProgramType) (GLuint); +typedef void (*glValidateProgramType) (GLuint); +typedef void (*glVertexAttrib1fType) (GLuint, const GLfloat); +typedef void (*glVertexAttrib1fvType) (GLuint, const GLfloat*); +typedef void (*glVertexAttrib2fType) (GLuint, const GLfloat, const GLfloat); +typedef void (*glVertexAttrib2fvType) (GLuint, const GLfloat*); +typedef void (*glVertexAttrib3fType) (GLuint, const GLfloat, const GLfloat, const GLfloat); +typedef void (*glVertexAttrib3fvType) (GLuint, const GLfloat*); +typedef void (*glVertexAttrib4fType) (GLuint, const GLfloat, const GLfloat, const GLfloat, const GLfloat); +typedef void (*glVertexAttrib4fvType) (GLuint, const GLfloat*); +typedef void (*glVertexAttribPointerType) (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid*); + +#define FUNCTION_TABLE_ENTRY(FunctionName) FunctionName##Type FunctionName + +typedef struct _OpenGLFunctionTable { + FUNCTION_TABLE_ENTRY(glActiveTexture); + FUNCTION_TABLE_ENTRY(glAttachShader); + FUNCTION_TABLE_ENTRY(glBindAttribLocation); + FUNCTION_TABLE_ENTRY(glBindBuffer); + FUNCTION_TABLE_ENTRY(glBindFramebuffer); + FUNCTION_TABLE_ENTRY(glBindRenderbuffer); + FUNCTION_TABLE_ENTRY(glBlendColor); + FUNCTION_TABLE_ENTRY(glBlendEquation); + FUNCTION_TABLE_ENTRY(glBlendEquationSeparate); + FUNCTION_TABLE_ENTRY(glBlendFuncSeparate); + FUNCTION_TABLE_ENTRY(glBlitFramebuffer); + FUNCTION_TABLE_ENTRY(glBufferData); + FUNCTION_TABLE_ENTRY(glBufferSubData); + FUNCTION_TABLE_ENTRY(glCheckFramebufferStatus); + FUNCTION_TABLE_ENTRY(glCompileShader); + FUNCTION_TABLE_ENTRY(glCreateProgram); + FUNCTION_TABLE_ENTRY(glCreateShader); + FUNCTION_TABLE_ENTRY(glDeleteBuffers); + FUNCTION_TABLE_ENTRY(glDeleteFramebuffers); + FUNCTION_TABLE_ENTRY(glDeleteProgram); + FUNCTION_TABLE_ENTRY(glDeleteRenderbuffers); + FUNCTION_TABLE_ENTRY(glDeleteShader); + FUNCTION_TABLE_ENTRY(glDetachShader); + FUNCTION_TABLE_ENTRY(glDisableVertexAttribArray); + FUNCTION_TABLE_ENTRY(glEnableVertexAttribArray); + FUNCTION_TABLE_ENTRY(glFramebufferRenderbuffer); + FUNCTION_TABLE_ENTRY(glFramebufferTexture2D); + FUNCTION_TABLE_ENTRY(glGenBuffers); + FUNCTION_TABLE_ENTRY(glGenerateMipmap); + FUNCTION_TABLE_ENTRY(glGenFramebuffers); + FUNCTION_TABLE_ENTRY(glGenRenderbuffers); + FUNCTION_TABLE_ENTRY(glGetActiveAttrib); + FUNCTION_TABLE_ENTRY(glGetActiveUniform); + FUNCTION_TABLE_ENTRY(glGetAttachedShaders); + FUNCTION_TABLE_ENTRY(glGetAttribLocation); + FUNCTION_TABLE_ENTRY(glGetBufferParameteriv); + FUNCTION_TABLE_ENTRY(glGetFramebufferAttachmentParameteriv); + FUNCTION_TABLE_ENTRY(glGetProgramInfoLog); + FUNCTION_TABLE_ENTRY(glGetProgramiv); + FUNCTION_TABLE_ENTRY(glGetRenderbufferParameteriv); + FUNCTION_TABLE_ENTRY(glGetShaderInfoLog); + FUNCTION_TABLE_ENTRY(glGetShaderiv); + FUNCTION_TABLE_ENTRY(glGetShaderSource); + FUNCTION_TABLE_ENTRY(glGetUniformfv); + FUNCTION_TABLE_ENTRY(glGetUniformiv); + FUNCTION_TABLE_ENTRY(glGetUniformLocation); + FUNCTION_TABLE_ENTRY(glGetVertexAttribfv); + FUNCTION_TABLE_ENTRY(glGetVertexAttribiv); + FUNCTION_TABLE_ENTRY(glGetVertexAttribPointerv); + FUNCTION_TABLE_ENTRY(glIsBuffer); + FUNCTION_TABLE_ENTRY(glIsFramebuffer); + FUNCTION_TABLE_ENTRY(glIsProgram); + FUNCTION_TABLE_ENTRY(glIsRenderbuffer); + FUNCTION_TABLE_ENTRY(glIsShader); + FUNCTION_TABLE_ENTRY(glLinkProgram); + FUNCTION_TABLE_ENTRY(glRenderbufferStorage); + FUNCTION_TABLE_ENTRY(glRenderbufferStorageMultisample); + FUNCTION_TABLE_ENTRY(glSampleCoverage); + FUNCTION_TABLE_ENTRY(glShaderSource); + FUNCTION_TABLE_ENTRY(glStencilFuncSeparate); + FUNCTION_TABLE_ENTRY(glStencilMaskSeparate); + FUNCTION_TABLE_ENTRY(glStencilOpSeparate); + FUNCTION_TABLE_ENTRY(glUniform1f); + FUNCTION_TABLE_ENTRY(glUniform1fv); + FUNCTION_TABLE_ENTRY(glUniform1i); + FUNCTION_TABLE_ENTRY(glUniform1iv); + FUNCTION_TABLE_ENTRY(glUniform2f); + FUNCTION_TABLE_ENTRY(glUniform2fv); + FUNCTION_TABLE_ENTRY(glUniform2i); + FUNCTION_TABLE_ENTRY(glUniform2iv); + FUNCTION_TABLE_ENTRY(glUniform3f); + FUNCTION_TABLE_ENTRY(glUniform3fv); + FUNCTION_TABLE_ENTRY(glUniform3i); + FUNCTION_TABLE_ENTRY(glUniform3iv); + FUNCTION_TABLE_ENTRY(glUniform4f); + FUNCTION_TABLE_ENTRY(glUniform4fv); + FUNCTION_TABLE_ENTRY(glUniform4i); + FUNCTION_TABLE_ENTRY(glUniform4iv); + FUNCTION_TABLE_ENTRY(glUniformMatrix2fv); + FUNCTION_TABLE_ENTRY(glUniformMatrix3fv); + FUNCTION_TABLE_ENTRY(glUniformMatrix4fv); + FUNCTION_TABLE_ENTRY(glUseProgram); + FUNCTION_TABLE_ENTRY(glValidateProgram); + FUNCTION_TABLE_ENTRY(glVertexAttrib1f); + FUNCTION_TABLE_ENTRY(glVertexAttrib1fv); + FUNCTION_TABLE_ENTRY(glVertexAttrib2f); + FUNCTION_TABLE_ENTRY(glVertexAttrib2fv); + FUNCTION_TABLE_ENTRY(glVertexAttrib3f); + FUNCTION_TABLE_ENTRY(glVertexAttrib3fv); + FUNCTION_TABLE_ENTRY(glVertexAttrib4f); + FUNCTION_TABLE_ENTRY(glVertexAttrib4fv); + FUNCTION_TABLE_ENTRY(glVertexAttribPointer); +} OpenGLFunctionTable; + +// We disable the shims for OpenGLShims.cpp, so that we can set them. +#ifndef DISABLE_SHIMS +#define LOOKUP_GL_FUNCTION(Function) WebCore::openGLFunctionTable()->Function +#define glActiveTexture LOOKUP_GL_FUNCTION(glActiveTexture) +#define glAttachShader LOOKUP_GL_FUNCTION(glAttachShader) +#define glBindAttribLocation LOOKUP_GL_FUNCTION(glBindAttribLocation) +#define glBindBuffer LOOKUP_GL_FUNCTION(glBindBuffer) +#define glBindFramebufferEXT LOOKUP_GL_FUNCTION(glBindFramebuffer) +#define glBindRenderbufferEXT LOOKUP_GL_FUNCTION(glBindRenderbuffer) +#define glBlendColor LOOKUP_GL_FUNCTION(glBlendColor) +#define glBlendEquation LOOKUP_GL_FUNCTION(glBlendEquation) +#define glBlendEquationSeparate LOOKUP_GL_FUNCTION(glBlendEquationSeparate) +#define glBlendFuncSeparate LOOKUP_GL_FUNCTION(glBlendFuncSeparate) +#define glBlitFramebufferEXT LOOKUP_GL_FUNCTION(glBlitFramebuffer) +#define glBufferData LOOKUP_GL_FUNCTION(glBufferData) +#define glBufferSubData LOOKUP_GL_FUNCTION(glBufferSubData) +#define glCheckFramebufferStatusEXT LOOKUP_GL_FUNCTION(glCheckFramebufferStatus) +#define glCompileShader LOOKUP_GL_FUNCTION(glCompileShader) +#define glCreateProgram LOOKUP_GL_FUNCTION(glCreateProgram) +#define glCreateShader LOOKUP_GL_FUNCTION(glCreateShader) +#define glDeleteBuffers LOOKUP_GL_FUNCTION(glDeleteBuffers) +#define glDeleteFramebuffersEXT LOOKUP_GL_FUNCTION(glDeleteFramebuffers) +#define glDeleteProgram LOOKUP_GL_FUNCTION(glDeleteProgram) +#define glDeleteRenderbuffersEXT LOOKUP_GL_FUNCTION(glDeleteRenderbuffers) +#define glDeleteShader LOOKUP_GL_FUNCTION(glDeleteShader) +#define glDetachShader LOOKUP_GL_FUNCTION(glDetachShader) +#define glDisableVertexAttribArray LOOKUP_GL_FUNCTION(glDisableVertexAttribArray) +#define glEnableVertexAttribArray LOOKUP_GL_FUNCTION(glEnableVertexAttribArray) +#define glFramebufferRenderbufferEXT LOOKUP_GL_FUNCTION(glFramebufferRenderbuffer) +#define glFramebufferTexture2DEXT LOOKUP_GL_FUNCTION(glFramebufferTexture2D) +#define glGenBuffers LOOKUP_GL_FUNCTION(glGenBuffers) +#define glGenerateMipmapEXT LOOKUP_GL_FUNCTION(glGenerateMipmap) +#define glGenFramebuffersEXT LOOKUP_GL_FUNCTION(glGenFramebuffers) +#define glGenRenderbuffersEXT LOOKUP_GL_FUNCTION(glGenRenderbuffers) +#define glGetActiveAttrib LOOKUP_GL_FUNCTION(glGetActiveAttrib) +#define glGetActiveUniform LOOKUP_GL_FUNCTION(glGetActiveUniform) +#define glGetAttachedShaders LOOKUP_GL_FUNCTION(glGetAttachedShaders) +#define glGetAttribLocation LOOKUP_GL_FUNCTION(glGetAttribLocation) +#define glGetBufferParameteriv LOOKUP_GL_FUNCTION(glGetBufferParameteriv) +#define glGetBufferParameterivEXT LOOKUP_GL_FUNCTION(glGetBufferParameteriv) +#define glGetFramebufferAttachmentParameterivEXT LOOKUP_GL_FUNCTION(glGetFramebufferAttachmentParameteriv) +#define glGetProgramInfoLog LOOKUP_GL_FUNCTION(glGetProgramInfoLog) +#define glGetProgramiv LOOKUP_GL_FUNCTION(glGetProgramiv) +#define glGetRenderbufferParameterivEXT LOOKUP_GL_FUNCTION(glGetRenderbufferParameteriv) +#define glGetShaderInfoLog LOOKUP_GL_FUNCTION(glGetShaderInfoLog) +#define glGetShaderiv LOOKUP_GL_FUNCTION(glGetShaderiv) +#define glGetShaderSource LOOKUP_GL_FUNCTION(glGetShaderSource) +#define glGetUniformfv LOOKUP_GL_FUNCTION(glGetUniformfv) +#define glGetUniformiv LOOKUP_GL_FUNCTION(glGetUniformiv) +#define glGetUniformLocation LOOKUP_GL_FUNCTION(glGetUniformLocation) +#define glGetVertexAttribfv LOOKUP_GL_FUNCTION(glGetVertexAttribfv) +#define glGetVertexAttribiv LOOKUP_GL_FUNCTION(glGetVertexAttribiv) +#define glGetVertexAttribPointerv LOOKUP_GL_FUNCTION(glGetVertexAttribPointerv) +#define glIsBuffer LOOKUP_GL_FUNCTION(glIsBuffer) +#define glIsFramebufferEXT LOOKUP_GL_FUNCTION(glIsFramebuffer) +#define glIsProgram LOOKUP_GL_FUNCTION(glIsProgram) +#define glIsRenderbufferEXT LOOKUP_GL_FUNCTION(glIsRenderbuffer) +#define glIsShader LOOKUP_GL_FUNCTION(glIsShader) +#define glLinkProgram LOOKUP_GL_FUNCTION(glLinkProgram) +#define glRenderbufferStorageEXT LOOKUP_GL_FUNCTION(glRenderbufferStorage) +#define glRenderbufferStorageMultisampleEXT LOOKUP_GL_FUNCTION(glRenderbufferStorageMultisample) +#define glSampleCoverage LOOKUP_GL_FUNCTION(glSampleCoverage) +#define glShaderSource LOOKUP_GL_FUNCTION(glShaderSource) +#define glStencilFuncSeparate LOOKUP_GL_FUNCTION(glStencilFuncSeparate) +#define glStencilMaskSeparate LOOKUP_GL_FUNCTION(glStencilMaskSeparate) +#define glStencilOpSeparate LOOKUP_GL_FUNCTION(glStencilOpSeparate) +#define glUniform1f LOOKUP_GL_FUNCTION(glUniform1f) +#define glUniform1fv LOOKUP_GL_FUNCTION(glUniform1fv) +#define glUniform1i LOOKUP_GL_FUNCTION(glUniform1i) +#define glUniform1iv LOOKUP_GL_FUNCTION(glUniform1iv) +#define glUniform2f LOOKUP_GL_FUNCTION(glUniform2f) +#define glUniform2fv LOOKUP_GL_FUNCTION(glUniform2fv) +#define glUniform2i LOOKUP_GL_FUNCTION(glUniform2i) +#define glUniform2iv LOOKUP_GL_FUNCTION(glUniform2iv) +#define glUniform3f LOOKUP_GL_FUNCTION(glUniform3f) +#define glUniform3fv LOOKUP_GL_FUNCTION(glUniform3fv) +#define glUniform3i LOOKUP_GL_FUNCTION(glUniform3i) +#define glUniform3iv LOOKUP_GL_FUNCTION(glUniform3iv) +#define glUniform4f LOOKUP_GL_FUNCTION(glUniform4f) +#define glUniform4fv LOOKUP_GL_FUNCTION(glUniform4fv) +#define glUniform4i LOOKUP_GL_FUNCTION(glUniform4i) +#define glUniform4iv LOOKUP_GL_FUNCTION(glUniform4iv) +#define glUniformMatrix2fv LOOKUP_GL_FUNCTION(glUniformMatrix2fv) +#define glUniformMatrix3fv LOOKUP_GL_FUNCTION(glUniformMatrix3fv) +#define glUniformMatrix4fv LOOKUP_GL_FUNCTION(glUniformMatrix4fv) +#define glUseProgram LOOKUP_GL_FUNCTION(glUseProgram) +#define glValidateProgram LOOKUP_GL_FUNCTION(glValidateProgram) +#define glVertexAttrib1f LOOKUP_GL_FUNCTION(glVertexAttrib1f) +#define glVertexAttrib1fv LOOKUP_GL_FUNCTION(glVertexAttrib1fv) +#define glVertexAttrib2f LOOKUP_GL_FUNCTION(glVertexAttrib2f) +#define glVertexAttrib2fv LOOKUP_GL_FUNCTION(glVertexAttrib2fv) +#define glVertexAttrib3f LOOKUP_GL_FUNCTION(glVertexAttrib3f) +#define glVertexAttrib3fv LOOKUP_GL_FUNCTION(glVertexAttrib3fv) +#define glVertexAttrib4f LOOKUP_GL_FUNCTION(glVertexAttrib4f) +#define glVertexAttrib4fv LOOKUP_GL_FUNCTION(glVertexAttrib4fv) +#define glVertexAttribPointer LOOKUP_GL_FUNCTION(glVertexAttribPointer) +#endif diff --git a/Source/WebCore/platform/graphics/cairo/PathCairo.cpp b/Source/WebCore/platform/graphics/cairo/PathCairo.cpp index 533df10..d62c33f 100644 --- a/Source/WebCore/platform/graphics/cairo/PathCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/PathCairo.cpp @@ -27,10 +27,10 @@ #include "Path.h" #include "AffineTransform.h" -#include "CairoPath.h" #include "FloatRect.h" #include "GraphicsContext.h" #include "OwnPtrCairo.h" +#include "PlatformPathCairo.h" #include "PlatformString.h" #include "StrokeStyleApplier.h" #include <cairo.h> diff --git a/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.cpp b/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.cpp index ba75162..061ee06 100644 --- a/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.cpp @@ -35,4 +35,51 @@ PlatformContextCairo::PlatformContextCairo(cairo_t* cr) { } +void PlatformContextCairo::restore() +{ + const ImageMaskInformation& maskInformation = m_maskImageStack.last(); + if (maskInformation.isValid()) { + const FloatRect& maskRect = maskInformation.maskRect(); + cairo_pop_group_to_source(m_cr.get()); + cairo_mask_surface(m_cr.get(), maskInformation.maskSurface(), maskRect.x(), maskRect.y()); + } + m_maskImageStack.removeLast(); + + cairo_restore(m_cr.get()); +} + +void PlatformContextCairo::save() +{ + m_maskImageStack.append(ImageMaskInformation()); + + cairo_save(m_cr.get()); +} + +void PlatformContextCairo::pushImageMask(cairo_surface_t* surface, const FloatRect& rect) +{ + // We must call savePlatformState at least once before we can use image masking, + // since we actually apply the mask in restorePlatformState. + ASSERT(!m_maskImageStack.isEmpty()); + m_maskImageStack.last().update(surface, rect); + + // Cairo doesn't support the notion of an image clip, so we push a group here + // and then paint it to the surface with an image mask (which is an immediate + // operation) during restorePlatformState. + + // We want to allow the clipped elements to composite with the surface as it + // is now, but they are isolated in another group. To make this work, we're + // going to blit the current surface contents onto the new group once we push it. + cairo_surface_t* currentTarget = cairo_get_target(m_cr.get()); + cairo_surface_flush(currentTarget); + + // Pushing a new group ensures that only things painted after this point are clipped. + cairo_push_group(m_cr.get()); + cairo_set_operator(m_cr.get(), CAIRO_OPERATOR_SOURCE); + + cairo_set_source_surface(m_cr.get(), currentTarget, 0, 0); + cairo_rectangle(m_cr.get(), rect.x(), rect.y(), rect.width(), rect.height()); + cairo_fill(m_cr.get()); +} + + } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.h b/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.h index c6cceda..937417a 100644 --- a/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.h +++ b/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.h @@ -31,6 +31,25 @@ namespace WebCore { +// In Cairo image masking is immediate, so to emulate image clipping we must save masking +// details as part of the context state and apply them during platform restore. +class ImageMaskInformation { +public: + void update(cairo_surface_t* maskSurface, const FloatRect& maskRect) + { + m_maskSurface = maskSurface; + m_maskRect = maskRect; + } + + bool isValid() const { return m_maskSurface; } + cairo_surface_t* maskSurface() const { return m_maskSurface.get(); } + const FloatRect& maskRect() const { return m_maskRect; } + +private: + RefPtr<cairo_surface_t> m_maskSurface; + FloatRect m_maskRect; +}; + // Much like PlatformContextSkia in the Skia port, this class holds information that // would normally be private to GraphicsContext, except that we want to allow access // to it in Font and Image code. This allows us to separate the concerns of Cairo-specific @@ -40,11 +59,17 @@ class PlatformContextCairo { WTF_MAKE_NONCOPYABLE(PlatformContextCairo); public: PlatformContextCairo(cairo_t*); + cairo_t* cr() { return m_cr.get(); } void setCr(cairo_t* cr) { m_cr = cr; } + void save(); + void restore(); + void pushImageMask(cairo_surface_t*, const FloatRect&); + private: RefPtr<cairo_t> m_cr; + Vector<ImageMaskInformation> m_maskImageStack; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/cairo/PlatformPathCairo.cpp b/Source/WebCore/platform/graphics/cairo/PlatformPathCairo.cpp new file mode 100644 index 0000000..3a7d512 --- /dev/null +++ b/Source/WebCore/platform/graphics/cairo/PlatformPathCairo.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2011 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. + */ + +#include "config.h" +#include "PlatformPathCairo.h" + +#include <cairo.h> + +namespace WebCore { + +static cairo_surface_t* getPathSurface() +{ + return cairo_image_surface_create(CAIRO_FORMAT_A8, 1, 1); +} + +static cairo_surface_t* gPathSurface = getPathSurface(); + +CairoPath::CairoPath() + : m_cr(adoptRef(cairo_create(gPathSurface))) +{ +} + +} diff --git a/Source/WebCore/platform/graphics/cairo/PlatformPathCairo.h b/Source/WebCore/platform/graphics/cairo/PlatformPathCairo.h new file mode 100644 index 0000000..938b942 --- /dev/null +++ b/Source/WebCore/platform/graphics/cairo/PlatformPathCairo.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk> + * Copyright (C) 2010 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef PlatformPathCairo_h +#define PlatformPathCairo_h + +#include "RefPtrCairo.h" + +namespace WebCore { + +// This is necessary since cairo_path_fixed_t isn't exposed in Cairo's public API. +class CairoPath { +public: + CairoPath(); + + ~CairoPath() {} + + cairo_t* context() { return m_cr.get(); } + +private: + RefPtr<cairo_t> m_cr; +}; + +} // namespace WebCore + +#endif // PlatformPathCairo_h diff --git a/Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp b/Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp index 1792002..90bc3b1 100644 --- a/Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp @@ -61,7 +61,7 @@ template<> void refIfNotNull(cairo_font_face_t* ptr) template<> void derefIfNotNull(cairo_font_face_t* ptr) { if (LIKELY(ptr != 0)) - cairo_font_face_reference(ptr); + cairo_font_face_destroy(ptr); } template<> void refIfNotNull(cairo_scaled_font_t* ptr) diff --git a/Source/WebCore/platform/graphics/cg/ColorCG.cpp b/Source/WebCore/platform/graphics/cg/ColorCG.cpp index c9b05da..55a3017 100644 --- a/Source/WebCore/platform/graphics/cg/ColorCG.cpp +++ b/Source/WebCore/platform/graphics/cg/ColorCG.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "Color.h" -#if PLATFORM(CG) +#if USE(CG) #include "GraphicsContextCG.h" #include <wtf/Assertions.h> @@ -146,4 +146,4 @@ CGColorRef cachedCGColor(const Color& color, ColorSpace colorSpace) } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/cg/FloatPointCG.cpp b/Source/WebCore/platform/graphics/cg/FloatPointCG.cpp index f9c3353..5e7aab3 100644 --- a/Source/WebCore/platform/graphics/cg/FloatPointCG.cpp +++ b/Source/WebCore/platform/graphics/cg/FloatPointCG.cpp @@ -27,7 +27,7 @@ #include "config.h" #include "FloatPoint.h" -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) #include <ApplicationServices/ApplicationServices.h> @@ -44,4 +44,4 @@ FloatPoint::operator CGPoint() const } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/cg/FloatRectCG.cpp b/Source/WebCore/platform/graphics/cg/FloatRectCG.cpp index a1ce367..131b7ac 100644 --- a/Source/WebCore/platform/graphics/cg/FloatRectCG.cpp +++ b/Source/WebCore/platform/graphics/cg/FloatRectCG.cpp @@ -27,7 +27,7 @@ #include "config.h" #include "FloatRect.h" -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) #include <ApplicationServices/ApplicationServices.h> @@ -44,4 +44,4 @@ FloatRect::operator CGRect() const } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/cg/FloatSizeCG.cpp b/Source/WebCore/platform/graphics/cg/FloatSizeCG.cpp index 383af21..a035c7a 100644 --- a/Source/WebCore/platform/graphics/cg/FloatSizeCG.cpp +++ b/Source/WebCore/platform/graphics/cg/FloatSizeCG.cpp @@ -27,7 +27,7 @@ #include "config.h" #include "FloatSize.h" -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) #include <ApplicationServices/ApplicationServices.h> @@ -44,4 +44,4 @@ FloatSize::operator CGSize() const } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp b/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp index 187d296..57abe71 100644 --- a/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp +++ b/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp @@ -29,8 +29,9 @@ #if ENABLE(WEBGL) #include "GraphicsContext3D.h" -#include "GraphicsContextCG.h" +#include "BitmapImage.h" +#include "GraphicsContextCG.h" #include "Image.h" #include <CoreGraphics/CGBitmapContext.h> @@ -99,7 +100,8 @@ bool GraphicsContext3D::getImageData(Image* image, return false; CGImageRef cgImage; RetainPtr<CGImageRef> decodedImage; - if (image->data()) { + bool hasAlpha = image->isBitmapImage() ? static_cast<BitmapImage*>(image)->frameHasAlphaAtIndex(0) : true; + if ((ignoreGammaAndColorProfile || (hasAlpha && !premultiplyAlpha)) && image->data()) { ImageSource decoder(ImageSource::AlphaNotPremultiplied, ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied); decoder.setData(image->data(), true); @@ -196,11 +198,6 @@ bool GraphicsContext3D::getImageData(Image* image, AlphaFormat alphaFormat = AlphaFormatNone; switch (CGImageGetAlphaInfo(cgImage)) { case kCGImageAlphaPremultipliedFirst: - // This is a special case for texImage2D with HTMLCanvasElement input, - // in which case image->data() should be null, or indexed color models, - // where we need premultiplied alpha to create the bitmap context - // successfully. - ASSERT(!image->data() || model == kCGColorSpaceModelIndexed); if (!premultiplyAlpha) neededAlphaOp = AlphaDoUnmultiply; alphaFormat = AlphaFormatFirst; @@ -216,9 +213,6 @@ bool GraphicsContext3D::getImageData(Image* image, alphaFormat = AlphaFormatFirst; break; case kCGImageAlphaPremultipliedLast: - // This is a special case for texImage2D with HTMLCanvasElement input, - // in which case image->data() should be null. - ASSERT(!image->data()); if (!premultiplyAlpha) neededAlphaOp = AlphaDoUnmultiply; alphaFormat = AlphaFormatLast; diff --git a/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp index 7799137..c7626b9 100644 --- a/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp +++ b/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp @@ -756,9 +756,6 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef if (oldFillColor != color || oldColorSpace != colorSpace) setCGFillColor(context, color, colorSpace); - Path path; - path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight); - bool drawOwnShadow = !isAcceleratedContext() && hasBlurredShadow(m_state) && !m_state.shadowsIgnoreTransforms; // Don't use ShadowBlur for canvas yet. if (drawOwnShadow) { float shadowBlur = m_state.shadowsUseLegacyRadius ? radiusToLegacyRadius(m_state.shadowBlur) : m_state.shadowBlur; @@ -771,7 +768,15 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef contextShadow.drawRectShadow(this, rect, RoundedIntRect::Radii(topLeft, topRight, bottomLeft, bottomRight)); } - fillPath(path); + bool equalWidths = (topLeft.width() == topRight.width() && topRight.width() == bottomLeft.width() && bottomLeft.width() == bottomRight.width()); + bool equalHeights = (topLeft.height() == bottomLeft.height() && bottomLeft.height() == topRight.height() && topRight.height() == bottomRight.height()); + if (equalWidths && equalHeights && topLeft.width() * 2 == rect.width() && topLeft.height() * 2 == rect.height()) + CGContextFillEllipseInRect(context, rect); + else { + Path path; + path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight); + fillPath(path); + } if (drawOwnShadow) CGContextRestoreGState(context); @@ -791,7 +796,7 @@ void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const Rounded path.addRect(rect); if (!roundedHoleRect.radii().isZero()) - path.addRoundedRect(roundedHoleRect.rect(), roundedHoleRect.radii().topLeft(), roundedHoleRect.radii().topRight(), roundedHoleRect.radii().bottomLeft(), roundedHoleRect.radii().bottomRight()); + path.addRoundedRect(roundedHoleRect); else path.addRect(roundedHoleRect.rect()); @@ -1167,8 +1172,11 @@ AffineTransform GraphicsContext::getCTM() const return AffineTransform(t.a, t.b, t.c, t.d, t.tx, t.ty); } -FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect, RoundingMode roundingMode) { +#if PLATFORM(CHROMIUM) + return rect; +#else // It is not enough just to round to pixels in device space. The rotation part of the // affine transform matrix to device space can mess with this conversion if we have a // rotating image like the hands of the world clock widget. We just need the scale, so @@ -1192,8 +1200,13 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) deviceOrigin.x = roundf(deviceOrigin.x); deviceOrigin.y = roundf(deviceOrigin.y); - deviceLowerRight.x = roundf(deviceLowerRight.x); - deviceLowerRight.y = roundf(deviceLowerRight.y); + if (roundingMode == RoundAllSides) { + deviceLowerRight.x = roundf(deviceLowerRight.x); + deviceLowerRight.y = roundf(deviceLowerRight.y); + } else { + deviceLowerRight.x = deviceOrigin.x + roundf(rect.width() * deviceScaleX); + deviceLowerRight.y = deviceOrigin.y + roundf(rect.height() * deviceScaleY); + } // Don't let the height or width round to 0 unless either was originally 0 if (deviceOrigin.y == deviceLowerRight.y && rect.height()) @@ -1204,6 +1217,7 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) FloatPoint roundedOrigin = FloatPoint(deviceOrigin.x / deviceScaleX, deviceOrigin.y / deviceScaleY); FloatPoint roundedLowerRight = FloatPoint(deviceLowerRight.x / deviceScaleX, deviceLowerRight.y / deviceScaleY); return FloatRect(roundedOrigin, roundedLowerRight - roundedOrigin); +#endif } void GraphicsContext::drawLineForText(const FloatPoint& point, float width, bool printing) @@ -1232,7 +1246,7 @@ void GraphicsContext::drawLineForText(const FloatPoint& point, float width, bool // We try to round all parameters to integer boundaries in device space. If rounding pixels in device space // makes our thickness more than double, then there must be a shrinking-scale factor and rounding to pixels // in device space will make the underlines too thick. - CGRect lineRect = roundToDevicePixels(FloatRect(x, y, lineLength, adjustedThickness)); + CGRect lineRect = roundToDevicePixels(FloatRect(x, y, lineLength, adjustedThickness), RoundOriginAndDimensions); if (lineRect.size.height < thickness * 2.0) { x = lineRect.origin.x; y = lineRect.origin.y; diff --git a/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp b/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp index 3c8f959..95ce8c1 100644 --- a/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp +++ b/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp @@ -42,10 +42,6 @@ #include <wtf/Threading.h> #include <math.h> -#if USE(IOSURFACE_CANVAS_BACKING_STORE) -#include <IOSurface/IOSurface.h> -#endif - #if PLATFORM(MAC) || PLATFORM(CHROMIUM) #include "WebCoreSystemInterface.h" #endif @@ -56,6 +52,7 @@ namespace WebCore { #if USE(IOSURFACE_CANVAS_BACKING_STORE) static const int maxIOSurfaceDimension = 4096; +static const int minIOSurfaceArea = 50 * 100; static RetainPtr<IOSurfaceRef> createIOSurface(const IntSize& size) { @@ -100,14 +97,6 @@ static void releaseImageData(void*, const void* data, size_t) fastFree(const_cast<void*>(data)); } -ImageBufferData::ImageBufferData(const IntSize&) - : m_data(0) -#if USE(IOSURFACE_CANVAS_BACKING_STORE) - , m_surface(0) -#endif -{ -} - ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace imageColorSpace, RenderingMode renderingMode, bool& success) : m_data(size) , m_size(size) @@ -117,7 +106,7 @@ ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace imageColorSpace, Render if (size.width() < 0 || size.height() < 0) return; #if USE(IOSURFACE_CANVAS_BACKING_STORE) - if (size.width() >= maxIOSurfaceDimension || size.height() >= maxIOSurfaceDimension) + if (size.width() >= maxIOSurfaceDimension || size.height() >= maxIOSurfaceDimension || size.width() * size.height() < minIOSurfaceArea) m_accelerateRendering = false; #else ASSERT(renderingMode == Unaccelerated); @@ -262,208 +251,32 @@ void ImageBuffer::clip(GraphicsContext* contextToClip, const FloatRect& rect) co CGContextTranslateCTM(platformContextToClip, -rect.x(), -rect.y() - rect.height()); } -template <Multiply multiplied> -PassRefPtr<ByteArray> getImageData(const IntRect& rect, const ImageBufferData& imageData, const IntSize& size, bool accelerateRendering) -{ - RefPtr<ByteArray> result = ByteArray::create(rect.width() * rect.height() * 4); - unsigned char* data = result->data(); - - if (rect.x() < 0 || rect.y() < 0 || rect.maxX() > size.width() || rect.maxY() > size.height()) - memset(data, 0, result->length()); - - int originx = rect.x(); - int destx = 0; - if (originx < 0) { - destx = -originx; - originx = 0; - } - int endx = rect.maxX(); - if (endx > size.width()) - endx = size.width(); - int numColumns = endx - originx; - - int originy = rect.y(); - int desty = 0; - if (originy < 0) { - desty = -originy; - originy = 0; - } - int endy = rect.maxY(); - if (endy > size.height()) - endy = size.height(); - int numRows = endy - originy; - - unsigned destBytesPerRow = 4 * rect.width(); - unsigned char* destRows = data + desty * destBytesPerRow + destx * 4; - - unsigned srcBytesPerRow; - unsigned char* srcRows; - - if (!accelerateRendering) { - srcBytesPerRow = 4 * size.width(); - srcRows = reinterpret_cast<unsigned char*>(imageData.m_data) + originy * srcBytesPerRow + originx * 4; - - for (int y = 0; y < numRows; ++y) { - for (int x = 0; x < numColumns; x++) { - int basex = x * 4; - unsigned char alpha = srcRows[basex + 3]; - if (multiplied == Unmultiplied && alpha) { - destRows[basex] = (srcRows[basex] * 255) / alpha; - destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha; - destRows[basex + 2] = (srcRows[basex + 2] * 255) / alpha; - destRows[basex + 3] = alpha; - } else - reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0]; - } - srcRows += srcBytesPerRow; - destRows += destBytesPerRow; - } - } else { -#if USE(IOSURFACE_CANVAS_BACKING_STORE) - IOSurfaceRef surface = imageData.m_surface.get(); - IOSurfaceLock(surface, kIOSurfaceLockReadOnly, 0); - srcBytesPerRow = IOSurfaceGetBytesPerRow(surface); - srcRows = (unsigned char*)(IOSurfaceGetBaseAddress(surface)) + originy * srcBytesPerRow + originx * 4; - - for (int y = 0; y < numRows; ++y) { - for (int x = 0; x < numColumns; x++) { - int basex = x * 4; - unsigned char alpha = srcRows[basex + 3]; - if (multiplied == Unmultiplied && alpha) { - destRows[basex] = (srcRows[basex + 2] * 255) / alpha; - destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha; - destRows[basex + 2] = (srcRows[basex] * 255) / alpha; - destRows[basex + 3] = alpha; - } else { - destRows[basex] = srcRows[basex + 2]; - destRows[basex + 1] = srcRows[basex + 1]; - destRows[basex + 2] = srcRows[basex]; - destRows[basex + 3] = alpha; - } - } - srcRows += srcBytesPerRow; - destRows += destBytesPerRow; - } - IOSurfaceUnlock(surface, kIOSurfaceLockReadOnly, 0); -#else - ASSERT_NOT_REACHED(); -#endif - } - - return result.release(); -} - PassRefPtr<ByteArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const { if (m_accelerateRendering) CGContextFlush(context()->platformContext()); - return getImageData<Unmultiplied>(rect, m_data, m_size, m_accelerateRendering); + return m_data.getData(rect, m_size, m_accelerateRendering, true); } PassRefPtr<ByteArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const { if (m_accelerateRendering) CGContextFlush(context()->platformContext()); - return getImageData<Premultiplied>(rect, m_data, m_size, m_accelerateRendering); -} - -template <Multiply multiplied> -void putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, ImageBufferData& imageData, const IntSize& size, bool accelerateRendering) -{ - ASSERT(sourceRect.width() > 0); - ASSERT(sourceRect.height() > 0); - - int originx = sourceRect.x(); - int destx = destPoint.x() + sourceRect.x(); - ASSERT(destx >= 0); - ASSERT(destx < size.width()); - ASSERT(originx >= 0); - ASSERT(originx <= sourceRect.maxX()); - - int endx = destPoint.x() + sourceRect.maxX(); - ASSERT(endx <= size.width()); - - int numColumns = endx - destx; - - int originy = sourceRect.y(); - int desty = destPoint.y() + sourceRect.y(); - ASSERT(desty >= 0); - ASSERT(desty < size.height()); - ASSERT(originy >= 0); - ASSERT(originy <= sourceRect.maxY()); - - int endy = destPoint.y() + sourceRect.maxY(); - ASSERT(endy <= size.height()); - int numRows = endy - desty; - - unsigned srcBytesPerRow = 4 * sourceSize.width(); - unsigned char* srcRows = source->data() + originy * srcBytesPerRow + originx * 4; - unsigned destBytesPerRow; - unsigned char* destRows; - - if (!accelerateRendering) { - destBytesPerRow = 4 * size.width(); - destRows = reinterpret_cast<unsigned char*>(imageData.m_data) + desty * destBytesPerRow + destx * 4; - for (int y = 0; y < numRows; ++y) { - for (int x = 0; x < numColumns; x++) { - int basex = x * 4; - unsigned char alpha = srcRows[basex + 3]; - if (multiplied == Unmultiplied && alpha != 255) { - destRows[basex] = (srcRows[basex] * alpha + 254) / 255; - destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255; - destRows[basex + 2] = (srcRows[basex + 2] * alpha + 254) / 255; - destRows[basex + 3] = alpha; - } else - reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0]; - } - destRows += destBytesPerRow; - srcRows += srcBytesPerRow; - } - } else { -#if USE(IOSURFACE_CANVAS_BACKING_STORE) - IOSurfaceRef surface = imageData.m_surface.get(); - IOSurfaceLock(surface, 0, 0); - destBytesPerRow = IOSurfaceGetBytesPerRow(surface); - destRows = (unsigned char*)(IOSurfaceGetBaseAddress(surface)) + desty * destBytesPerRow + destx * 4; - - for (int y = 0; y < numRows; ++y) { - for (int x = 0; x < numColumns; x++) { - int basex = x * 4; - unsigned char alpha = srcRows[basex + 3]; - if (multiplied == Unmultiplied && alpha != 255) { - destRows[basex] = (srcRows[basex + 2] * alpha + 254) / 255; - destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255; - destRows[basex + 2] = (srcRows[basex] * alpha + 254) / 255; - destRows[basex + 3] = alpha; - } else { - destRows[basex] = srcRows[basex + 2]; - destRows[basex + 1] = srcRows[basex + 1]; - destRows[basex + 2] = srcRows[basex]; - destRows[basex + 3] = alpha; - } - } - destRows += destBytesPerRow; - srcRows += srcBytesPerRow; - } - IOSurfaceUnlock(surface, 0, 0); -#else - ASSERT_NOT_REACHED(); -#endif - } + return m_data.getData(rect, m_size, m_accelerateRendering, false); } void ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint) { if (m_accelerateRendering) CGContextFlush(context()->platformContext()); - putImageData<Unmultiplied>(source, sourceSize, sourceRect, destPoint, m_data, m_size, m_accelerateRendering); + m_data.putData(source, sourceSize, sourceRect, destPoint, m_size, m_accelerateRendering, true); } void ImageBuffer::putPremultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint) { if (m_accelerateRendering) CGContextFlush(context()->platformContext()); - putImageData<Premultiplied>(source, sourceSize, sourceRect, destPoint, m_data, m_size, m_accelerateRendering); + m_data.putData(source, sourceSize, sourceRect, destPoint, m_size, m_accelerateRendering, false); } static inline CFStringRef jpegUTI() diff --git a/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.cpp b/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.cpp new file mode 100644 index 0000000..f067b66 --- /dev/null +++ b/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.cpp @@ -0,0 +1,387 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ImageBufferData.h" + +#include <wtf/Assertions.h> + +#if USE(ACCELERATE) +#include <Accelerate/Accelerate.h> +#endif + +#if USE(IOSURFACE_CANVAS_BACKING_STORE) +#include <IOSurface/IOSurface.h> +#include <dispatch/dispatch.h> +#endif + +#if USE(ACCELERATE) +struct ScanlineData { + vImagePixelCount scanlineWidth; + unsigned char* srcData; + size_t srcRowBytes; + unsigned char* destData; + size_t destRowBytes; +}; +#endif + +namespace WebCore { + +ImageBufferData::ImageBufferData(const IntSize&) +: m_data(0) +#if USE(IOSURFACE_CANVAS_BACKING_STORE) +, m_surface(0) +#endif +{ +} + +#if USE(ACCELERATE) +// The vImage unpremultiply routine had a rounding bug before 10.6.7 <rdar://problem/8631548> +static bool haveVImageRoundingErrorFix() +{ + SInt32 version; + static bool result = (Gestalt(gestaltSystemVersion, &version) == noErr && version > 0x1066); + return result; +} + +#if USE(IOSURFACE_CANVAS_BACKING_STORE) +static void convertScanline(void* data, size_t tileNumber, bool premultiply) +{ + ScanlineData* scanlineData = static_cast<ScanlineData*>(data); + + vImage_Buffer src; + src.data = scanlineData->srcData + tileNumber * scanlineData->srcRowBytes; + src.height = 1; + src.width = scanlineData->scanlineWidth; + src.rowBytes = scanlineData->srcRowBytes; + + vImage_Buffer dest; + dest.data = scanlineData->destData + tileNumber * scanlineData->destRowBytes; + dest.height = 1; + dest.width = scanlineData->scanlineWidth; + dest.rowBytes = scanlineData->destRowBytes; + + if (premultiply) { + if (kvImageNoError != vImagePremultiplyData_RGBA8888(&src, &dest, kvImageDoNotTile)) + return; + } else { + if (kvImageNoError != vImageUnpremultiplyData_RGBA8888(&src, &dest, kvImageDoNotTile)) + return; + } + + // Swap channels 1 and 3, to convert BGRA<->RGBA. IOSurfaces is BGRA, ImageData expects RGBA. + const uint8_t map[4] = { 2, 1, 0, 3 }; + vImagePermuteChannels_ARGB8888(&dest, &dest, map, kvImageDoNotTile); +} + +static void unpremultitplyScanline(void* data, size_t tileNumber) +{ + convertScanline(data, tileNumber, false); +} + +static void premultitplyScanline(void* data, size_t tileNumber) +{ + convertScanline(data, tileNumber, true); +} +#endif // USE(IOSURFACE_CANVAS_BACKING_STORE) +#endif // USE(ACCELERATE) + +PassRefPtr<ByteArray> ImageBufferData::getData(const IntRect& rect, const IntSize& size, bool accelerateRendering, bool unmultiplied) const +{ + RefPtr<ByteArray> result = ByteArray::create(rect.width() * rect.height() * 4); + unsigned char* data = result->data(); + + if (rect.x() < 0 || rect.y() < 0 || rect.maxX() > size.width() || rect.maxY() > size.height()) + memset(data, 0, result->length()); + + int originx = rect.x(); + int destx = 0; + if (originx < 0) { + destx = -originx; + originx = 0; + } + int endx = rect.maxX(); + if (endx > size.width()) + endx = size.width(); + int width = endx - originx; + + int originy = rect.y(); + int desty = 0; + if (originy < 0) { + desty = -originy; + originy = 0; + } + int endy = rect.maxY(); + if (endy > size.height()) + endy = size.height(); + int height = endy - originy; + + if (width <= 0 || height <= 0) + return result.release(); + + unsigned destBytesPerRow = 4 * rect.width(); + unsigned char* destRows = data + desty * destBytesPerRow + destx * 4; + + unsigned srcBytesPerRow; + unsigned char* srcRows; + + if (!accelerateRendering) { + srcBytesPerRow = 4 * size.width(); + srcRows = reinterpret_cast<unsigned char*>(m_data) + originy * srcBytesPerRow + originx * 4; + +#if USE(ACCELERATE) + if (unmultiplied && haveVImageRoundingErrorFix()) { + vImage_Buffer src; + src.height = height; + src.width = width; + src.rowBytes = srcBytesPerRow; + src.data = srcRows; + + vImage_Buffer dst; + dst.height = height; + dst.width = width; + dst.rowBytes = destBytesPerRow; + dst.data = destRows; + + vImageUnpremultiplyData_RGBA8888(&src, &dst, kvImageNoFlags); + return result.release(); + } +#endif + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; x++) { + int basex = x * 4; + unsigned char alpha = srcRows[basex + 3]; + if (unmultiplied && alpha) { + destRows[basex] = (srcRows[basex] * 255) / alpha; + destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha; + destRows[basex + 2] = (srcRows[basex + 2] * 255) / alpha; + destRows[basex + 3] = alpha; + } else + reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0]; + } + srcRows += srcBytesPerRow; + destRows += destBytesPerRow; + } + } else { +#if USE(IOSURFACE_CANVAS_BACKING_STORE) + IOSurfaceRef surface = m_surface.get(); + IOSurfaceLock(surface, kIOSurfaceLockReadOnly, 0); + srcBytesPerRow = IOSurfaceGetBytesPerRow(surface); + srcRows = (unsigned char*)(IOSurfaceGetBaseAddress(surface)) + originy * srcBytesPerRow + originx * 4; + +#if USE(ACCELERATE) + if (unmultiplied) { + ScanlineData scanlineData; + scanlineData.scanlineWidth = width; + scanlineData.srcData = srcRows; + scanlineData.srcRowBytes = srcBytesPerRow; + scanlineData.destData = destRows; + scanlineData.destRowBytes = destBytesPerRow; + + dispatch_apply_f(height, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), &scanlineData, unpremultitplyScanline); + } else { + vImage_Buffer src; + src.height = height; + src.width = width; + src.rowBytes = srcBytesPerRow; + src.data = srcRows; + + vImage_Buffer dest; + dest.height = height; + dest.width = width; + dest.rowBytes = destBytesPerRow; + dest.data = destRows; + + // Swap pixel channels from BGRA to RGBA. + const uint8_t map[4] = { 2, 1, 0, 3 }; + vImagePermuteChannels_ARGB8888(&src, &dest, map, kvImageNoFlags); + } +#else + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; x++) { + int basex = x * 4; + unsigned char alpha = srcRows[basex + 3]; + if (unmultiplied && alpha) { + destRows[basex] = (srcRows[basex + 2] * 255) / alpha; + destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha; + destRows[basex + 2] = (srcRows[basex] * 255) / alpha; + destRows[basex + 3] = alpha; + } else { + destRows[basex] = srcRows[basex + 2]; + destRows[basex + 1] = srcRows[basex + 1]; + destRows[basex + 2] = srcRows[basex]; + destRows[basex + 3] = alpha; + } + } + srcRows += srcBytesPerRow; + destRows += destBytesPerRow; + } +#endif // USE(ACCELERATE) + IOSurfaceUnlock(surface, kIOSurfaceLockReadOnly, 0); +#else + ASSERT_NOT_REACHED(); +#endif // USE(IOSURFACE_CANVAS_BACKING_STORE) + } + + return result.release(); +} + +void ImageBufferData::putData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, const IntSize& size, bool accelerateRendering, bool unmultiplied) +{ + ASSERT(sourceRect.width() > 0); + ASSERT(sourceRect.height() > 0); + + int originx = sourceRect.x(); + int destx = destPoint.x() + sourceRect.x(); + ASSERT(destx >= 0); + ASSERT(destx < size.width()); + ASSERT(originx >= 0); + ASSERT(originx <= sourceRect.maxX()); + + int endx = destPoint.x() + sourceRect.maxX(); + ASSERT(endx <= size.width()); + + int width = endx - destx; + + int originy = sourceRect.y(); + int desty = destPoint.y() + sourceRect.y(); + ASSERT(desty >= 0); + ASSERT(desty < size.height()); + ASSERT(originy >= 0); + ASSERT(originy <= sourceRect.maxY()); + + int endy = destPoint.y() + sourceRect.maxY(); + ASSERT(endy <= size.height()); + int height = endy - desty; + + if (width <= 0 || height <= 0) + return; + + unsigned srcBytesPerRow = 4 * sourceSize.width(); + unsigned char* srcRows = source->data() + originy * srcBytesPerRow + originx * 4; + unsigned destBytesPerRow; + unsigned char* destRows; + + if (!accelerateRendering) { + destBytesPerRow = 4 * size.width(); + destRows = reinterpret_cast<unsigned char*>(m_data) + desty * destBytesPerRow + destx * 4; + +#if USE(ACCELERATE) + if (haveVImageRoundingErrorFix() && unmultiplied) { + vImage_Buffer src; + src.height = height; + src.width = width; + src.rowBytes = srcBytesPerRow; + src.data = srcRows; + + vImage_Buffer dst; + dst.height = height; + dst.width = width; + dst.rowBytes = destBytesPerRow; + dst.data = destRows; + + vImagePremultiplyData_RGBA8888(&src, &dst, kvImageNoFlags); + return; + } +#endif + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; x++) { + int basex = x * 4; + unsigned char alpha = srcRows[basex + 3]; + if (unmultiplied && alpha != 255) { + destRows[basex] = (srcRows[basex] * alpha + 254) / 255; + destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255; + destRows[basex + 2] = (srcRows[basex + 2] * alpha + 254) / 255; + destRows[basex + 3] = alpha; + } else + reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0]; + } + destRows += destBytesPerRow; + srcRows += srcBytesPerRow; + } + } else { +#if USE(IOSURFACE_CANVAS_BACKING_STORE) + IOSurfaceRef surface = m_surface.get(); + IOSurfaceLock(surface, 0, 0); + destBytesPerRow = IOSurfaceGetBytesPerRow(surface); + destRows = (unsigned char*)(IOSurfaceGetBaseAddress(surface)) + desty * destBytesPerRow + destx * 4; + +#if USE(ACCELERATE) + if (unmultiplied) { + ScanlineData scanlineData; + scanlineData.scanlineWidth = width; + scanlineData.srcData = srcRows; + scanlineData.srcRowBytes = srcBytesPerRow; + scanlineData.destData = destRows; + scanlineData.destRowBytes = destBytesPerRow; + + dispatch_apply_f(height, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), &scanlineData, premultitplyScanline); + } else { + vImage_Buffer src; + src.height = height; + src.width = width; + src.rowBytes = srcBytesPerRow; + src.data = srcRows; + + vImage_Buffer dest; + dest.height = height; + dest.width = width; + dest.rowBytes = destBytesPerRow; + dest.data = destRows; + + // Swap pixel channels from RGBA to BGRA. + const uint8_t map[4] = { 2, 1, 0, 3 }; + vImagePermuteChannels_ARGB8888(&src, &dest, map, kvImageNoFlags); + } +#else + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; x++) { + int basex = x * 4; + unsigned char alpha = srcRows[basex + 3]; + if (unmultiplied && alpha != 255) { + destRows[basex] = (srcRows[basex + 2] * alpha + 254) / 255; + destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255; + destRows[basex + 2] = (srcRows[basex] * alpha + 254) / 255; + destRows[basex + 3] = alpha; + } else { + destRows[basex] = srcRows[basex + 2]; + destRows[basex + 1] = srcRows[basex + 1]; + destRows[basex + 2] = srcRows[basex]; + destRows[basex + 3] = alpha; + } + } + destRows += destBytesPerRow; + srcRows += srcBytesPerRow; + } +#endif // USE(ACCELERATE) + + IOSurfaceUnlock(surface, 0, 0); +#else + ASSERT_NOT_REACHED(); +#endif // USE(IOSURFACE_CANVAS_BACKING_STORE) + } +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/cg/ImageBufferData.h b/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.h index 1f706ec..54169e6 100644 --- a/Source/WebCore/platform/graphics/cg/ImageBufferData.h +++ b/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2011 Apple Inc. All rights reserved. * Copyright (C) 2008 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,13 +24,15 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ImageBufferData_h -#define ImageBufferData_h - #include "Image.h" +#include <wtf/ByteArray.h> #include <wtf/RefPtr.h> #include <wtf/RetainPtr.h> +#if (PLATFORM(MAC) && USE(CA) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)) +#define WTF_USE_IOSURFACE_CANVAS_BACKING_STORE 1 +#endif + typedef struct __IOSurface *IOSurfaceRef; typedef struct CGColorSpace *CGColorSpaceRef; typedef struct CGDataProvider *CGDataProviderRef; @@ -50,8 +53,9 @@ public: unsigned m_bytesPerRow; CGColorSpaceRef m_colorSpace; RetainPtr<IOSurfaceRef> m_surface; -}; -} // namespace WebCore + PassRefPtr<ByteArray> getData(const IntRect& rect, const IntSize& size, bool accelerateRendering, bool unmultiplied) const; + void putData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, const IntSize& size, bool accelerateRendering, bool unmultiplied); +}; -#endif // ImageBufferData_h +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/cg/ImageCG.cpp b/Source/WebCore/platform/graphics/cg/ImageCG.cpp index 08f65bd..635a804 100644 --- a/Source/WebCore/platform/graphics/cg/ImageCG.cpp +++ b/Source/WebCore/platform/graphics/cg/ImageCG.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "BitmapImage.h" -#if PLATFORM(CG) +#if USE(CG) #include "AffineTransform.h" #include "FloatConversion.h" @@ -154,6 +154,19 @@ CGImageRef BitmapImage::getCGImageRef() return frameAtIndex(0); } +CGImageRef BitmapImage::getFirstCGImageRefOfSize(const IntSize& size) +{ + size_t count = frameCount(); + for (size_t i = 0; i < count; ++i) { + CGImageRef cgImage = frameAtIndex(i); + if (IntSize(CGImageGetWidth(cgImage), CGImageGetHeight(cgImage)) == size) + return cgImage; + } + + // Fallback to the default CGImageRef if we can't find the right size + return getCGImageRef(); +} + void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp) { startAnimation(); @@ -186,7 +199,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const F // containing only the portion we want to display. We need to do this because high-quality // interpolation smoothes sharp edges, causing pixels from outside the source rect to bleed // into the destination rect. See <rdar://problem/6112909>. - shouldUseSubimage = (interpolationQuality == kCGInterpolationHigh || interpolationQuality == kCGInterpolationDefault) && (srcRect.size() != destRect.size() || !ctxt->getCTM().isIdentityOrTranslationOrFlipped()); + shouldUseSubimage = (interpolationQuality != kCGInterpolationNone) && (srcRect.size() != destRect.size() || !ctxt->getCTM().isIdentityOrTranslationOrFlipped()); float xScale = srcRect.width() / destRect.width(); float yScale = srcRect.height() / destRect.height(); if (shouldUseSubimage) { @@ -255,6 +268,11 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const // Avoid a hang under CGContextDrawTiledImage on release builds. return; +#if !ASSERT_DISABLED + if (this->isBitmapImage()) + ASSERT(static_cast<BitmapImage*>(this)->notSolidColor()); +#endif + CGContextRef context = ctxt->platformContext(); ctxt->save(); CGContextClipToRect(context, destRect); @@ -346,4 +364,4 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp index 068ea5b..1a630d4 100644 --- a/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp +++ b/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "ImageSource.h" -#if PLATFORM(CG) +#if USE(CG) #include "ImageSourceCG.h" #include "IntPoint.h" @@ -356,4 +356,4 @@ bool ImageSource::frameHasAlphaAtIndex(size_t) } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/cg/IntPointCG.cpp b/Source/WebCore/platform/graphics/cg/IntPointCG.cpp index 95dbe5f..4a1096b 100644 --- a/Source/WebCore/platform/graphics/cg/IntPointCG.cpp +++ b/Source/WebCore/platform/graphics/cg/IntPointCG.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "IntPoint.h" -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) #include <ApplicationServices/ApplicationServices.h> @@ -43,4 +43,4 @@ IntPoint::operator CGPoint() const } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/cg/IntRectCG.cpp b/Source/WebCore/platform/graphics/cg/IntRectCG.cpp index 73fd63f..18edeb0 100644 --- a/Source/WebCore/platform/graphics/cg/IntRectCG.cpp +++ b/Source/WebCore/platform/graphics/cg/IntRectCG.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "IntRect.h" -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) #include <ApplicationServices/ApplicationServices.h> @@ -48,4 +48,4 @@ IntRect enclosingIntRect(const CGRect& rect) } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/cg/IntSizeCG.cpp b/Source/WebCore/platform/graphics/cg/IntSizeCG.cpp index d8e8c83..c844cbc 100644 --- a/Source/WebCore/platform/graphics/cg/IntSizeCG.cpp +++ b/Source/WebCore/platform/graphics/cg/IntSizeCG.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "IntSize.h" -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) #include <ApplicationServices/ApplicationServices.h> @@ -43,4 +43,4 @@ IntSize::operator CGSize() const } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp b/Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp index 8bf04f1..a7d465f 100644 --- a/Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp +++ b/Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp @@ -27,7 +27,7 @@ #include "config.h" #include "PDFDocumentImage.h" -#if PLATFORM(CG) +#if USE(CG) #include "GraphicsContext.h" #include "ImageObserver.h" @@ -188,4 +188,4 @@ void PDFDocumentImage::draw(GraphicsContext* context, const FloatRect& dstRect, } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/cg/PDFDocumentImage.h b/Source/WebCore/platform/graphics/cg/PDFDocumentImage.h index ecd57be..c69a222 100644 --- a/Source/WebCore/platform/graphics/cg/PDFDocumentImage.h +++ b/Source/WebCore/platform/graphics/cg/PDFDocumentImage.h @@ -31,7 +31,7 @@ #include "FloatRect.h" #include "GraphicsTypes.h" -#if PLATFORM(CG) +#if USE(CG) #include <ApplicationServices/ApplicationServices.h> @@ -78,6 +78,6 @@ namespace WebCore { } -#endif // PLATFORM(CG) +#endif // USE(CG) #endif // PDFDocumentImage_h diff --git a/Source/WebCore/platform/graphics/cg/PathCG.cpp b/Source/WebCore/platform/graphics/cg/PathCG.cpp index b8fc7d4..3b9725a 100644 --- a/Source/WebCore/platform/graphics/cg/PathCG.cpp +++ b/Source/WebCore/platform/graphics/cg/PathCG.cpp @@ -27,7 +27,7 @@ #include "config.h" #include "Path.h" -#if PLATFORM(CG) +#if USE(CG) #include "AffineTransform.h" #include "FloatRect.h" @@ -309,4 +309,4 @@ void Path::transform(const AffineTransform& transform) } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp b/Source/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp index ec40836..b49a2ab 100644 --- a/Source/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp +++ b/Source/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp @@ -27,7 +27,7 @@ #include "AffineTransform.h" #include "TransformationMatrix.h" -#if PLATFORM(CG) +#if USE(CG) #include <CoreGraphics/CGAffineTransform.h> #include "FloatConversion.h" @@ -66,4 +66,4 @@ AffineTransform::operator CGAffineTransform() const } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp index 4cb119a..26ad37a 100644 --- a/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp @@ -36,6 +36,7 @@ #include "DrawingBuffer.h" #include "GraphicsContext3D.h" +#include "LayerRendererChromium.h" namespace WebCore { @@ -54,6 +55,8 @@ Canvas2DLayerChromium::~Canvas2DLayerChromium() { if (m_textureId) layerRendererContext()->deleteTexture(m_textureId); + if (m_drawingBuffer && layerRenderer()) + layerRenderer()->removeChildContext(m_drawingBuffer->graphicsContext3D().get()); } void Canvas2DLayerChromium::updateCompositorResources() @@ -103,8 +106,28 @@ unsigned Canvas2DLayerChromium::textureId() const void Canvas2DLayerChromium::setDrawingBuffer(DrawingBuffer* drawingBuffer) { if (drawingBuffer != m_drawingBuffer) { + if (m_drawingBuffer && layerRenderer()) + layerRenderer()->removeChildContext(m_drawingBuffer->graphicsContext3D().get()); + m_drawingBuffer = drawingBuffer; m_textureChanged = true; + + if (drawingBuffer && layerRenderer()) + layerRenderer()->addChildContext(m_drawingBuffer->graphicsContext3D().get()); + } +} + +void Canvas2DLayerChromium::setLayerRenderer(LayerRendererChromium* newLayerRenderer) +{ + if (layerRenderer() != newLayerRenderer) { + if (m_drawingBuffer->graphicsContext3D()) { + if (layerRenderer()) + layerRenderer()->removeChildContext(m_drawingBuffer->graphicsContext3D().get()); + if (newLayerRenderer) + newLayerRenderer->addChildContext(m_drawingBuffer->graphicsContext3D().get()); + } + + LayerChromium::setLayerRenderer(newLayerRenderer); } } diff --git a/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h b/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h index 81b118c..4224ab1 100644 --- a/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h @@ -52,6 +52,8 @@ public: unsigned textureId() const; void setDrawingBuffer(DrawingBuffer*); + virtual void setLayerRenderer(LayerRendererChromium*); + private: explicit Canvas2DLayerChromium(DrawingBuffer*, GraphicsLayerChromium* owner); DrawingBuffer* m_drawingBuffer; diff --git a/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp index 4ea9c92..aff2981 100644 --- a/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp @@ -41,6 +41,14 @@ #include "RenderLayerBacking.h" #include "TextStream.h" +// Maximum size the width or height of this layer can be before enabling tiling +// when m_tilingOption == AutoTile. +static int maxUntiledSize = 512; +// When tiling is enabled, use tiles of this dimension squared. +static int defaultTileSize = 256; + +using namespace std; + namespace WebCore { PassRefPtr<ContentLayerChromium> ContentLayerChromium::create(GraphicsLayerChromium* owner) @@ -50,240 +58,171 @@ PassRefPtr<ContentLayerChromium> ContentLayerChromium::create(GraphicsLayerChrom ContentLayerChromium::ContentLayerChromium(GraphicsLayerChromium* owner) : LayerChromium(owner) - , m_contentsTexture(0) - , m_skipsDraw(false) + , m_tilingOption(ContentLayerChromium::AutoTile) { } ContentLayerChromium::~ContentLayerChromium() { - cleanupResources(); -} - -void ContentLayerChromium::cleanupResources() -{ + m_tiler.clear(); LayerChromium::cleanupResources(); - m_contentsTexture.clear(); } -bool ContentLayerChromium::requiresClippedUpdateRect() -{ - // To avoid allocating excessively large textures, switch into "large layer mode" if - // one of the layer's dimensions is larger than 2000 pixels or the size of - // surface it's rendering into. This is a temporary measure until layer tiling is implemented. - static const int maxLayerSize = 2000; - return (bounds().width() > max(maxLayerSize, ccLayerImpl()->targetRenderSurface()->contentRect().width()) - || bounds().height() > max(maxLayerSize, ccLayerImpl()->targetRenderSurface()->contentRect().height()) - || !layerRenderer()->checkTextureSize(bounds())); -} +class ContentLayerPainter : public TilePaintInterface { +public: + explicit ContentLayerPainter(GraphicsLayerChromium* owner) + : m_owner(owner) + { + } -void ContentLayerChromium::paintContentsIfDirty() -{ - RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_owner->client()); - if (!backing || backing->paintingGoesToWindow()) - return; + virtual void paint(GraphicsContext& context, const IntRect& contentRect) + { + context.save(); + context.clearRect(contentRect); + context.clip(contentRect); + m_owner->paintGraphicsLayerContents(context, contentRect); + context.restore(); + } +private: + GraphicsLayerChromium* m_owner; +}; +void ContentLayerChromium::paintContentsIfDirty(const IntRect& targetSurfaceRect) +{ ASSERT(drawsContent()); - ASSERT(layerRenderer()); - IntRect dirtyRect; - IntRect boundsRect(IntPoint(0, 0), bounds()); - IntPoint paintingOffset; - - // FIXME: Remove this test when tiled layers are implemented. - if (requiresClippedUpdateRect()) { - // Calculate the region of this layer that is currently visible. - const IntRect clipRect = ccLayerImpl()->targetRenderSurface()->contentRect(); - - TransformationMatrix layerOriginTransform = ccLayerImpl()->drawTransform(); - layerOriginTransform.translate3d(-0.5 * bounds().width(), -0.5 * bounds().height(), 0); - - // We compute the visible portion of the layer by back-mapping the current RenderSurface - // content area to the layer. To do that, we invert the drawing matrix of the layer - // and project the content area rectangle to it. If the layer transform is not invertible - // then we skip rendering the layer. - if (!layerOriginTransform.isInvertible()) { - m_skipsDraw = true; - return; - } - TransformationMatrix targetToLayerMatrix = layerOriginTransform.inverse(); - FloatQuad mappedClipToLayer = targetToLayerMatrix.projectQuad(FloatRect(clipRect)); - IntRect visibleRectInLayerCoords = mappedClipToLayer.enclosingBoundingBox(); - visibleRectInLayerCoords.intersect(IntRect(0, 0, bounds().width(), bounds().height())); - - // If this is still too large to render, then skip the layer completely. - if (!layerRenderer()->checkTextureSize(visibleRectInLayerCoords.size())) { - m_skipsDraw = true; - return; - } - - // If we need to resize the upload buffer we have to repaint everything. - if (m_canvas.size() != visibleRectInLayerCoords.size()) { - resizeUploadBuffer(visibleRectInLayerCoords.size()); - m_dirtyRect = boundsRect; - } - // If the visible portion of the layer is different from the last upload. - if (visibleRectInLayerCoords != m_visibleRectInLayerCoords) - m_dirtyRect = boundsRect; - m_visibleRectInLayerCoords = visibleRectInLayerCoords; - - // Calculate the portion of the dirty rectangle that is visible. m_dirtyRect is in layer space. - IntRect visibleDirtyRectInLayerSpace = enclosingIntRect(m_dirtyRect); - visibleDirtyRectInLayerSpace.intersect(visibleRectInLayerCoords); - - // What the rectangles mean: - // dirtyRect: The region of this layer that will be updated. - // m_uploadUpdateRect: The region of the layer's texture that will be uploaded into. - dirtyRect = visibleDirtyRectInLayerSpace; - m_uploadUpdateRect = dirtyRect; - IntSize visibleRectOffsetInLayerCoords(visibleRectInLayerCoords.x(), visibleRectInLayerCoords.y()); - paintingOffset = IntPoint(visibleRectOffsetInLayerCoords); - m_uploadUpdateRect.move(-visibleRectOffsetInLayerCoords); - } else { - dirtyRect = IntRect(m_dirtyRect); - // If the texture needs to be reallocated then we must redraw the entire - // contents of the layer. - if (m_canvas.size() != bounds()) { - resizeUploadBuffer(bounds()); - dirtyRect = boundsRect; - } else { - // Clip the dirtyRect to the size of the layer to avoid drawing - // outside the bounds of the backing texture. - dirtyRect.intersect(boundsRect); - } - m_uploadUpdateRect = dirtyRect; - } + createTilerIfNeeded(); - if (dirtyRect.isEmpty()) - return; + ContentLayerPainter painter(m_owner); + updateLayerSize(layerBounds().size()); - PlatformCanvas::Painter painter(&m_canvas); - painter.context()->save(); - painter.context()->translate(-paintingOffset.x(), -paintingOffset.y()); - painter.context()->clearRect(dirtyRect); - painter.context()->clip(dirtyRect); + IntRect layerRect = visibleLayerRect(targetSurfaceRect); + if (layerRect.isEmpty()) + return; + m_tiler->invalidateRect(enclosingIntRect(m_dirtyRect)); + m_tiler->update(painter, layerRect); + m_dirtyRect = FloatRect(); +} - m_owner->paintGraphicsLayerContents(*painter.context(), dirtyRect); - painter.context()->restore(); +void ContentLayerChromium::setLayerRenderer(LayerRendererChromium* layerRenderer) +{ + LayerChromium::setLayerRenderer(layerRenderer); + createTilerIfNeeded(); + m_tiler->setLayerRenderer(layerRenderer); } -void ContentLayerChromium::resizeUploadBuffer(const IntSize& size) +TransformationMatrix ContentLayerChromium::tilingTransform() { - m_canvas.resize(size); + TransformationMatrix transform = ccLayerImpl()->drawTransform(); + // Tiler draws from the upper left corner. The draw transform + // specifies the middle of the layer. + IntSize size = bounds(); + transform.translate(-size.width() / 2.0, -size.height() / 2.0); + + return transform; } -void ContentLayerChromium::updateTextureIfNeeded() +IntRect ContentLayerChromium::visibleLayerRect(const IntRect& targetSurfaceRect) +{ + if (targetSurfaceRect.isEmpty()) + return targetSurfaceRect; + + const IntRect layerBoundRect = layerBounds(); + const TransformationMatrix transform = tilingTransform(); + + // Is this layer fully contained within the target surface? + IntRect layerInSurfaceSpace = transform.mapRect(layerBoundRect); + if (targetSurfaceRect.contains(layerInSurfaceSpace)) + return layerBoundRect; + + // If the layer doesn't fill up the entire surface, then find the part of + // the surface rect where the layer could be visible. This avoids trying to + // project surface rect points that are behind the projection point. + IntRect minimalSurfaceRect = targetSurfaceRect; + minimalSurfaceRect.intersect(layerInSurfaceSpace); + + // Project the corners of the target surface rect into the layer space. + // This bounding rectangle may be larger than it needs to be (being + // axis-aligned), but is a reasonable filter on the space to consider. + // Non-invertible transforms will create an empty rect here. + const TransformationMatrix surfaceToLayer = transform.inverse(); + IntRect layerRect = surfaceToLayer.projectQuad(FloatQuad(FloatRect(minimalSurfaceRect))).enclosingBoundingBox(); + layerRect.intersect(layerBoundRect); + return layerRect; +} + +IntRect ContentLayerChromium::layerBounds() const { - PlatformCanvas::AutoLocker locker(&m_canvas); - updateTexture(locker.pixels(), m_canvas.size()); + return IntRect(IntPoint(0, 0), bounds()); } -void ContentLayerChromium::updateTexture(const uint8_t* pixels, const IntSize& size) +void ContentLayerChromium::updateLayerSize(const IntSize& layerSize) { - if (!pixels) + if (!m_tiler) return; - GraphicsContext3D* context = layerRendererContext(); - if (!m_contentsTexture) - m_contentsTexture = LayerTexture::create(context, layerRenderer()->textureManager()); + const IntSize tileSize(min(defaultTileSize, layerSize.width()), min(defaultTileSize, layerSize.height())); + const bool autoTiled = layerSize.width() > maxUntiledSize || layerSize.height() > maxUntiledSize; - // If we have to allocate a new texture we have to upload the full contents. - if (!m_contentsTexture->isValid(size, GraphicsContext3D::RGBA)) - m_uploadUpdateRect = IntRect(IntPoint(0, 0), size); + bool isTiled; + if (m_tilingOption == AlwaysTile) + isTiled = true; + else if (m_tilingOption == NeverTile) + isTiled = false; + else + isTiled = autoTiled; - if (!m_contentsTexture->reserve(size, GraphicsContext3D::RGBA)) { - m_skipsDraw = true; - return; - } - - IntRect srcRect = IntRect(IntPoint(0, 0), size); - if (requiresClippedUpdateRect()) - srcRect = m_visibleRectInLayerCoords; - - const size_t destStride = m_uploadUpdateRect.width() * 4; - const size_t srcStride = srcRect.width() * 4; - - const uint8_t* uploadPixels = pixels + srcStride * m_uploadUpdateRect.y(); - Vector<uint8_t> uploadBuffer; - if (srcStride != destStride || m_uploadUpdateRect.x()) { - uploadBuffer.resize(m_uploadUpdateRect.height() * destStride); - for (int row = 0; row < m_uploadUpdateRect.height(); ++row) { - size_t srcOffset = (m_uploadUpdateRect.y() + row) * srcStride + m_uploadUpdateRect.x() * 4; - ASSERT(srcOffset + destStride <= static_cast<size_t>(size.width() * size.height() * 4)); - size_t destOffset = row * destStride; - ASSERT(destOffset + destStride <= uploadBuffer.size()); - memcpy(uploadBuffer.data() + destOffset, pixels + srcOffset, destStride); - } - uploadPixels = uploadBuffer.data(); - } - - m_contentsTexture->bindTexture(); - GLC(context, context->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, - m_uploadUpdateRect.x(), m_uploadUpdateRect.y(), m_uploadUpdateRect.width(), m_uploadUpdateRect.height(), - GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, - uploadPixels)); + m_tiler->setTileSize(isTiled ? tileSize : layerSize); +} - m_uploadUpdateRect = IntRect(); - m_dirtyRect.setSize(FloatSize()); - // Large layers always stay dirty, because they need to update when the content rect changes. - m_contentsDirty = requiresClippedUpdateRect(); +void ContentLayerChromium::draw(const IntRect& targetSurfaceRect) +{ + const TransformationMatrix transform = tilingTransform(); + IntRect layerRect = visibleLayerRect(targetSurfaceRect); + if (!layerRect.isEmpty()) + m_tiler->draw(layerRect, transform, ccLayerImpl()->drawOpacity()); + m_tiler->unreserveTextures(); } -void ContentLayerChromium::draw() +void ContentLayerChromium::createTilerIfNeeded() { - if (m_skipsDraw) + if (m_tiler) return; + m_tiler = LayerTilerChromium::create(layerRenderer(), IntSize(defaultTileSize, defaultTileSize), LayerTilerChromium::HasBorderTexels); +} - ASSERT(layerRenderer()); +void ContentLayerChromium::updateCompositorResources() +{ + m_tiler->uploadCanvas(); +} - const ContentLayerChromium::Program* program = layerRenderer()->contentLayerProgram(); - ASSERT(program && program->initialized()); - GraphicsContext3D* context = layerRendererContext(); - GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); - bindContentsTexture(); - layerRenderer()->useShader(program->program()); - GLC(context, context->uniform1i(program->fragmentShader().samplerLocation(), 0)); - GLC(context, context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA)); - - if (requiresClippedUpdateRect()) { - // Compute the offset between the layer's center point and the center of the visible portion - // of the layer. - FloatPoint visibleRectCenterOffset = FloatRect(m_visibleRectInLayerCoords).center(); - visibleRectCenterOffset.move(-0.5 * bounds().width(), -0.5 * bounds().height()); - - TransformationMatrix transform = ccLayerImpl()->drawTransform(); - transform.translate(visibleRectCenterOffset.x(), visibleRectCenterOffset.y()); - - drawTexturedQuad(context, layerRenderer()->projectionMatrix(), - transform, m_visibleRectInLayerCoords.width(), - m_visibleRectInLayerCoords.height(), ccLayerImpl()->drawOpacity(), - program->vertexShader().matrixLocation(), - program->fragmentShader().alphaLocation()); - } else { - drawTexturedQuad(context, layerRenderer()->projectionMatrix(), - ccLayerImpl()->drawTransform(), bounds().width(), bounds().height(), - ccLayerImpl()->drawOpacity(), program->vertexShader().matrixLocation(), - program->fragmentShader().alphaLocation()); - } - unreserveContentsTexture(); +void ContentLayerChromium::setTilingOption(TilingOption option) +{ + m_tilingOption = option; + updateLayerSize(bounds()); } -void ContentLayerChromium::updateCompositorResources() +void ContentLayerChromium::bindContentsTexture() { - updateTextureIfNeeded(); + // This function is only valid for single texture layers, e.g. masks. + ASSERT(m_tilingOption == NeverTile); + ASSERT(m_tiler); + + LayerTexture* texture = m_tiler->getSingleTexture(); + ASSERT(texture); + + texture->bindTexture(); } void ContentLayerChromium::unreserveContentsTexture() { - if (!m_skipsDraw && m_contentsTexture) - m_contentsTexture->unreserve(); + m_tiler->unreserveTextures(); } -void ContentLayerChromium::bindContentsTexture() +void ContentLayerChromium::setIsMask(bool isMask) { - if (!m_skipsDraw && m_contentsTexture) - m_contentsTexture->bindTexture(); + setTilingOption(isMask ? NeverTile : AutoTile); } static void writeIndent(TextStream& ts, int indent) @@ -296,7 +235,7 @@ void ContentLayerChromium::dumpLayerProperties(TextStream& ts, int indent) const { LayerChromium::dumpLayerProperties(ts, indent); writeIndent(ts, indent); - ts << "skipsDraw: " << m_skipsDraw << "\n"; + ts << "skipsDraw: " << m_tiler->skipsDraw() << "\n"; } } diff --git a/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h index cf296ab..c0cf582 100644 --- a/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h @@ -35,7 +35,7 @@ #if USE(ACCELERATED_COMPOSITING) #include "LayerChromium.h" -#include "PlatformCanvas.h" +#include "LayerTilerChromium.h" #include "TextureManager.h" namespace WebCore { @@ -46,43 +46,43 @@ class LayerTexture; class ContentLayerChromium : public LayerChromium { friend class LayerRendererChromium; public: + enum TilingOption { AlwaysTile, NeverTile, AutoTile }; + static PassRefPtr<ContentLayerChromium> create(GraphicsLayerChromium* owner = 0); virtual ~ContentLayerChromium(); - virtual void paintContentsIfDirty(); + virtual void paintContentsIfDirty(const IntRect& targetSurfaceRect); virtual void updateCompositorResources(); + virtual void setIsMask(bool); virtual void unreserveContentsTexture(); virtual void bindContentsTexture(); - virtual void draw(); - virtual bool drawsContent() const { return m_owner && m_owner->drawsContent(); } - - typedef ProgramBinding<VertexShaderPosTex, FragmentShaderTexAlpha> Program; + virtual void draw(const IntRect& targetSurfaceRect); + virtual bool drawsContent() const { return m_owner && m_owner->drawsContent() && (!m_tiler || !m_tiler->skipsDraw()); } protected: explicit ContentLayerChromium(GraphicsLayerChromium* owner); - virtual void cleanupResources(); - bool requiresClippedUpdateRect(); - void resizeUploadBuffer(const IntSize&); - virtual const char* layerTypeAsString() const { return "ContentLayer"; } virtual void dumpLayerProperties(TextStream&, int indent) const; - OwnPtr<LayerTexture> m_contentsTexture; - bool m_skipsDraw; + virtual void setLayerRenderer(LayerRendererChromium*); + + virtual IntRect layerBounds() const; - // The portion of the upload buffer that has a pending update, in the coordinates of the texture. - IntRect m_uploadUpdateRect; + virtual TransformationMatrix tilingTransform(); - virtual void updateTextureIfNeeded(); - void updateTexture(const uint8_t* pixels, const IntSize&); + // For a given render surface rect that this layer will be transformed and + // drawn into, return the layer space rect that is visible in that surface. + IntRect visibleLayerRect(const IntRect&); -private: - PlatformCanvas m_canvas; + void updateLayerSize(const IntSize&); + void createTilerIfNeeded(); + void setTilingOption(TilingOption); - IntRect m_visibleRectInLayerCoords; + OwnPtr<LayerTilerChromium> m_tiler; + TilingOption m_tilingOption; }; } diff --git a/Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp b/Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp index e559edb..bad0c6c 100644 --- a/Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp @@ -76,7 +76,7 @@ DrawingBuffer::DrawingBuffer(GraphicsContext3D* context, bool multisampleExtensionSupported, bool packedDepthStencilExtensionSupported) : m_context(context) - , m_size(size) + , m_size(-1, -1) , m_multisampleExtensionSupported(multisampleExtensionSupported) , m_packedDepthStencilExtensionSupported(packedDepthStencilExtensionSupported) , m_fbo(0) @@ -173,6 +173,29 @@ void DrawingBuffer::setGrContext(GrContext* context) // the SharedGraphicsContext3D object that is giving us the context. m_grContext = context; } + +void DrawingBuffer::getGrPlatformSurfaceDesc(GrPlatformSurfaceDesc* desc) +{ + desc->fSurfaceType = kTextureRenderTarget_GrPlatformSurfaceType; + + desc->fPlatformTexture = m_colorBuffer; + if (multisample()) { + desc->fRenderTargetFlags = kIsMultisampled_GrPlatformRenderTargetFlagBit | kGrCanResolve_GrPlatformRenderTargetFlagBit; + desc->fPlatformRenderTarget = m_multisampleFBO; + desc->fPlatformResolveDestination = m_fbo; + } else { + desc->fRenderTargetFlags = kNone_GrPlatformRenderTargetFlagBit; + desc->fPlatformRenderTarget = m_fbo; + desc->fPlatformResolveDestination = 0; + } + + desc->fWidth = m_size.width(); + desc->fHeight = m_size.height(); + desc->fConfig = kRGBA_8888_GrPixelConfig; + + desc->fStencilBits = (m_depthStencilBuffer || m_stencilBuffer) ? 8 : 0; +} + #endif } diff --git a/Source/WebCore/platform/graphics/chromium/Extensions3DChromium.h b/Source/WebCore/platform/graphics/chromium/Extensions3DChromium.h index 3b0fdbf..c542351 100644 --- a/Source/WebCore/platform/graphics/chromium/Extensions3DChromium.h +++ b/Source/WebCore/platform/graphics/chromium/Extensions3DChromium.h @@ -43,6 +43,7 @@ public: // Extensions3D methods. virtual bool supports(const String&); virtual void ensureEnabled(const String&); + virtual bool isEnabled(const String&); virtual int getGraphicsResetStatusARB(); virtual void blitFramebuffer(long srcX0, long srcY0, long srcX1, long srcY1, long dstX0, long dstY0, long dstX1, long dstY1, unsigned long mask, unsigned long filter); virtual void renderbufferStorageMultisample(unsigned long target, unsigned long samples, unsigned long internalformat, unsigned long width, unsigned long height); @@ -66,6 +67,12 @@ public: // GL_CHROMIUM_copy_texture_to_parent_texture void copyTextureToParentTextureCHROMIUM(unsigned texture, unsigned parentTexture); + // Latch support + void getParentToChildLatchCHROMIUM(GC3Duint* latchId); + void getChildToParentLatchCHROMIUM(GC3Duint* latchId); + void waitLatchCHROMIUM(GC3Duint latchId); + void setLatchCHROMIUM(GC3Duint latchId); + private: // Instances of this class are strictly owned by the GraphicsContext3D implementation and do not // need to be instantiated by any other code. diff --git a/Source/WebCore/platform/graphics/chromium/FontChromiumWin.cpp b/Source/WebCore/platform/graphics/chromium/FontChromiumWin.cpp index 3c254dc..ac1e1af 100644 --- a/Source/WebCore/platform/graphics/chromium/FontChromiumWin.cpp +++ b/Source/WebCore/platform/graphics/chromium/FontChromiumWin.cpp @@ -43,7 +43,7 @@ #include "TransparencyWin.h" #include "UniscribeHelperTextRun.h" -#include "skia/ext/platform_canvas_win.h" +#include "skia/ext/platform_canvas.h" #include "skia/ext/skia_utils_win.h" // FIXME: remove this dependency. #include <windows.h> @@ -165,7 +165,7 @@ void TransparencyAwareFontPainter::initializeForGDI() // Set up the DC, using the one from the transparency helper. if (m_transparency.platformContext()) { - m_hdc = m_transparency.platformContext()->canvas()->beginPlatformPaint(); + m_hdc = skia::BeginPlatformPaint(m_transparency.platformContext()->canvas()); SetTextColor(m_hdc, skia::SkColorToCOLORREF(color)); SetBkMode(m_hdc, TRANSPARENT); } @@ -179,7 +179,7 @@ TransparencyAwareFontPainter::~TransparencyAwareFontPainter() if (m_createdTransparencyLayer) m_graphicsContext->endTransparencyLayer(); m_graphicsContext->restore(); - m_platformContext->canvas()->endPlatformPaint(); + skia::EndPlatformPaint(m_platformContext->canvas()); } // Specialization for simple GlyphBuffer painting. @@ -374,21 +374,14 @@ bool Font::canExpandAroundIdeographsInComplexText() return false; } -void Font::drawGlyphs(GraphicsContext* graphicsContext, - const SimpleFontData* font, - const GlyphBuffer& glyphBuffer, - int from, - int numGlyphs, - const FloatPoint& point) const -{ +static void drawGlyphsWin(GraphicsContext* graphicsContext, + const SimpleFontData* font, + const GlyphBuffer& glyphBuffer, + int from, + int numGlyphs, + const FloatPoint& point) { graphicsContext->platformContext()->prepareForSoftwareDraw(); - SkColor color = graphicsContext->platformContext()->effectiveFillColor(); - unsigned char alpha = SkColorGetA(color); - // Skip 100% transparent text; no need to draw anything. - if (!alpha && graphicsContext->platformContext()->getStrokeStyle() == NoStroke) - return; - TransparencyAwareGlyphPainter painter(graphicsContext, font, glyphBuffer, from, numGlyphs, point); // We draw the glyphs in chunks to avoid having to do a heap allocation for @@ -449,6 +442,39 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, } } +void Font::drawGlyphs(GraphicsContext* graphicsContext, + const SimpleFontData* font, + const GlyphBuffer& glyphBuffer, + int from, + int numGlyphs, + const FloatPoint& point) const +{ + SkColor color = graphicsContext->platformContext()->effectiveFillColor(); + unsigned char alpha = SkColorGetA(color); + // Skip 100% transparent text; no need to draw anything. + if (!alpha && graphicsContext->platformContext()->getStrokeStyle() == NoStroke && !graphicsContext->hasShadow()) + return; + if (!alpha || windowsCanHandleDrawTextShadow(graphicsContext) || !windowsCanHandleTextDrawingWithoutShadow(graphicsContext)) { + drawGlyphsWin(graphicsContext, font, glyphBuffer, from, numGlyphs, point); + return; + } + // Draw in two passes: skia for the shadow, GDI for foreground text + // pass1: shadow (will use skia) + graphicsContext->save(); + graphicsContext->setFillColor(Color::transparent, graphicsContext->fillColorSpace()); + drawGlyphsWin(graphicsContext, font, glyphBuffer, from, numGlyphs, point); + graphicsContext->restore(); + // pass2: foreground text (will use GDI) + FloatSize shadowOffset; + float shadowBlur; + Color shadowColor; + ColorSpace shadowColorSpace; + graphicsContext->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace); + graphicsContext->setShadow(shadowOffset, shadowBlur, Color::transparent, shadowColorSpace); + drawGlyphsWin(graphicsContext, font, glyphBuffer, from, numGlyphs, point); + graphicsContext->setShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace); +} + FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& point, int h, @@ -516,7 +542,7 @@ void Font::drawComplexText(GraphicsContext* graphicsContext, // the baseline, so we have to subtract off the ascent. state.draw(graphicsContext, hdc, lroundf(point.x()), lroundf(point.y() - fontMetrics().ascent()), from, to); - context->canvas()->endPlatformPaint(); + skia::EndPlatformPaint(context->canvas()); } void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const diff --git a/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp b/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp index c3edfac..1fb5957 100644 --- a/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp +++ b/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp @@ -122,7 +122,7 @@ int FontPlatformData::emSizeInFontUnits() const if (m_emSizeInFontUnits) return m_emSizeInFontUnits; - SkAdvancedTypefaceMetrics* metrics = m_typeface->getAdvancedTypefaceMetrics(false); + SkAdvancedTypefaceMetrics* metrics = m_typeface->getAdvancedTypefaceMetrics(SkAdvancedTypefaceMetrics::kNo_PerGlyphInfo); m_emSizeInFontUnits = metrics->fEmSize; metrics->unref(); return m_emSizeInFontUnits; diff --git a/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp b/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp index bea0572..a4798dd 100644 --- a/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp +++ b/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp @@ -250,17 +250,31 @@ int getAscent(HFONT hfont) return gotMetrics ? tm.tmAscent : kUndefinedAscent; } +WORD getSpaceGlyph(HFONT hfont) +{ + HDC dc = GetDC(0); + HGDIOBJ oldFont = SelectObject(dc, hfont); + WCHAR space = L' '; + WORD spaceGlyph = 0; + GetGlyphIndices(dc, &space, 1, &spaceGlyph, 0); + SelectObject(dc, oldFont); + ReleaseDC(0, dc); + return spaceGlyph; +} + struct FontData { FontData() : hfont(0) , ascent(kUndefinedAscent) , scriptCache(0) + , spaceGlyph(0) { } HFONT hfont; int ascent; mutable SCRIPT_CACHE scriptCache; + WORD spaceGlyph; }; // Again, using hash_map does not earn us much here. page_cycler_test intl2 @@ -379,7 +393,8 @@ bool getDerivedFontData(const UChar* family, LOGFONT* logfont, int* ascent, HFONT* hfont, - SCRIPT_CACHE** scriptCache) + SCRIPT_CACHE** scriptCache, + WORD* spaceGlyph) { ASSERT(logfont); ASSERT(family); @@ -408,6 +423,7 @@ bool getDerivedFontData(const UChar* family, // cache it so that we won't have to call CreateFontIndirect once // more for HFONT next time. derived->ascent = getAscent(derived->hfont); + derived->spaceGlyph = getSpaceGlyph(derived->hfont); } else { derived = &iter->second; // Last time, GetAscent failed so that only HFONT was @@ -419,6 +435,7 @@ bool getDerivedFontData(const UChar* family, *hfont = derived->hfont; *ascent = derived->ascent; *scriptCache = &(derived->scriptCache); + *spaceGlyph = derived->spaceGlyph; return *ascent != kUndefinedAscent; } diff --git a/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.h b/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.h index b637ede..d9de002 100644 --- a/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.h +++ b/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.h @@ -78,7 +78,7 @@ const UChar* getFallbackFamily(const UChar* characters, int length, // intl2 page-cycler test is noticeably slower with one out param than // the current version although the subsequent 9 passes take about the // same time. -bool getDerivedFontData(const UChar* family, int style, LOGFONT*, int* ascent, HFONT*, SCRIPT_CACHE**); +bool getDerivedFontData(const UChar* family, int style, LOGFONT*, int* ascent, HFONT*, SCRIPT_CACHE**, WORD* spaceGlyph); enum { FontStyleNormal = 0, diff --git a/Source/WebCore/platform/graphics/chromium/GLES2Canvas.cpp b/Source/WebCore/platform/graphics/chromium/GLES2Canvas.cpp index cc5a060..87d54b0 100644 --- a/Source/WebCore/platform/graphics/chromium/GLES2Canvas.cpp +++ b/Source/WebCore/platform/graphics/chromium/GLES2Canvas.cpp @@ -38,6 +38,7 @@ #include "GraphicsContext3D.h" #include "internal_glu.h" #include "IntRect.h" +#include "LoopBlinnMathUtils.h" #include "LoopBlinnPathProcessor.h" #include "LoopBlinnSolidFillShader.h" #include "Path.h" @@ -60,7 +61,7 @@ namespace WebCore { const int pathTesselation = 30; typedef void (GLAPIENTRY *TESSCB)(); typedef WTF::Vector<float> FloatVector; -typedef WTF::Vector<double> DoubleVector; +typedef WTF::Vector<FloatPoint> FloatPointVector; struct PathAndTransform { PathAndTransform(const Path& p, const AffineTransform& t) @@ -186,7 +187,7 @@ class Cubic { FloatPoint d = -1.0f * p0 + 3.0f * p1s - 3.0f * p2s + p3s; return Cubic(p0, b, c, d); } - FloatPoint evaluate(float t) + inline FloatPoint evaluate(float t) { return m_a + t * (m_b + t * (m_c + t * m_d)); } @@ -198,6 +199,7 @@ GLES2Canvas::GLES2Canvas(SharedGraphicsContext3D* context, DrawingBuffer* drawin , m_context(context) , m_drawingBuffer(drawingBuffer) , m_state(0) + , m_pathIndexBuffer(0) , m_pathVertexBuffer(0) { m_flipMatrix.translate(-1.0f, 1.0f); @@ -209,6 +211,10 @@ GLES2Canvas::GLES2Canvas(SharedGraphicsContext3D* context, DrawingBuffer* drawin GLES2Canvas::~GLES2Canvas() { + if (m_pathIndexBuffer) + m_context->graphicsContext3D()->deleteBuffer(m_pathIndexBuffer); + if (m_pathVertexBuffer) + m_context->graphicsContext3D()->deleteBuffer(m_pathVertexBuffer); } void GLES2Canvas::bindFramebuffer() @@ -229,6 +235,13 @@ void GLES2Canvas::clearRect(const FloatRect& rect) } } +void GLES2Canvas::applyState() +{ + bindFramebuffer(); + m_context->applyCompositeOperator(m_state->m_compositeOp); + applyClipping(m_state->clippingEnabled()); +} + void GLES2Canvas::scissorClear(float x, float y, float width, float height) { int intX = static_cast<int>(x + 0.5f); @@ -250,10 +263,7 @@ void GLES2Canvas::fillPath(const Path& path) endShadowDraw(path.boundingRect()); } - bindFramebuffer(); - m_context->applyCompositeOperator(m_state->m_compositeOp); - applyClipping(m_state->clippingEnabled()); - + applyState(); fillPathInternal(path, m_state->applyAlpha(m_state->m_fillColor)); } @@ -265,10 +275,7 @@ void GLES2Canvas::fillRect(const FloatRect& rect, const Color& color, ColorSpace endShadowDraw(rect); } - bindFramebuffer(); - m_context->applyCompositeOperator(m_state->m_compositeOp); - applyClipping(m_state->clippingEnabled()); - + applyState(); fillRectInternal(rect, color); } @@ -546,38 +553,30 @@ Texture* GLES2Canvas::getTexture(NativeImagePtr ptr) #if USE(SKIA) // This is actually cross-platform code, but since its only caller is inside a // USE(SKIA), it will cause a warning-as-error on Chrome/Mac. -static void interpolateQuadratic(DoubleVector* vertices, const FloatPoint& p0, const FloatPoint& p1, const FloatPoint& p2) +static void interpolateQuadratic(FloatPointVector* vertices, const FloatPoint& p0, const FloatPoint& p1, const FloatPoint& p2) { float tIncrement = 1.0f / pathTesselation, t = tIncrement; Quadratic c = Quadratic::fromBezier(p0, p1, p2); - for (int i = 0; i < pathTesselation; ++i, t += tIncrement) { - FloatPoint p = c.evaluate(t); - vertices->append(p.x()); - vertices->append(p.y()); - vertices->append(1.0); - } + for (int i = 0; i < pathTesselation; ++i, t += tIncrement) + vertices->append(c.evaluate(t)); } -static void interpolateCubic(DoubleVector* vertices, const FloatPoint& p0, const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& p3) +static void interpolateCubic(FloatPointVector* vertices, const FloatPoint& p0, const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& p3) { float tIncrement = 1.0f / pathTesselation, t = tIncrement; Cubic c = Cubic::fromBezier(p0, p1, p2, p3); - for (int i = 0; i < pathTesselation; ++i, t += tIncrement) { - FloatPoint p = c.evaluate(t); - vertices->append(p.x()); - vertices->append(p.y()); - vertices->append(1.0); - } + for (int i = 0; i < pathTesselation; ++i, t += tIncrement) + vertices->append(c.evaluate(t)); } #endif struct PolygonData { - PolygonData(FloatVector* vertices, WTF::Vector<short>* indices) + PolygonData(FloatPointVector* vertices, WTF::Vector<short>* indices) : m_vertices(vertices) , m_indices(indices) { } - FloatVector* m_vertices; + FloatPointVector* m_vertices; WTF::Vector<short>* m_indices; }; @@ -603,22 +602,24 @@ static void combineData(GLdouble coords[3], void* vertexData[4], GLfloat weight[4], void **outData, void* data) { PolygonData* polygonData = static_cast<PolygonData*>(data); - int index = polygonData->m_vertices->size() / 3; - polygonData->m_vertices->append(static_cast<float>(coords[0])); - polygonData->m_vertices->append(static_cast<float>(coords[1])); - polygonData->m_vertices->append(1.0f); + int index = polygonData->m_vertices->size(); + polygonData->m_vertices->append(FloatPoint(static_cast<float>(coords[0]), static_cast<float>(coords[1]))); *outData = reinterpret_cast<void*>(index); } typedef void (*TESSCB)(); -void GLES2Canvas::createVertexBufferFromPath(const Path& path, int* count, unsigned* vertexBuffer, unsigned* indexBuffer) +void GLES2Canvas::tesselateAndFillPath(const Path& path, const Color& color) { - *vertexBuffer = m_context->graphicsContext3D()->createBuffer(); - checkGLError("createVertexBufferFromPath, createBuffer"); - *indexBuffer = m_context->graphicsContext3D()->createBuffer(); - checkGLError("createVertexBufferFromPath, createBuffer"); - DoubleVector inVertices; + if (!m_pathVertexBuffer) + m_pathVertexBuffer = m_context->graphicsContext3D()->createBuffer(); + if (!m_pathIndexBuffer) + m_pathIndexBuffer = m_context->graphicsContext3D()->createBuffer(); + + AffineTransform matrix(m_flipMatrix); + matrix *= m_state->m_ctm; + + FloatPointVector inVertices; WTF::Vector<size_t> contours; #if USE(SKIA) const SkPath* skPath = path.platformPath(); @@ -628,14 +629,10 @@ void GLES2Canvas::createVertexBufferFromPath(const Path& path, int* count, unsig while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { switch (verb) { case SkPath::kMove_Verb: - inVertices.append(pts[0].fX); - inVertices.append(pts[0].fY); - inVertices.append(1.0); + inVertices.append(pts[0]); break; case SkPath::kLine_Verb: - inVertices.append(pts[1].fX); - inVertices.append(pts[1].fY); - inVertices.append(1.0); + inVertices.append(pts[1]); break; case SkPath::kQuad_Verb: interpolateQuadratic(&inVertices, pts[0], pts[1], pts[2]); @@ -644,7 +641,7 @@ void GLES2Canvas::createVertexBufferFromPath(const Path& path, int* count, unsig interpolateCubic(&inVertices, pts[0], pts[1], pts[2], pts[3]); break; case SkPath::kClose_Verb: - contours.append(inVertices.size() / 3); + contours.append(inVertices.size()); break; case SkPath::kDone_Verb: break; @@ -654,6 +651,21 @@ void GLES2Canvas::createVertexBufferFromPath(const Path& path, int* count, unsig ASSERT(!"Path extraction not implemented on this platform."); #endif + if (contours.size() == 1 && LoopBlinnMathUtils::isConvex(inVertices.begin(), inVertices.size())) { + m_context->graphicsContext3D()->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_pathVertexBuffer); + m_context->graphicsContext3D()->bufferData(GraphicsContext3D::ARRAY_BUFFER, inVertices.size() * 2 * sizeof(float), inVertices.data(), GraphicsContext3D::STREAM_DRAW); + m_context->useFillSolidProgram(matrix, color); + m_context->graphicsContext3D()->drawArrays(GraphicsContext3D::TRIANGLE_FAN, 0, inVertices.size()); + return; + } + + OwnArrayPtr<double> inVerticesDouble = adoptArrayPtr(new double[inVertices.size() * 3]); + for (size_t i = 0; i < inVertices.size(); ++i) { + inVerticesDouble[i * 3 ] = inVertices[i].x(); + inVerticesDouble[i * 3 + 1] = inVertices[i].y(); + inVerticesDouble[i * 3 + 2] = 1.0; + } + GLUtesselator* tess = internal_gluNewTess(); internal_gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO); internal_gluTessCallback(tess, GLU_TESS_BEGIN_DATA, (TESSCB) &beginData); @@ -662,7 +674,7 @@ void GLES2Canvas::createVertexBufferFromPath(const Path& path, int* count, unsig internal_gluTessCallback(tess, GLU_TESS_EDGE_FLAG_DATA, (TESSCB) &edgeFlagData); internal_gluTessCallback(tess, GLU_TESS_COMBINE_DATA, (TESSCB) &combineData); WTF::Vector<short> indices; - FloatVector vertices; + FloatPointVector vertices; vertices.reserveInitialCapacity(inVertices.size()); PolygonData data(&vertices, &indices); internal_gluTessBeginPolygon(tess, &data); @@ -671,26 +683,27 @@ void GLES2Canvas::createVertexBufferFromPath(const Path& path, int* count, unsig for (contour = contours.begin(); contour != contours.end(); ++contour) { internal_gluTessBeginContour(tess); for (; i < *contour; ++i) { - vertices.append(inVertices[i * 3]); - vertices.append(inVertices[i * 3 + 1]); - vertices.append(1.0f); - internal_gluTessVertex(tess, &inVertices[i * 3], reinterpret_cast<void*>(i)); + double* inVertex = &inVerticesDouble[i * 3]; + vertices.append(FloatPoint(inVertex[0], inVertex[1])); + internal_gluTessVertex(tess, inVertex, reinterpret_cast<void*>(i)); } internal_gluTessEndContour(tess); } internal_gluTessEndPolygon(tess); internal_gluDeleteTess(tess); - m_context->graphicsContext3D()->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, *vertexBuffer); + m_context->graphicsContext3D()->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_pathVertexBuffer); checkGLError("createVertexBufferFromPath, bindBuffer ARRAY_BUFFER"); - m_context->graphicsContext3D()->bufferData(GraphicsContext3D::ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GraphicsContext3D::STREAM_DRAW); + m_context->graphicsContext3D()->bufferData(GraphicsContext3D::ARRAY_BUFFER, vertices.size() * 2 * sizeof(float), vertices.data(), GraphicsContext3D::STREAM_DRAW); checkGLError("createVertexBufferFromPath, bufferData ARRAY_BUFFER"); - m_context->graphicsContext3D()->bindBuffer(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, *indexBuffer); + m_context->graphicsContext3D()->bindBuffer(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, m_pathIndexBuffer); checkGLError("createVertexBufferFromPath, bindBuffer ELEMENT_ARRAY_BUFFER"); m_context->graphicsContext3D()->bufferData(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(short), indices.data(), GraphicsContext3D::STREAM_DRAW); checkGLError("createVertexBufferFromPath, bufferData ELEMENT_ARRAY_BUFFER"); - *count = indices.size(); + + m_context->useFillSolidProgram(matrix, color); + m_context->graphicsContext3D()->drawElements(GraphicsContext3D::TRIANGLES, indices.size(), GraphicsContext3D::UNSIGNED_SHORT, 0); } void GLES2Canvas::fillPathInternal(const Path& path, const Color& color) @@ -723,29 +736,7 @@ void GLES2Canvas::fillPathInternal(const Path& path, const Color& color) m_context->useLoopBlinnInteriorProgram(byteSizeOfVertices + byteSizeOfTexCoords, matrix, color); m_context->drawArrays(GraphicsContext3D::TRIANGLES, 0, m_pathCache.numberOfInteriorVertices()); } else { - int count; - unsigned vertexBuffer, indexBuffer; - createVertexBufferFromPath(path, &count, &vertexBuffer, &indexBuffer); - - AffineTransform matrix(m_flipMatrix); - matrix *= m_state->m_ctm; - - m_context->graphicsContext3D()->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, vertexBuffer); - checkGLError("bindBuffer"); - m_context->graphicsContext3D()->bindBuffer(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, indexBuffer); - checkGLError("bindBuffer"); - - m_context->useFillSolidProgram(matrix, color); - checkGLError("useFillSolidProgram"); - - m_context->graphicsContext3D()->drawElements(GraphicsContext3D::TRIANGLES, count, GraphicsContext3D::UNSIGNED_SHORT, 0); - checkGLError("drawArrays"); - - m_context->graphicsContext3D()->deleteBuffer(vertexBuffer); - checkGLError("deleteBuffer"); - - m_context->graphicsContext3D()->deleteBuffer(indexBuffer); - checkGLError("deleteBuffer"); + tesselateAndFillPath(path, color); } } @@ -787,9 +778,7 @@ void GLES2Canvas::beginShadowDraw() m_context->clearColor(Color(RGBA32(0))); m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT); } else { - bindFramebuffer(); - m_context->applyCompositeOperator(m_state->m_compositeOp); - applyClipping(m_state->clippingEnabled()); + applyState(); } } @@ -864,19 +853,14 @@ void GLES2Canvas::endShadowDraw(const FloatRect& boundingBox) std::swap(srcBuffer, dstBuffer); // Upsample srcBuffer -> main framebuffer using bicubic filtering. - bindFramebuffer(); - m_context->applyCompositeOperator(m_state->m_compositeOp); - applyClipping(m_state->clippingEnabled()); + applyState(); m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, srcBuffer->colorBuffer()); FloatRect dstRect = srcRect; dstRect.scale(scaleFactor); drawTexturedQuadMitchell(srcBuffer->size(), flipRect(srcRect), dstRect, AffineTransform(), 1.0); } else { // Blur in Y directly to framebuffer. - bindFramebuffer(); - m_context->applyCompositeOperator(m_state->m_compositeOp); - applyClipping(m_state->clippingEnabled()); - + applyState(); convolveRect(srcBuffer->colorBuffer(), srcBuffer->size(), flipRect(srcRect), srcRect, imageIncrementY, kernel.get(), kernelWidth); } } diff --git a/Source/WebCore/platform/graphics/chromium/GLES2Canvas.h b/Source/WebCore/platform/graphics/chromium/GLES2Canvas.h index f6a8bcf..635eb10 100644 --- a/Source/WebCore/platform/graphics/chromium/GLES2Canvas.h +++ b/Source/WebCore/platform/graphics/chromium/GLES2Canvas.h @@ -100,14 +100,14 @@ public: DrawingBuffer* drawingBuffer() const { return m_drawingBuffer; } private: + void applyState(); void scissorClear(float x, float y, float width, float height); void drawTexturedRectTile(Texture* texture, int tile, const FloatRect& srcRect, const FloatRect& dstRect, const AffineTransform&, float alpha); void drawTexturedQuad(const IntSize& textureSize, const FloatRect& srcRect, const FloatRect& dstRect, const AffineTransform&, float alpha); void drawTexturedQuadMitchell(const IntSize& textureSize, const FloatRect& srcRect, const FloatRect& dstRect, const AffineTransform&, float alpha); void convolveRect(unsigned texture, const IntSize& textureSize, const FloatRect& srcRect, const FloatRect& dstRect, float imageIncrement[2], const float* kernel, int kernelWidth); - void applyCompositeOperator(CompositeOperator); - void createVertexBufferFromPath(const Path&, int* count, unsigned* vertexBuffer, unsigned* indexBuffer); + void tesselateAndFillPath(const Path&, const Color&); void fillPathInternal(const Path&, const Color&); void fillRectInternal(const FloatRect&, const Color&); FloatRect flipRect(const FloatRect&); @@ -131,6 +131,7 @@ private: // Members for GPU-accelerated path rendering. LoopBlinnPathCache m_pathCache; + unsigned m_pathIndexBuffer; unsigned m_pathVertexBuffer; }; diff --git a/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp index 067c54d..2301ca3 100644 --- a/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp @@ -283,6 +283,8 @@ void GraphicsLayerChromium::setMaskLayer(GraphicsLayer* maskLayer) GraphicsLayer::setMaskLayer(maskLayer); LayerChromium* maskLayerChromium = m_maskLayer ? m_maskLayer->platformLayer() : 0; + if (maskLayerChromium) + maskLayerChromium->setIsMask(true); m_layer->setMaskLayer(maskLayerChromium); } diff --git a/Source/WebCore/platform/graphics/chromium/ImageBufferData.h b/Source/WebCore/platform/graphics/chromium/ImageBufferDataSkia.h index 504b893..75c91ed 100644 --- a/Source/WebCore/platform/graphics/chromium/ImageBufferData.h +++ b/Source/WebCore/platform/graphics/chromium/ImageBufferDataSkia.h @@ -28,9 +28,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ImageBufferData_h -#define ImageBufferData_h - #include "PlatformContextSkia.h" #include "skia/ext/platform_canvas.h" @@ -41,10 +38,8 @@ class ImageBufferData { public: ImageBufferData(const IntSize&); - skia::PlatformCanvas m_canvas; + OwnPtr<SkCanvas> m_canvas; PlatformContextSkia m_platformContext; }; -} // namespace WebCore - -#endif // ImageBufferData_h +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp index 60c1332..d72fb1e 100644 --- a/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp @@ -34,6 +34,7 @@ #include "ImageLayerChromium.h" +#include "cc/CCLayerImpl.h" #include "Image.h" #include "LayerRendererChromium.h" #include "LayerTexture.h" @@ -47,42 +48,69 @@ PassRefPtr<ImageLayerChromium> ImageLayerChromium::create(GraphicsLayerChromium* ImageLayerChromium::ImageLayerChromium(GraphicsLayerChromium* owner) : ContentLayerChromium(owner) + , m_imageForCurrentFrame(0) , m_contents(0) { } void ImageLayerChromium::setContents(Image* contents) { - // Check if the image has changed. - if (m_contents == contents) + // setContents() currently gets called whenever there is any + // style change that affects the layer even if that change doesn't + // affect the actual contents of the image (e.g. a CSS animation). + // With this check in place we avoid unecessary texture uploads. + if ((m_contents == contents) && (m_contents->nativeImageForCurrentFrame() == m_imageForCurrentFrame)) return; + m_contents = contents; + m_imageForCurrentFrame = m_contents->nativeImageForCurrentFrame(); + m_dirtyRect = IntRect(IntPoint(0, 0), bounds()); setNeedsDisplay(); } -void ImageLayerChromium::paintContentsIfDirty() +void ImageLayerChromium::paintContentsIfDirty(const IntRect&) { ASSERT(layerRenderer()); - // FIXME: Remove this test when tiled layers are implemented. - if (requiresClippedUpdateRect()) { - // Use the base version of updateContents which draws a subset of the - // image to a bitmap, as the pixel contents can't be uploaded directly. - ContentLayerChromium::paintContentsIfDirty(); - return; + if (!m_dirtyRect.isEmpty()) { + m_decodedImage.updateFromImage(m_contents->nativeImageForCurrentFrame()); } - - m_decodedImage.updateFromImage(m_contents->nativeImageForCurrentFrame()); } -void ImageLayerChromium::updateTextureIfNeeded() +void ImageLayerChromium::updateCompositorResources() { - // FIXME: Remove this test when tiled layers are implemented. - if (requiresClippedUpdateRect()) { - ContentLayerChromium::updateTextureIfNeeded(); - return; + updateLayerSize(m_decodedImage.size()); + + IntRect paintRect(IntPoint(0, 0), m_decodedImage.size()); + if (!m_dirtyRect.isEmpty()) { + m_tiler->invalidateRect(paintRect); + m_dirtyRect = IntRect(); } - updateTexture(m_decodedImage.pixels(), m_decodedImage.size()); + m_tiler->updateFromPixels(paintRect, m_decodedImage.pixels()); +} + +IntRect ImageLayerChromium::layerBounds() const +{ + return IntRect(IntPoint(0, 0), m_decodedImage.size()); +} + +TransformationMatrix ImageLayerChromium::tilingTransform() +{ + // Tiler draws from the upper left corner. The draw transform + // specifies the middle of the layer. + TransformationMatrix transform = ccLayerImpl()->drawTransform(); + const IntRect sourceRect = layerBounds(); + const IntSize destSize = bounds(); + + transform.translate(-destSize.width() / 2.0, -destSize.height() / 2.0); + + // Tiler also draws at the original content size, so rescale the original + // image dimensions to the bounds that it is meant to be drawn at. + float scaleX = destSize.width() / static_cast<float>(sourceRect.size().width()); + float scaleY = destSize.height() / static_cast<float>(sourceRect.size().height()); + transform.scale3d(scaleX, scaleY, 1.0f); + + return transform; } } diff --git a/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.h b/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.h index 6addabc..8ab76a8 100644 --- a/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.h @@ -37,7 +37,7 @@ #include "ContentLayerChromium.h" #include "PlatformImage.h" -#if PLATFORM(CG) +#if USE(CG) #include <wtf/RetainPtr.h> #endif @@ -50,7 +50,8 @@ class ImageLayerChromium : public ContentLayerChromium { public: static PassRefPtr<ImageLayerChromium> create(GraphicsLayerChromium* owner = 0); - virtual void paintContentsIfDirty(); + virtual void paintContentsIfDirty(const IntRect& targetSurfaceRect); + virtual void updateCompositorResources(); virtual bool drawsContent() const { return m_contents; } void setContents(Image* image); @@ -58,12 +59,14 @@ public: protected: virtual const char* layerTypeAsString() const { return "ImageLayer"; } -private: - virtual void updateTextureIfNeeded(); + virtual TransformationMatrix tilingTransform(); + virtual IntRect layerBounds() const; +private: ImageLayerChromium(GraphicsLayerChromium* owner); PlatformImage m_decodedImage; + NativeImagePtr m_imageForCurrentFrame; RefPtr<Image> m_contents; }; diff --git a/Source/WebCore/platform/graphics/chromium/LayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/LayerChromium.cpp index bc28239..fba1dc5 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/LayerChromium.cpp @@ -89,6 +89,9 @@ LayerChromium::~LayerChromium() // way for us to be destroyed while we still have a superlayer. ASSERT(!superlayer()); + if (m_ccLayerImpl) + m_ccLayerImpl->resetOwner(); + // Remove the superlayer reference from all sublayers. removeAllSublayers(); } diff --git a/Source/WebCore/platform/graphics/chromium/LayerChromium.h b/Source/WebCore/platform/graphics/chromium/LayerChromium.h index 428ce61..5564f91 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/LayerChromium.h @@ -50,11 +50,6 @@ #include <wtf/text/StringHash.h> #include <wtf/text/WTFString.h> - -namespace skia { -class PlatformCanvas; -} - namespace WebCore { class CCLayerImpl; @@ -113,6 +108,7 @@ public: void setNeedsDisplay(const FloatRect& dirtyRect); void setNeedsDisplay(); + virtual void invalidateRect(const FloatRect& dirtyRect) {} const FloatRect& dirtyRect() const { return m_dirtyRect; } void resetNeedsDisplay(); @@ -156,11 +152,13 @@ public: // These methods typically need to be overwritten by derived classes. virtual bool drawsContent() const { return false; } + virtual void paintContentsIfDirty(const IntRect&) { } virtual void paintContentsIfDirty() { } virtual void updateCompositorResources() { } + virtual void setIsMask(bool) {} virtual void unreserveContentsTexture() { } virtual void bindContentsTexture() { } - virtual void draw() { } + virtual void draw(const IntRect&) { } // These exists just for debugging (via drawDebugBorder()). void setBorderColor(const Color&); diff --git a/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp index fc15abd..27a67e9 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp @@ -34,8 +34,8 @@ #if USE(ACCELERATED_COMPOSITING) #include "LayerRendererChromium.h" -#include "cc/CCLayerImpl.h" #include "Canvas2DLayerChromium.h" +#include "Extensions3DChromium.h" #include "FloatQuad.h" #include "GeometryBinding.h" #include "GraphicsContext3D.h" @@ -50,7 +50,7 @@ #if USE(SKIA) #include "NativeImageSkia.h" #include "PlatformContextSkia.h" -#elif PLATFORM(CG) +#elif USE(CG) #include <CoreGraphics/CGBitmapContext.h> #endif @@ -88,35 +88,38 @@ static bool isScaleOrTranslation(const TransformationMatrix& m) } -bool LayerRendererChromium::compareLayerZ(const CCLayerImpl* a, const CCLayerImpl* b) +bool LayerRendererChromium::compareLayerZ(const RefPtr<CCLayerImpl>& a, const RefPtr<CCLayerImpl>& b) { return a->drawDepth() < b->drawDepth(); } -PassRefPtr<LayerRendererChromium> LayerRendererChromium::create(PassRefPtr<GraphicsContext3D> context, PassOwnPtr<TilePaintInterface> contentPaint, PassOwnPtr<TilePaintInterface> scrollbarPaint) +PassRefPtr<LayerRendererChromium> LayerRendererChromium::create(PassRefPtr<GraphicsContext3D> context, PassOwnPtr<TilePaintInterface> contentPaint) { if (!context) return 0; - RefPtr<LayerRendererChromium> layerRenderer(adoptRef(new LayerRendererChromium(context, contentPaint, scrollbarPaint))); + RefPtr<LayerRendererChromium> layerRenderer(adoptRef(new LayerRendererChromium(context, contentPaint))); if (!layerRenderer->hardwareCompositing()) return 0; return layerRenderer.release(); } -LayerRendererChromium::LayerRendererChromium(PassRefPtr<GraphicsContext3D> context, PassOwnPtr<TilePaintInterface> contentPaint, PassOwnPtr<TilePaintInterface> scrollbarPaint) +LayerRendererChromium::LayerRendererChromium(PassRefPtr<GraphicsContext3D> context, + PassOwnPtr<TilePaintInterface> contentPaint) : m_viewportScrollPosition(IntPoint(-1, -1)) , m_rootLayer(0) , m_rootLayerContentPaint(contentPaint) - , m_rootLayerScrollbarPaint(scrollbarPaint) , m_currentShader(0) , m_currentRenderSurface(0) , m_offscreenFramebufferId(0) , m_compositeOffscreen(false) , m_context(context) + , m_childContextsWereCopied(false) + , m_contextSupportsLatch(false) , m_defaultRenderSurface(0) { + m_contextSupportsLatch = m_context->getExtensions()->supports("GL_CHROMIUM_latch"); m_hardwareCompositing = initializeSharedObjects(); m_rootLayerContentTiler = LayerTilerChromium::create(this, IntSize(256, 256), LayerTilerChromium::NoBorderTexels); ASSERT(m_rootLayerContentTiler); @@ -150,40 +153,9 @@ void LayerRendererChromium::useShader(unsigned programId) } } -IntRect LayerRendererChromium::verticalScrollbarRect() const -{ - IntRect verticalScrollbar(IntPoint(m_viewportContentRect.maxX(), m_viewportContentRect.y()), IntSize(m_viewportVisibleRect.width() - m_viewportContentRect.width(), m_viewportVisibleRect.height())); - return verticalScrollbar; -} - -IntRect LayerRendererChromium::horizontalScrollbarRect() const -{ - IntRect horizontalScrollbar(IntPoint(m_viewportContentRect.x(), m_viewportContentRect.maxY()), IntSize(m_viewportVisibleRect.width(), m_viewportVisibleRect.height() - m_viewportContentRect.height())); - return horizontalScrollbar; -} - void LayerRendererChromium::invalidateRootLayerRect(const IntRect& dirtyRect) { m_rootLayerContentTiler->invalidateRect(dirtyRect); - - // Scrollbars never need to render beyond the fold, so clip to the viewport. - IntRect visibleDirtyRect = dirtyRect; - visibleDirtyRect.intersect(m_viewportVisibleRect); - - if (m_horizontalScrollbarTiler) { - IntRect scrollbar = horizontalScrollbarRect(); - if (visibleDirtyRect.intersects(scrollbar)) { - m_horizontalScrollbarTiler->setLayerPosition(scrollbar.location()); - m_horizontalScrollbarTiler->invalidateRect(visibleDirtyRect); - } - } - if (m_verticalScrollbarTiler) { - IntRect scrollbar = verticalScrollbarRect(); - if (visibleDirtyRect.intersects(scrollbar)) { - m_verticalScrollbarTiler->setLayerPosition(scrollbar.location()); - m_verticalScrollbarTiler->invalidateRect(visibleDirtyRect); - } - } } void LayerRendererChromium::updateRootLayerContents() @@ -192,43 +164,14 @@ void LayerRendererChromium::updateRootLayerContents() m_rootLayerContentTiler->update(*m_rootLayerContentPaint, m_viewportVisibleRect); } -void LayerRendererChromium::updateRootLayerScrollbars() -{ - TRACE_EVENT("LayerRendererChromium::updateRootLayerScrollbars", this, 0); - if (m_viewportVisibleRect.width() > m_viewportContentRect.width()) { - IntRect verticalScrollbar = verticalScrollbarRect(); - IntSize tileSize = verticalScrollbar.size().shrunkTo(IntSize(m_maxTextureSize, m_maxTextureSize)); - if (!m_verticalScrollbarTiler) - m_verticalScrollbarTiler = LayerTilerChromium::create(this, tileSize, LayerTilerChromium::NoBorderTexels); - else - m_verticalScrollbarTiler->setTileSize(tileSize); - m_verticalScrollbarTiler->setLayerPosition(verticalScrollbar.location()); - m_verticalScrollbarTiler->update(*m_rootLayerScrollbarPaint, m_viewportVisibleRect); - } else - m_verticalScrollbarTiler.clear(); - - if (m_viewportVisibleRect.height() > m_viewportContentRect.height()) { - IntRect horizontalScrollbar = horizontalScrollbarRect(); - IntSize tileSize = horizontalScrollbar.size().shrunkTo(IntSize(m_maxTextureSize, m_maxTextureSize)); - if (!m_horizontalScrollbarTiler) - m_horizontalScrollbarTiler = LayerTilerChromium::create(this, tileSize, LayerTilerChromium::NoBorderTexels); - else - m_horizontalScrollbarTiler->setTileSize(tileSize); - m_horizontalScrollbarTiler->setLayerPosition(horizontalScrollbar.location()); - m_horizontalScrollbarTiler->update(*m_rootLayerScrollbarPaint, m_viewportVisibleRect); - } else - m_horizontalScrollbarTiler.clear(); -} - void LayerRendererChromium::drawRootLayer() { - m_rootLayerContentTiler->draw(m_viewportVisibleRect); - - if (m_verticalScrollbarTiler) - m_verticalScrollbarTiler->draw(m_viewportVisibleRect); + TransformationMatrix scroll; + scroll.translate(-m_viewportVisibleRect.x(), -m_viewportVisibleRect.y()); - if (m_horizontalScrollbarTiler) - m_horizontalScrollbarTiler->draw(m_viewportVisibleRect); + m_rootLayerContentTiler->uploadCanvas(); + m_rootLayerContentTiler->draw(m_viewportVisibleRect, scroll, 1.0f); + m_rootLayerContentTiler->unreserveTextures(); } void LayerRendererChromium::setViewport(const IntRect& visibleRect, const IntRect& contentRect, const IntPoint& scrollPosition) @@ -243,12 +186,7 @@ void LayerRendererChromium::setViewport(const IntRect& visibleRect, const IntRec // Reset the current render surface to force an update of the viewport and // projection matrix next time useRenderSurface is called. m_currentRenderSurface = 0; - m_rootLayerContentTiler->invalidateEntireLayer(); - if (m_horizontalScrollbarTiler) - m_horizontalScrollbarTiler->invalidateEntireLayer(); - if (m_verticalScrollbarTiler) - m_verticalScrollbarTiler->invalidateEntireLayer(); } } @@ -266,18 +204,56 @@ void LayerRendererChromium::updateAndDrawLayers() if (!m_rootLayer) return; - updateRootLayerScrollbars(); + LayerList renderSurfaceLayerList; - Vector<CCLayerImpl*> renderSurfaceLayerList; updateLayers(renderSurfaceLayerList); + // Before drawLayers: + if (hardwareCompositing() && m_contextSupportsLatch) { + // FIXME: The multithreaded compositor case will not work as long as + // copyTexImage2D resolves to the parent texture, because the main + // thread can execute WebGL calls on the child context at any time, + // potentially clobbering the parent texture that is being renderered + // by the compositor thread. + if (m_childContextsWereCopied) { + Extensions3DChromium* parentExt = static_cast<Extensions3DChromium*>(m_context->getExtensions()); + // For each child context: + // glWaitLatch(Offscreen->Compositor); + ChildContextMap::iterator i = m_childContexts.begin(); + for (; i != m_childContexts.end(); ++i) { + Extensions3DChromium* childExt = static_cast<Extensions3DChromium*>(i->first->getExtensions()); + GC3Duint latchId; + childExt->getChildToParentLatchCHROMIUM(&latchId); + parentExt->waitLatchCHROMIUM(latchId); + } + } + // Reset to false to indicate that we have consumed the dirty child + // contexts' parent textures. (This is only useful when the compositor + // is multithreaded.) + m_childContextsWereCopied = false; + } + drawLayers(renderSurfaceLayerList); + // After drawLayers: + if (hardwareCompositing() && m_contextSupportsLatch) { + Extensions3DChromium* parentExt = static_cast<Extensions3DChromium*>(m_context->getExtensions()); + // For each child context: + // glSetLatch(Compositor->Offscreen); + ChildContextMap::iterator i = m_childContexts.begin(); + for (; i != m_childContexts.end(); ++i) { + Extensions3DChromium* childExt = static_cast<Extensions3DChromium*>(i->first->getExtensions()); + GC3Duint latchId; + childExt->getParentToChildLatchCHROMIUM(&latchId); + parentExt->setLatchCHROMIUM(latchId); + } + } + if (isCompositingOffscreen()) copyOffscreenTextureToDisplay(); } -void LayerRendererChromium::updateLayers(Vector<CCLayerImpl*>& renderSurfaceLayerList) +void LayerRendererChromium::updateLayers(LayerList& renderSurfaceLayerList) { TRACE_EVENT("LayerRendererChromium::updateLayers", this, 0); m_rootLayer->createCCLayerImplIfNeeded(); @@ -289,8 +265,7 @@ void LayerRendererChromium::updateLayers(Vector<CCLayerImpl*>& renderSurfaceLaye rootDrawLayer->renderSurface()->m_contentRect = IntRect(IntPoint(0, 0), m_viewportVisibleRect.size()); - // Scissor out the scrollbars to avoid rendering on top of them. - IntRect rootScissorRect(m_viewportContentRect); + IntRect rootScissorRect(m_viewportVisibleRect); // The scissorRect should not include the scroll offset. rootScissorRect.move(-m_viewportScrollPosition.x(), -m_viewportScrollPosition.y()); rootDrawLayer->setScissorRect(rootScissorRect); @@ -309,10 +284,51 @@ void LayerRendererChromium::updateLayers(Vector<CCLayerImpl*>& renderSurfaceLaye paintContentsRecursive(m_rootLayer.get()); + // FIXME: Before updateCompositorResourcesRecursive, when the compositor runs in + // its own thread, and when the copyTexImage2D bug is fixed, insert + // a glWaitLatch(Compositor->Offscreen) on all child contexts here instead + // of after updateCompositorResourcesRecursive. + // Also uncomment the glSetLatch(Compositor->Offscreen) code in addChildContext. +// if (hardwareCompositing() && m_contextSupportsLatch) { +// // For each child context: +// // glWaitLatch(Compositor->Offscreen); +// ChildContextMap::iterator i = m_childContexts.begin(); +// for (; i != m_childContexts.end(); ++i) { +// Extensions3DChromium* ext = static_cast<Extensions3DChromium*>(i->first->getExtensions()); +// GC3Duint childToParentLatchId, parentToChildLatchId; +// ext->getParentToChildLatchCHROMIUM(&parentToChildLatchId); +// ext->waitLatchCHROMIUM(parentToChildLatchId); +// } +// } + updateCompositorResourcesRecursive(m_rootLayer.get()); + + // After updateCompositorResourcesRecursive, set/wait latches for all child + // contexts. This will prevent the compositor from using any of the child + // parent textures while WebGL commands are executing from javascript *and* + // while the final parent texture is being blit'd. copyTexImage2D + // uses the parent texture as a temporary resolve buffer, so that's why the + // waitLatch is below, to block the compositor from using the parent texture + // until the next WebGL SwapBuffers (or copyTextureToParentTexture for + // Canvas2D). + if (hardwareCompositing() && m_contextSupportsLatch) { + m_childContextsWereCopied = true; + // For each child context: + // glSetLatch(Offscreen->Compositor); + // glWaitLatch(Compositor->Offscreen); + ChildContextMap::iterator i = m_childContexts.begin(); + for (; i != m_childContexts.end(); ++i) { + Extensions3DChromium* ext = static_cast<Extensions3DChromium*>(i->first->getExtensions()); + GC3Duint childToParentLatchId, parentToChildLatchId; + ext->getParentToChildLatchCHROMIUM(&parentToChildLatchId); + ext->getChildToParentLatchCHROMIUM(&childToParentLatchId); + ext->setLatchCHROMIUM(childToParentLatchId); + ext->waitLatchCHROMIUM(parentToChildLatchId); + } + } } -void LayerRendererChromium::drawLayers(const Vector<CCLayerImpl*>& renderSurfaceLayerList) +void LayerRendererChromium::drawLayers(const LayerList& renderSurfaceLayerList) { TRACE_EVENT("LayerRendererChromium::drawLayers", this, 0); CCLayerImpl* rootDrawLayer = m_rootLayer->ccLayerImpl(); @@ -347,13 +363,14 @@ void LayerRendererChromium::drawLayers(const Vector<CCLayerImpl*>& renderSurface m_context->colorMask(true, true, true, true); GLC(m_context.get(), m_context->enable(GraphicsContext3D::BLEND)); + GLC(m_context.get(), m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA)); GLC(m_context.get(), m_context->enable(GraphicsContext3D::SCISSOR_TEST)); // Update the contents of the render surfaces. We traverse the array from // back to front to guarantee that nested render surfaces get rendered in the // correct order. for (int surfaceIndex = renderSurfaceLayerList.size() - 1; surfaceIndex >= 0 ; --surfaceIndex) { - CCLayerImpl* renderSurfaceLayer = renderSurfaceLayerList[surfaceIndex]; + CCLayerImpl* renderSurfaceLayer = renderSurfaceLayerList[surfaceIndex].get(); ASSERT(renderSurfaceLayer->renderSurface()); // Render surfaces whose drawable area has zero width or height @@ -369,10 +386,10 @@ void LayerRendererChromium::drawLayers(const Vector<CCLayerImpl*>& renderSurface GLC(m_context.get(), m_context->enable(GraphicsContext3D::SCISSOR_TEST)); } - Vector<CCLayerImpl*>& layerList = renderSurfaceLayer->renderSurface()->m_layerList; + LayerList& layerList = renderSurfaceLayer->renderSurface()->m_layerList; ASSERT(layerList.size()); for (unsigned layerIndex = 0; layerIndex < layerList.size(); ++layerIndex) - drawLayer(layerList[layerIndex], renderSurfaceLayer->renderSurface()); + drawLayer(layerList[layerIndex].get(), renderSurfaceLayer->renderSurface()); } } @@ -412,10 +429,6 @@ void LayerRendererChromium::setRootLayer(PassRefPtr<LayerChromium> layer) if (m_rootLayer) m_rootLayer->setLayerRenderer(this); m_rootLayerContentTiler->invalidateEntireLayer(); - if (m_horizontalScrollbarTiler) - m_horizontalScrollbarTiler->invalidateEntireLayer(); - if (m_verticalScrollbarTiler) - m_verticalScrollbarTiler->invalidateEntireLayer(); } void LayerRendererChromium::getFramebufferPixels(void *pixels, const IntRect& rect) @@ -473,7 +486,7 @@ bool LayerRendererChromium::isLayerVisible(LayerChromium* layer, const Transform // Recursively walks the layer tree starting at the given node and computes all the // necessary transformations, scissor rectangles, render surfaces, etc. -void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* layer, const TransformationMatrix& parentMatrix, Vector<CCLayerImpl*>& renderSurfaceLayerList, Vector<CCLayerImpl*>& layerList) +void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* layer, const TransformationMatrix& parentMatrix, LayerList& renderSurfaceLayerList, LayerList& layerList) { // Make sure we have CCLayerImpls for this subtree. layer->createCCLayerImplIfNeeded(); @@ -659,7 +672,18 @@ void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* lay // M[s] = M * Tr[-center] sublayerMatrix.translate3d(-bounds.width() * 0.5, -bounds.height() * 0.5, 0); - Vector<CCLayerImpl*>& descendants = (drawLayer->renderSurface() ? drawLayer->renderSurface()->m_layerList : layerList); + // Compute the depth value of the center of the layer which will be used when + // sorting the layers for the preserves-3d property. + const TransformationMatrix& layerDrawMatrix = drawLayer->renderSurface() ? drawLayer->renderSurface()->m_drawTransform : drawLayer->drawTransform(); + if (drawLayer->superlayer()) { + if (!drawLayer->superlayer()->preserves3D()) + drawLayer->setDrawDepth(drawLayer->superlayer()->drawDepth()); + else + drawLayer->setDrawDepth(layerDrawMatrix.m43()); + } else + drawLayer->setDrawDepth(0); + + LayerList& descendants = (drawLayer->renderSurface() ? drawLayer->renderSurface()->m_layerList : layerList); descendants.append(drawLayer); unsigned thisLayerIndex = descendants.size() - 1; @@ -730,17 +754,6 @@ void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* lay } } - // Compute the depth value of the center of the layer which will be used when - // sorting the layers for the preserves-3d property. - const TransformationMatrix& layerDrawMatrix = drawLayer->renderSurface() ? drawLayer->renderSurface()->m_drawTransform : drawLayer->drawTransform(); - if (drawLayer->superlayer()) { - if (!drawLayer->superlayer()->preserves3D()) - drawLayer->setDrawDepth(drawLayer->superlayer()->drawDepth()); - else - drawLayer->setDrawDepth(layerDrawMatrix.m43()); - } else - drawLayer->setDrawDepth(0); - // If preserves-3d then sort all the descendants by the Z coordinate of their // center. If the preserves-3d property is also set on the superlayer then // skip the sorting as the superlayer will sort all the descendants anyway. @@ -757,14 +770,16 @@ void LayerRendererChromium::paintContentsRecursive(LayerChromium* layer) if (layer->bounds().isEmpty()) return; + const IntRect targetSurfaceRect = layer->ccLayerImpl()->scissorRect(); + if (layer->drawsContent()) - layer->paintContentsIfDirty(); + layer->paintContentsIfDirty(targetSurfaceRect); if (layer->maskLayer() && layer->maskLayer()->drawsContent()) - layer->maskLayer()->paintContentsIfDirty(); + layer->maskLayer()->paintContentsIfDirty(targetSurfaceRect); if (layer->replicaLayer() && layer->replicaLayer()->drawsContent()) - layer->replicaLayer()->paintContentsIfDirty(); + layer->replicaLayer()->paintContentsIfDirty(targetSurfaceRect); if (layer->replicaLayer() && layer->replicaLayer()->maskLayer() && layer->replicaLayer()->maskLayer()->drawsContent()) - layer->replicaLayer()->maskLayer()->paintContentsIfDirty(); + layer->replicaLayer()->maskLayer()->paintContentsIfDirty(targetSurfaceRect); } void LayerRendererChromium::updateCompositorResourcesRecursive(LayerChromium* layer) @@ -816,7 +831,7 @@ void LayerRendererChromium::copyOffscreenTextureToDisplay() m_defaultRenderSurface->m_drawTransform.translate3d(0.5 * m_defaultRenderSurface->m_contentRect.width(), 0.5 * m_defaultRenderSurface->m_contentRect.height(), 0); m_defaultRenderSurface->m_drawOpacity = 1; - m_defaultRenderSurface->draw(); + m_defaultRenderSurface->draw(m_defaultRenderSurface->m_contentRect); } } @@ -857,10 +872,13 @@ bool LayerRendererChromium::useRenderSurface(RenderSurfaceChromium* renderSurfac void LayerRendererChromium::drawLayer(CCLayerImpl* layer, RenderSurfaceChromium* targetSurface) { if (layer->renderSurface() && layer->renderSurface() != targetSurface) { - layer->renderSurface()->draw(); + layer->renderSurface()->draw(layer->getDrawRect()); return; } + if (!layer->drawsContent()) + return; + if (layer->bounds().isEmpty()) { layer->unreserveContentsTexture(); return; @@ -894,8 +912,7 @@ void LayerRendererChromium::drawLayer(CCLayerImpl* layer, RenderSurfaceChromium* } } - if (layer->drawsContent()) - layer->draw(); + layer->draw(layer->scissorRect()); // Draw the debug border if there is one. layer->drawDebugBorder(); @@ -968,7 +985,6 @@ bool LayerRendererChromium::initializeSharedObjects() m_sharedGeometry = adoptPtr(new GeometryBinding(m_context.get())); m_borderProgram = adoptPtr(new LayerChromium::BorderProgram(m_context.get())); - m_contentLayerProgram = adoptPtr(new ContentLayerChromium::Program(m_context.get())); m_canvasLayerProgram = adoptPtr(new CCCanvasLayerImpl::Program(m_context.get())); m_videoLayerRGBAProgram = adoptPtr(new CCVideoLayerImpl::RGBAProgram(m_context.get())); m_videoLayerYUVProgram = adoptPtr(new CCVideoLayerImpl::YUVProgram(m_context.get())); @@ -978,7 +994,7 @@ bool LayerRendererChromium::initializeSharedObjects() m_tilerProgram = adoptPtr(new LayerTilerChromium::Program(m_context.get())); if (!m_sharedGeometry->initialized() || !m_borderProgram->initialized() - || !m_contentLayerProgram->initialized() || !m_canvasLayerProgram->initialized() + || !m_canvasLayerProgram->initialized() || !m_videoLayerRGBAProgram->initialized() || !m_videoLayerYUVProgram->initialized() || !m_pluginLayerProgram->initialized() || !m_renderSurfaceProgram->initialized() || !m_renderSurfaceMaskProgram->initialized() || !m_tilerProgram->initialized()) { @@ -997,7 +1013,6 @@ void LayerRendererChromium::cleanupSharedObjects() m_sharedGeometry.clear(); m_borderProgram.clear(); - m_contentLayerProgram.clear(); m_canvasLayerProgram.clear(); m_videoLayerRGBAProgram.clear(); m_videoLayerYUVProgram.clear(); @@ -1010,8 +1025,6 @@ void LayerRendererChromium::cleanupSharedObjects() // Clear tilers before the texture manager, as they have references to textures. m_rootLayerContentTiler.clear(); - m_horizontalScrollbarTiler.clear(); - m_verticalScrollbarTiler.clear(); m_textureManager.clear(); } @@ -1027,6 +1040,48 @@ String LayerRendererChromium::layerTreeAsText() const return ts.release(); } +void LayerRendererChromium::addChildContext(GraphicsContext3D* ctx) +{ + if (!ctx->getExtensions()->supports("GL_CHROMIUM_latch")) + return; + + // This is a ref-counting map, because some contexts are shared by multiple + // layers (specifically, Canvas2DLayerChromium). + + // Insert the ctx with a count of 1, or return the existing iterator. + std::pair<ChildContextMap::iterator, bool> insert_result = m_childContexts.add(ctx, 1); + if (!insert_result.second) { + // Already present in map, so increment. + ++insert_result.first->second; + } else { +// FIXME(jbates): when compositor is multithreaded and copyTexImage2D bug is fixed, +// uncomment this block: +// // This is a new child context - set the parentToChild latch so that it +// // can continue past its first wait latch. +// Extensions3DChromium* ext = static_cast<Extensions3DChromium*>(ctx->getExtensions()); +// GC3Duint latchId; +// ext->getParentToChildLatchCHROMIUM(&latchId); +// ext->setLatchCHROMIUM(0, latchId); + } +} + +void LayerRendererChromium::removeChildContext(GraphicsContext3D* ctx) +{ + if (!ctx->getExtensions()->supports("GL_CHROMIUM_latch")) + return; + + ChildContextMap::iterator i = m_childContexts.find(ctx); + if (i != m_childContexts.end()) { + if (--i->second <= 0) { + // Count reached zero, so remove from map. + m_childContexts.remove(i); + } + } else { + // error + ASSERT(0 && "m_childContexts map has mismatched add/remove calls"); + } +} + void LayerRendererChromium::dumpRenderSurfaces(TextStream& ts, int indent, LayerChromium* layer) const { if (layer->ccLayerImpl()->renderSurface()) diff --git a/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h index 667ede2..813eb46 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h +++ b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h @@ -52,22 +52,22 @@ #include <wtf/RefCounted.h> #include <wtf/Vector.h> -#if PLATFORM(CG) +#if USE(CG) #include <CoreGraphics/CGContext.h> #include <wtf/RetainPtr.h> #endif namespace WebCore { +class CCHeadsUpDisplay; class CCLayerImpl; class GeometryBinding; class GraphicsContext3D; -class CCHeadsUpDisplay; // Class that handles drawing of composited render layers using GL. class LayerRendererChromium : public RefCounted<LayerRendererChromium> { public: - static PassRefPtr<LayerRendererChromium> create(PassRefPtr<GraphicsContext3D>, PassOwnPtr<TilePaintInterface> contentPaint, PassOwnPtr<TilePaintInterface> scrollbarPaint); + static PassRefPtr<LayerRendererChromium> create(PassRefPtr<GraphicsContext3D>, PassOwnPtr<TilePaintInterface> contentPaint); ~LayerRendererChromium(); @@ -88,7 +88,7 @@ public: IntSize viewportSize() const { return m_viewportVisibleRect.size(); } - void setRootLayer(PassRefPtr<LayerChromium> layer); + void setRootLayer(PassRefPtr<LayerChromium>); LayerChromium* rootLayer() { return m_rootLayer.get(); } void transferRootLayer(LayerRendererChromium* other) { other->m_rootLayer = m_rootLayer.release(); } @@ -110,7 +110,6 @@ public: const GeometryBinding* sharedGeometry() const { return m_sharedGeometry.get(); } const LayerChromium::BorderProgram* borderProgram() const { return m_borderProgram.get(); } - const ContentLayerChromium::Program* contentLayerProgram() const { return m_contentLayerProgram.get(); } const RenderSurfaceChromium::Program* renderSurfaceProgram() const { return m_renderSurfaceProgram.get(); } const RenderSurfaceChromium::MaskProgram* renderSurfaceMaskProgram() const { return m_renderSurfaceMaskProgram.get(); } const LayerTilerChromium::Program* tilerProgram() const { return m_tilerProgram.get(); } @@ -131,17 +130,23 @@ public: String layerTreeAsText() const; + void addChildContext(GraphicsContext3D*); + void removeChildContext(GraphicsContext3D*); + private: - explicit LayerRendererChromium(PassRefPtr<GraphicsContext3D>, PassOwnPtr<TilePaintInterface> contentPaint, PassOwnPtr<TilePaintInterface> scrollbarPaint); + typedef Vector<RefPtr<CCLayerImpl> > LayerList; + typedef HashMap<GraphicsContext3D*, int> ChildContextMap; + + explicit LayerRendererChromium(PassRefPtr<GraphicsContext3D>, PassOwnPtr<TilePaintInterface> contentPaint); - void updateLayers(Vector<CCLayerImpl*>& renderSurfaceLayerList); + void updateLayers(LayerList& renderSurfaceLayerList); void updateRootLayerContents(); - void updateRootLayerScrollbars(); - void updatePropertiesAndRenderSurfaces(LayerChromium*, const TransformationMatrix& parentMatrix, Vector<CCLayerImpl*>& renderSurfaceLayerList, Vector<CCLayerImpl*>& layerList); + void updatePropertiesAndRenderSurfaces(LayerChromium*, const TransformationMatrix& parentMatrix, LayerList& renderSurfaceLayerList, LayerList& layers); + void paintContentsRecursive(LayerChromium*); void updateCompositorResourcesRecursive(LayerChromium*); - void drawLayers(const Vector<CCLayerImpl*>& renderSurfaceLayerList); + void drawLayers(const LayerList& renderSurfaceLayerList); void drawLayer(CCLayerImpl*, RenderSurfaceChromium*); void drawRootLayer(); @@ -156,16 +161,13 @@ private: bool makeContextCurrent(); - static bool compareLayerZ(const CCLayerImpl*, const CCLayerImpl*); + static bool compareLayerZ(const RefPtr<CCLayerImpl>&, const RefPtr<CCLayerImpl>&); void dumpRenderSurfaces(TextStream&, int indent, LayerChromium*) const; bool initializeSharedObjects(); void cleanupSharedObjects(); - IntRect verticalScrollbarRect() const; - IntRect horizontalScrollbarRect() const; - IntRect m_viewportVisibleRect; IntRect m_viewportContentRect; IntPoint m_viewportScrollPosition; @@ -174,10 +176,7 @@ private: RefPtr<LayerChromium> m_rootLayer; OwnPtr<TilePaintInterface> m_rootLayerContentPaint; - OwnPtr<TilePaintInterface> m_rootLayerScrollbarPaint; OwnPtr<LayerTilerChromium> m_rootLayerContentTiler; - OwnPtr<LayerTilerChromium> m_horizontalScrollbarTiler; - OwnPtr<LayerTilerChromium> m_verticalScrollbarTiler; bool m_hardwareCompositing; @@ -188,10 +187,10 @@ private: bool m_compositeOffscreen; #if USE(SKIA) - OwnPtr<skia::PlatformCanvas> m_rootLayerCanvas; + OwnPtr<SkCanvas> m_rootLayerCanvas; OwnPtr<PlatformContextSkia> m_rootLayerSkiaContext; OwnPtr<GraphicsContext> m_rootLayerGraphicsContext; -#elif PLATFORM(CG) +#elif USE(CG) Vector<uint8_t> m_rootLayerBackingStore; RetainPtr<CGContextRef> m_rootLayerCGContext; OwnPtr<GraphicsContext> m_rootLayerGraphicsContext; @@ -206,7 +205,6 @@ private: // we cannot store these values in static variables. OwnPtr<GeometryBinding> m_sharedGeometry; OwnPtr<LayerChromium::BorderProgram> m_borderProgram; - OwnPtr<ContentLayerChromium::Program> m_contentLayerProgram; OwnPtr<RenderSurfaceChromium::Program> m_renderSurfaceProgram; OwnPtr<RenderSurfaceChromium::MaskProgram> m_renderSurfaceMaskProgram; OwnPtr<LayerTilerChromium::Program> m_tilerProgram; @@ -220,6 +218,15 @@ private: OwnPtr<CCHeadsUpDisplay> m_headsUpDisplay; RefPtr<GraphicsContext3D> m_context; + ChildContextMap m_childContexts; + + // If true, the child contexts were copied to the compositor texture targets + // and the compositor will need to wait on the proper latches before using + // the target textures. If false, the compositor is reusing the textures + // from last frame. + bool m_childContextsWereCopied; + + bool m_contextSupportsLatch; RenderSurfaceChromium* m_defaultRenderSurface; }; diff --git a/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.cpp b/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.cpp index bc37201..54c6ac2 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.cpp @@ -40,6 +40,8 @@ using namespace std; +static int minTextureSize = 16; + namespace WebCore { PassOwnPtr<LayerTilerChromium> LayerTilerChromium::create(LayerRendererChromium* layerRenderer, const IntSize& tileSize, BorderTexelOption border) @@ -69,8 +71,10 @@ GraphicsContext3D* LayerTilerChromium::layerRendererContext() const return layerRenderer()->context(); } -void LayerTilerChromium::setTileSize(const IntSize& size) +void LayerTilerChromium::setTileSize(const IntSize& requestedSize) { + IntSize size(max(minTextureSize, requestedSize.width()), max(minTextureSize, requestedSize.height())); + if (m_tileSize == size) return; @@ -81,6 +85,12 @@ void LayerTilerChromium::setTileSize(const IntSize& size) m_tilingData.setMaxTextureSize(max(size.width(), size.height())); } +LayerTexture* LayerTilerChromium::getSingleTexture() +{ + Tile* tile = tileAt(0, 0); + return tile ? tile->texture() : 0; +} + void LayerTilerChromium::reset() { m_tiles.clear(); @@ -180,7 +190,7 @@ IntRect LayerTilerChromium::tileLayerRect(const Tile* tile) const void LayerTilerChromium::invalidateRect(const IntRect& contentRect) { - if (contentRect.isEmpty()) + if (contentRect.isEmpty() || m_skipsDraw) return; growLayerToContain(contentRect); @@ -236,6 +246,8 @@ void LayerTilerChromium::update(TilePaintInterface& painter, const IntRect& cont tile = createTile(i, j); if (!tile->texture()->isValid(m_tileSize, GraphicsContext3D::RGBA)) tile->m_dirtyLayerRect = tileLayerRect(tile); + else + tile->texture()->reserve(m_tileSize, GraphicsContext3D::RGBA); dirtyLayerRect.unite(tile->m_dirtyLayerRect); } } @@ -243,27 +255,35 @@ void LayerTilerChromium::update(TilePaintInterface& painter, const IntRect& cont if (dirtyLayerRect.isEmpty()) return; - const IntRect paintRect = layerRectToContentRect(dirtyLayerRect); + m_paintRect = layerRectToContentRect(dirtyLayerRect); + + m_canvas.resize(m_paintRect.size()); - m_canvas.resize(paintRect.size()); - PlatformCanvas::Painter canvasPainter(&m_canvas); - canvasPainter.context()->translate(-paintRect.x(), -paintRect.y()); + // Assumption: if a tiler is using border texels, then it is because the + // layer is likely to be filtered or transformed. Because of it might be + // transformed, draw the text in grayscale instead of subpixel antialiasing. + PlatformCanvas::Painter::TextOption textOption = m_tilingData.borderTexels() ? PlatformCanvas::Painter::GrayscaleText : PlatformCanvas::Painter::SubpixelText; + PlatformCanvas::Painter canvasPainter(&m_canvas, textOption); + canvasPainter.context()->translate(-m_paintRect.x(), -m_paintRect.y()); { TRACE_EVENT("LayerTilerChromium::update::paint", this, 0); - painter.paint(*canvasPainter.context(), paintRect); + painter.paint(*canvasPainter.context(), m_paintRect); } +} +void LayerTilerChromium::uploadCanvas() +{ PlatformCanvas::AutoLocker locker(&m_canvas); { TRACE_EVENT("LayerTilerChromium::updateFromPixels", this, 0); - updateFromPixels(paintRect, locker.pixels()); + updateFromPixels(m_paintRect, locker.pixels()); } } void LayerTilerChromium::updateFromPixels(const IntRect& paintRect, const uint8_t* paintPixels) { // Painting could cause compositing to get turned off, which may cause the tiler to become invalidated mid-update. - if (!m_tiles.size()) + if (!m_tilingData.totalSizeX() || !m_tilingData.totalSizeY()) return; GraphicsContext3D* context = layerRendererContext(); @@ -274,21 +294,26 @@ void LayerTilerChromium::updateFromPixels(const IntRect& paintRect, const uint8_ for (int i = left; i <= right; ++i) { Tile* tile = tileAt(i, j); if (!tile) - CRASH(); - if (!tile->dirty()) + tile = createTile(i, j); + else if (!tile->dirty()) continue; // Calculate page-space rectangle to copy from. IntRect sourceRect = tileContentRect(tile); const IntPoint anchor = sourceRect.location(); sourceRect.intersect(layerRectToContentRect(tile->m_dirtyLayerRect)); + // Paint rect not guaranteed to line up on tile boundaries, so + // make sure that sourceRect doesn't extend outside of it. + sourceRect.intersect(paintRect); if (sourceRect.isEmpty()) continue; - if (!tile->texture()->reserve(m_tileSize, GraphicsContext3D::RGBA)) { - m_skipsDraw = true; - reset(); - return; + if (!tile->texture()->isReserved()) { + if (!tile->texture()->reserve(m_tileSize, GraphicsContext3D::RGBA)) { + m_skipsDraw = true; + reset(); + return; + } } // Calculate tile-space rectangle to upload into. @@ -324,8 +349,10 @@ void LayerTilerChromium::updateFromPixels(const IntRect& paintRect, const uint8_ } tile->texture()->bindTexture(); - GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST)); - GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::NEAREST)); + + const GC3Dint filter = m_tilingData.borderTexels() ? GraphicsContext3D::LINEAR : GraphicsContext3D::NEAREST; + GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, filter)); + GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, filter)); GLC(context, context->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, destRect.x(), destRect.y(), destRect.width(), destRect.height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, pixelSource)); @@ -339,7 +366,7 @@ void LayerTilerChromium::setLayerPosition(const IntPoint& layerPosition) m_layerPosition = layerPosition; } -void LayerTilerChromium::draw(const IntRect& contentRect) +void LayerTilerChromium::draw(const IntRect& contentRect, const TransformationMatrix& globalTransform, float opacity) { if (m_skipsDraw || !m_tiles.size()) return; @@ -354,17 +381,18 @@ void LayerTilerChromium::draw(const IntRect& contentRect) for (int j = top; j <= bottom; ++j) { for (int i = left; i <= right; ++i) { Tile* tile = tileAt(i, j); - ASSERT(tile); + if (!tile) + continue; tile->texture()->bindTexture(); - TransformationMatrix tileMatrix; + TransformationMatrix tileMatrix(globalTransform); // Don't use tileContentRect here, as that contains the full // rect with border texels which shouldn't be drawn. IntRect tileRect = m_tilingData.tileBounds(m_tilingData.tileIndex(tile->i(), tile->j())); tileRect.move(m_layerPosition.x(), m_layerPosition.y()); - tileMatrix.translate3d(tileRect.x() - contentRect.x() + tileRect.width() / 2.0, tileRect.y() - contentRect.y() + tileRect.height() / 2.0, 0); + tileMatrix.translate3d(tileRect.x() + tileRect.width() / 2.0, tileRect.y() + tileRect.height() / 2.0, 0); IntPoint texOffset = m_tilingData.textureOffset(tile->i(), tile->j()); float tileWidth = static_cast<float>(m_tileSize.width()); @@ -374,13 +402,21 @@ void LayerTilerChromium::draw(const IntRect& contentRect) float texScaleX = tileRect.width() / tileWidth; float texScaleY = tileRect.height() / tileHeight; - drawTexturedQuad(context, layerRenderer()->projectionMatrix(), tileMatrix, tileRect.width(), tileRect.height(), 1, texTranslateX, texTranslateY, texScaleX, texScaleY, program); - - tile->texture()->unreserve(); + drawTexturedQuad(context, layerRenderer()->projectionMatrix(), tileMatrix, tileRect.width(), tileRect.height(), opacity, texTranslateX, texTranslateY, texScaleX, texScaleY, program); } } } +void LayerTilerChromium::unreserveTextures() +{ + for (TileMap::iterator iter = m_tiles.begin(); iter != m_tiles.end(); ++iter) { + Tile* tile = iter->second.get(); + if (!tile) + continue; + tile->texture()->unreserve(); + } +} + void LayerTilerChromium::growLayerToContain(const IntRect& contentRect) { // Grow the tile array to contain this content rect. diff --git a/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.h b/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.h index 2f356e4..111dd7e 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.h @@ -56,19 +56,40 @@ public: ~LayerTilerChromium(); + // Set invalidations to be potentially repainted during update(). void invalidateRect(const IntRect& contentRect); void invalidateEntireLayer(); + + // Paint all invalidations and missing tiles needed to draw the contentRect + // into the internal canvas. void update(TilePaintInterface& painter, const IntRect& contentRect); + + // Reserve and upload tile textures from the internal canvas. + void uploadCanvas(); + + // Reserve and upload tile textures from an externally painted buffer. void updateFromPixels(const IntRect& paintRect, const uint8_t* pixels); - void draw(const IntRect& contentRect); + + // Draw all tiles that intersect with the content rect. + void draw(const IntRect& contentRect, const TransformationMatrix&, float opacity); + + // If uploadCanvas/updateFromPixels is called, this must be called after + // draw() to unreserve any textures that were reserved prior to uploading. + void unreserveTextures(); // Set position of this tiled layer in content space. void setLayerPosition(const IntPoint& position); // Change the tile size. This may invalidate all the existing tiles. void setTileSize(const IntSize& size); + void setLayerRenderer(LayerRendererChromium* layerRenderer) { m_layerRenderer = layerRenderer; } + + bool skipsDraw() const { return m_skipsDraw; } typedef ProgramBinding<VertexShaderPosTexTransform, FragmentShaderTexAlpha> Program; + // If this tiler has exactly one tile, return its texture. Otherwise, null. + LayerTexture* getSingleTexture(); + private: LayerTilerChromium(LayerRendererChromium*, const IntSize& tileSize, BorderTexelOption); @@ -140,6 +161,7 @@ private: // Tightly packed set of unused tiles. Vector<RefPtr<Tile> > m_unusedTiles; + IntRect m_paintRect; PlatformCanvas m_canvas; // Cache a tile-sized pixel buffer to draw into. diff --git a/Source/WebCore/platform/graphics/chromium/PlatformCanvas.cpp b/Source/WebCore/platform/graphics/chromium/PlatformCanvas.cpp index 29589f4..afaa6f7 100644 --- a/Source/WebCore/platform/graphics/chromium/PlatformCanvas.cpp +++ b/Source/WebCore/platform/graphics/chromium/PlatformCanvas.cpp @@ -34,7 +34,7 @@ #include "PlatformContextSkia.h" #include "SkColorPriv.h" #include "skia/ext/platform_canvas.h" -#elif PLATFORM(CG) +#elif USE(CG) #include <CoreGraphics/CGBitmapContext.h> #endif @@ -52,8 +52,8 @@ void PlatformCanvas::resize(const IntSize& size) { m_size = size; #if USE(SKIA) - m_skiaCanvas = new skia::PlatformCanvas(size.width(), size.height(), false); -#elif PLATFORM(CG) + m_skiaCanvas = skia::CreateBitmapCanvas(size.width(), size.height(), false); +#elif USE(CG) size_t bufferSize = size.width() * size.height() * 4; m_pixelData = adoptArrayPtr(new uint8_t[bufferSize]); memset(m_pixelData.get(), 0, bufferSize); @@ -73,8 +73,9 @@ PlatformCanvas::AutoLocker::AutoLocker(PlatformCanvas* canvas) m_pixels = static_cast<uint8_t*>(m_bitmap->getPixels()); } else m_bitmap = 0; -#elif PLATFORM(CG) - m_pixels = &canvas->m_pixelData[0]; +#elif USE(CG) + if (canvas->m_pixelData) + m_pixels = &canvas->m_pixelData[0]; #endif } @@ -86,16 +87,15 @@ PlatformCanvas::AutoLocker::~AutoLocker() #endif } -PlatformCanvas::Painter::Painter(PlatformCanvas* canvas) +PlatformCanvas::Painter::Painter(PlatformCanvas* canvas, PlatformCanvas::Painter::TextOption option) { #if USE(SKIA) m_skiaContext = adoptPtr(new PlatformContextSkia(canvas->m_skiaCanvas.get())); - // This is needed to get text to show up correctly. - m_skiaContext->setDrawingToImageBuffer(true); + m_skiaContext->setDrawingToImageBuffer(option == GrayscaleText); m_context = adoptPtr(new GraphicsContext(reinterpret_cast<PlatformGraphicsContext*>(m_skiaContext.get()))); -#elif PLATFORM(CG) +#elif USE(CG) m_colorSpace = CGColorSpaceCreateDeviceRGB(); size_t rowBytes = canvas->size().width() * 4; diff --git a/Source/WebCore/platform/graphics/chromium/PlatformCanvas.h b/Source/WebCore/platform/graphics/chromium/PlatformCanvas.h index 262fdd0..b002d26 100644 --- a/Source/WebCore/platform/graphics/chromium/PlatformCanvas.h +++ b/Source/WebCore/platform/graphics/chromium/PlatformCanvas.h @@ -31,7 +31,7 @@ #include <wtf/Noncopyable.h> #include <wtf/OwnPtr.h> -#if PLATFORM(CG) +#if USE(CG) #include <CoreGraphics/CGColorSpace.h> #include <CoreGraphics/CGContext.h> #include <wtf/OwnArrayPtr.h> @@ -39,8 +39,8 @@ #endif #if USE(SKIA) -namespace skia { class PlatformCanvas; } class SkBitmap; +class SkCanvas; #endif namespace WebCore { @@ -78,7 +78,9 @@ public: class Painter { WTF_MAKE_NONCOPYABLE(Painter); public: - explicit Painter(PlatformCanvas*); + enum TextOption { GrayscaleText, SubpixelText }; + + Painter(PlatformCanvas*, TextOption); ~Painter(); GraphicsContext* context() const { return m_context.get(); } @@ -86,7 +88,7 @@ public: OwnPtr<GraphicsContext> m_context; #if USE(SKIA) OwnPtr<PlatformContextSkia> m_skiaContext; -#elif PLATFORM(CG) +#elif USE(CG) RetainPtr<CGColorSpaceRef> m_colorSpace; RetainPtr<CGContextRef> m_contextCG; #endif @@ -97,8 +99,8 @@ public: private: #if USE(SKIA) - OwnPtr<skia::PlatformCanvas> m_skiaCanvas; -#elif PLATFORM(CG) + OwnPtr<SkCanvas> m_skiaCanvas; +#elif USE(CG) OwnArrayPtr<uint8_t> m_pixelData; #endif IntSize m_size; diff --git a/Source/WebCore/platform/graphics/chromium/PlatformImage.cpp b/Source/WebCore/platform/graphics/chromium/PlatformImage.cpp index 62cf4f8..c31b29c 100644 --- a/Source/WebCore/platform/graphics/chromium/PlatformImage.cpp +++ b/Source/WebCore/platform/graphics/chromium/PlatformImage.cpp @@ -30,7 +30,7 @@ #if USE(SKIA) #include "NativeImageSkia.h" #include "PlatformContextSkia.h" -#elif PLATFORM(CG) +#elif USE(CG) #include <CoreGraphics/CGBitmapContext.h> #include <CoreGraphics/CGContext.h> #include <CoreGraphics/CGImage.h> @@ -54,7 +54,7 @@ void PlatformImage::updateFromImage(NativeImagePtr nativeImage) IntSize bitmapSize(skiaBitmap->width(), skiaBitmap->height()); ASSERT(skiaBitmap); -#elif PLATFORM(CG) +#elif USE(CG) // NativeImagePtr is a CGImageRef on Mac OS X. int width = CGImageGetWidth(nativeImage); int height = CGImageGetHeight(nativeImage); @@ -73,7 +73,7 @@ void PlatformImage::updateFromImage(NativeImagePtr nativeImage) // FIXME: do we need to support more image configurations? ASSERT(skiaBitmap->config()== SkBitmap::kARGB_8888_Config); skiaBitmap->copyPixelsTo(m_pixelData.get(), bufferSize); -#elif PLATFORM(CG) +#elif USE(CG) // FIXME: we should get rid of this temporary copy where possible. int tempRowBytes = width * 4; // Note we do not zero this vector since we are going to diff --git a/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp b/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp index ca42d0b..c93ef3f 100644 --- a/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp @@ -143,7 +143,7 @@ void RenderSurfaceChromium::drawSurface(CCLayerImpl* maskLayer, const Transforma maskLayer->unreserveContentsTexture(); } -void RenderSurfaceChromium::draw() +void RenderSurfaceChromium::draw(const IntRect&) { if (m_skipsDraw || !m_contentsTexture) return; diff --git a/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h b/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h index 6400c63..7c0e984 100644 --- a/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h +++ b/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h @@ -52,7 +52,7 @@ public: bool prepareContentsTexture(); void cleanupResources(); - void draw(); + void draw(const IntRect& targetSurfaceRect); String name() const; void dumpSurface(TextStream&, int indent) const; @@ -84,7 +84,7 @@ private: TransformationMatrix m_replicaDrawTransform; TransformationMatrix m_originTransform; IntRect m_scissorRect; - Vector<CCLayerImpl*> m_layerList; + Vector<RefPtr<CCLayerImpl> > m_layerList; }; } diff --git a/Source/WebCore/platform/graphics/chromium/TransparencyWin.cpp b/Source/WebCore/platform/graphics/chromium/TransparencyWin.cpp index 193271d..f2c2394 100644 --- a/Source/WebCore/platform/graphics/chromium/TransparencyWin.cpp +++ b/Source/WebCore/platform/graphics/chromium/TransparencyWin.cpp @@ -49,14 +49,14 @@ namespace { // into. Buffers larger than this will be destroyed when we're done with them. const int maxCachedBufferPixelSize = 65536; -inline skia::PlatformCanvas* canvasForContext(const GraphicsContext& context) +inline SkCanvas* canvasForContext(const GraphicsContext& context) { return context.platformContext()->canvas(); } inline const SkBitmap& bitmapForContext(const GraphicsContext& context) { - return canvasForContext(context)->getTopPlatformDevice().accessBitmap(false); + return canvasForContext(context)->getTopDevice()->accessBitmap(false); } void compositeToCopy(const GraphicsContext& sourceLayers, @@ -466,7 +466,7 @@ void TransparencyWin::compositeTextComposite() if (!m_validLayer) return; - const SkBitmap& bitmap = m_layerBuffer->context()->platformContext()->canvas()->getTopPlatformDevice().accessBitmap(true); + const SkBitmap& bitmap = m_layerBuffer->context()->platformContext()->canvas()->getTopDevice()->accessBitmap(true); SkColor textColor = m_textCompositeColor.rgb(); for (int y = 0; y < m_layerSize.height(); y++) { uint32_t* row = bitmap.getAddr32(0, y); @@ -502,7 +502,7 @@ void TransparencyWin::makeLayerOpaque() return; SkBitmap& bitmap = const_cast<SkBitmap&>(m_drawContext->platformContext()-> - canvas()->getTopPlatformDevice().accessBitmap(true)); + canvas()->getTopDevice()->accessBitmap(true)); for (int y = 0; y < m_layerSize.height(); y++) { uint32_t* row = bitmap.getAddr32(0, y); for (int x = 0; x < m_layerSize.width(); x++) diff --git a/Source/WebCore/platform/graphics/chromium/UniscribeHelper.cpp b/Source/WebCore/platform/graphics/chromium/UniscribeHelper.cpp index dda84a9..524beec 100644 --- a/Source/WebCore/platform/graphics/chromium/UniscribeHelper.cpp +++ b/Source/WebCore/platform/graphics/chromium/UniscribeHelper.cpp @@ -31,45 +31,16 @@ #include "config.h" #include "UniscribeHelper.h" -#include <windows.h> - +#include "Font.h" #include "FontUtilsChromiumWin.h" #include "PlatformContextSkia.h" #include "SkiaFontWin.h" #include "SkPoint.h" +#include <windows.h> #include <wtf/Assertions.h> namespace WebCore { -// This function is used to see where word spacing should be applied inside -// runs. Note that this must match Font::treatAsSpace so we all agree where -// and how much space this is, so we don't want to do more general Unicode -// "is this a word break" thing. -static bool treatAsSpace(UChar c) -{ - return c == ' ' || c == '\t' || c == '\n' || c == 0x00A0; -} - -// SCRIPT_FONTPROPERTIES contains glyph indices for default, invalid -// and blank glyphs. Just because ScriptShape succeeds does not mean -// that a text run is rendered correctly. Some characters may be rendered -// with default/invalid/blank glyphs. Therefore, we need to check if the glyph -// array returned by ScriptShape contains any of those glyphs to make -// sure that the text run is rendered successfully. -static bool containsMissingGlyphs(WORD *glyphs, - int length, - SCRIPT_FONTPROPERTIES* properties) -{ - for (int i = 0; i < length; ++i) { - if (glyphs[i] == properties->wgDefault - || (glyphs[i] == properties->wgInvalid - && glyphs[i] != properties->wgBlank)) - return true; - } - - return false; -} - // HFONT is the 'incarnation' of 'everything' about font, but it's an opaque // handle and we can't directly query it to make a new HFONT sharing // its characteristics (height, style, etc) except for family name. @@ -102,13 +73,15 @@ UniscribeHelper::UniscribeHelper(const UChar* input, bool isRtl, HFONT hfont, SCRIPT_CACHE* scriptCache, - SCRIPT_FONTPROPERTIES* fontProperties) + SCRIPT_FONTPROPERTIES* fontProperties, + WORD spaceGlyph) : m_input(input) , m_inputLength(inputLength) , m_isRtl(isRtl) , m_hfont(hfont) , m_scriptCache(scriptCache) , m_fontProperties(fontProperties) + , m_spaceGlyph(spaceGlyph) , m_directionalOverride(false) , m_inhibitLigate(false) , m_letterSpacing(0) @@ -546,6 +519,7 @@ bool UniscribeHelper::shape(const UChar* input, SCRIPT_CACHE* scriptCache = m_scriptCache; SCRIPT_FONTPROPERTIES* fontProperties = m_fontProperties; int ascent = m_ascent; + WORD spaceGlyph = m_spaceGlyph; HDC tempDC = 0; HGDIOBJ oldFont = 0; HRESULT hr; @@ -601,7 +575,7 @@ bool UniscribeHelper::shape(const UChar* input, } else if (hr == E_OUTOFMEMORY) { numGlyphs *= 2; continue; - } else if (SUCCEEDED(hr) && (lastFallbackTried || !containsMissingGlyphs(&shaping.m_glyphs[0], generatedGlyphs, fontProperties))) + } else if (SUCCEEDED(hr) && (lastFallbackTried || !containsMissingGlyphs(shaping, run, fontProperties))) break; // The current font can't render this run. clear DC and try @@ -632,7 +606,9 @@ bool UniscribeHelper::shape(const UChar* input, const UChar *family = getFallbackFamily(input, itemLength, FontDescription::StandardFamily, 0, 0); bool fontOk = getDerivedFontData(family, m_style, &m_logfont, - &ascent, &hfont, &scriptCache); + &ascent, &hfont, &scriptCache, + &spaceGlyph); + if (!fontOk) { // If this GetDerivedFontData is called from the renderer it @@ -644,7 +620,8 @@ bool UniscribeHelper::shape(const UChar* input, // Try again. fontOk = getDerivedFontData(family, m_style, &m_logfont, - &ascent, &hfont, &scriptCache); + &ascent, &hfont, &scriptCache, + &spaceGlyph); ASSERT(fontOk); } @@ -673,6 +650,7 @@ bool UniscribeHelper::shape(const UChar* input, // because it's not used elsewhere. shaping.m_hfont = hfont; shaping.m_scriptCache = scriptCache; + shaping.m_spaceGlyph = spaceGlyph; // The ascent of a font for this run can be different from // that of the primary font so that we need to keep track of @@ -806,22 +784,39 @@ void UniscribeHelper::adjustSpaceAdvances() for (size_t run = 0; run < m_runs.size(); run++) { Shaping& shaping = m_shapes[run]; + // FIXME: This loop is not UTF-16-safe. Unicode 6.0 has a couple + // of complex script blocks in Plane 1. for (int i = 0; i < shaping.charLength(); i++) { - if (!treatAsSpace(m_input[m_runs[run].iCharPos + i])) + UChar c = m_input[m_runs[run].iCharPos + i]; + bool treatAsSpace = Font::treatAsSpace(c); + if (!treatAsSpace && !Font::treatAsZeroWidthSpaceInComplexScript(c)) continue; int glyphIndex = shaping.m_logs[i]; int currentAdvance = shaping.m_advance[glyphIndex]; - // currentAdvance does not include additional letter-spacing, but - // space_width does. Here we find out how off we are from the - // correct width for the space not including letter-spacing, then - // just subtract that diff. - int diff = currentAdvance - spaceWidthWithoutLetterSpacing; - // The shaping can consist of a run of text, so only subtract the - // difference in the width of the glyph. - shaping.m_advance[glyphIndex] -= diff; - shaping.m_abc.abcB -= diff; + if (treatAsSpace) { + // currentAdvance does not include additional letter-spacing, + // but m_spaceWidth does. Here we find out how off we are from + // the correct width (spaceWidthWithoutLetterSpacing) and + // just subtract that diff. + int diff = currentAdvance - spaceWidthWithoutLetterSpacing; + // The shaping can consist of a run of text, so only subtract + // the difference in the width of the glyph. + shaping.m_advance[glyphIndex] -= diff; + shaping.m_abc.abcB -= diff; + continue; + } + + // For characters treated as zero-width space in complex + // scripts, set the advance width to zero, adjust + // |abcB| of the current run accordingly and set + // the glyph to m_spaceGlyph (invisible). + shaping.m_advance[glyphIndex] = 0; + shaping.m_abc.abcB -= currentAdvance; + shaping.m_offsets[glyphIndex].du = 0; + shaping.m_offsets[glyphIndex].dv = 0; + shaping.m_glyphs[glyphIndex] = shaping.m_spaceGlyph; } } } @@ -872,7 +867,7 @@ void UniscribeHelper::applySpacing() // extra wordspacing amount for the glyphs they correspond to. if (m_wordSpacing != 0) { for (int i = 0; i < shaping.charLength(); i++) { - if (!treatAsSpace(m_input[m_runs[run].iCharPos + i])) + if (!Font::treatAsSpace(m_input[m_runs[run].iCharPos + i])) continue; // The char in question is a word separator... @@ -929,4 +924,31 @@ int UniscribeHelper::advanceForItem(int itemIndex) const return shaping.m_prePadding + justification; } +// SCRIPT_FONTPROPERTIES contains glyph indices for default, invalid +// and blank glyphs. Just because ScriptShape succeeds does not mean +// that a text run is rendered correctly. Some characters may be rendered +// with default/invalid/blank glyphs. Therefore, we need to check if the glyph +// array returned by ScriptShape contains any of those glyphs to make +// sure that the text run is rendered successfully. +// However, we should not subject zero-width characters to this test. + +bool UniscribeHelper::containsMissingGlyphs(const Shaping& shaping, + const SCRIPT_ITEM& run, + const SCRIPT_FONTPROPERTIES* properties) const +{ + for (int i = 0; i < shaping.charLength(); i++) { + UChar c = m_input[run.iCharPos + i]; + // Skip zero-width space characters because they're not considered to be missing in a font. + if (Font::treatAsZeroWidthSpaceInComplexScript(c)) + continue; + int glyphIndex = shaping.m_logs[i]; + WORD glyph = shaping.m_glyphs[glyphIndex]; + if (glyph == properties->wgDefault + || (glyph == properties->wgInvalid && glyph != properties->wgBlank)) + return true; + } + return false; +} + + } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/chromium/UniscribeHelper.h b/Source/WebCore/platform/graphics/chromium/UniscribeHelper.h index ffd57db..4bcdbd6 100644 --- a/Source/WebCore/platform/graphics/chromium/UniscribeHelper.h +++ b/Source/WebCore/platform/graphics/chromium/UniscribeHelper.h @@ -76,7 +76,8 @@ public: bool isRtl, HFONT, SCRIPT_CACHE*, - SCRIPT_FONTPROPERTIES*); + SCRIPT_FONTPROPERTIES*, + WORD); virtual ~UniscribeHelper(); @@ -225,7 +226,9 @@ private: : m_prePadding(0) , m_hfont(NULL) , m_scriptCache(NULL) - , m_ascentOffset(0) { + , m_ascentOffset(0) + , m_spaceGlyph(0) + { m_abc.abcA = 0; m_abc.abcB = 0; m_abc.abcC = 0; @@ -319,6 +322,8 @@ private: // when drawing a string, to align multiple runs rendered with // different fonts. int m_ascentOffset; + + WORD m_spaceGlyph; }; // Computes the runs_ array from the text run. @@ -343,6 +348,10 @@ private: // Returns the total width of a single item. int advanceForItem(int) const; + bool containsMissingGlyphs(const Shaping&, + const SCRIPT_ITEM&, + const SCRIPT_FONTPROPERTIES*) const; + // Shapes a run (pointed to by |input|) using |hfont| first. // Tries a series of fonts specified retrieved with NextWinFontData // and finally a font covering characters in |*input|. A string pointed @@ -384,6 +393,7 @@ private: int m_ascent; LOGFONT m_logfont; int m_style; + WORD m_spaceGlyph; // Options, see the getters/setters above. bool m_directionalOverride; diff --git a/Source/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp b/Source/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp index c060b43..8e0bc04 100644 --- a/Source/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp +++ b/Source/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp @@ -43,7 +43,8 @@ UniscribeHelperTextRun::UniscribeHelperTextRun(const TextRun& run, : UniscribeHelper(run.characters(), run.length(), run.rtl(), font.primaryFont()->platformData().hfont(), font.primaryFont()->platformData().scriptCache(), - font.primaryFont()->platformData().scriptFontProperties()) + font.primaryFont()->platformData().scriptFontProperties(), + font.primaryFont()->spaceGlyph()) , m_font(&font) , m_fontIndex(0) { @@ -69,7 +70,7 @@ UniscribeHelperTextRun::UniscribeHelperTextRun( SCRIPT_CACHE* scriptCache, SCRIPT_FONTPROPERTIES* fontProperties) : UniscribeHelper(input, inputLength, isRtl, hfont, - scriptCache, fontProperties) + scriptCache, fontProperties, 0) , m_font(0) , m_fontIndex(-1) { diff --git a/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp index 182e730..e75df24 100644 --- a/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp @@ -96,7 +96,7 @@ void VideoLayerChromium::cleanupResources() void VideoLayerChromium::updateCompositorResources() { - if (!m_contentsDirty) + if (!m_contentsDirty || !m_owner) return; RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_owner->client()); diff --git a/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp index 652e752..aef14ed 100644 --- a/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp @@ -51,6 +51,12 @@ WebGLLayerChromium::WebGLLayerChromium(GraphicsLayerChromium* owner) { } +WebGLLayerChromium::~WebGLLayerChromium() +{ + if (m_context && layerRenderer()) + layerRenderer()->removeChildContext(m_context); +} + void WebGLLayerChromium::updateCompositorResources() { if (!m_contentsDirty) @@ -70,6 +76,9 @@ void WebGLLayerChromium::updateCompositorResources() } // Update the contents of the texture used by the compositor. if (m_contentsDirty && m_textureUpdated) { + // prepareTexture copies the contents of the off-screen render target into the texture + // used by the compositor. + // m_context->prepareTexture(); m_context->markLayerComposited(); m_contentsDirty = false; @@ -84,6 +93,13 @@ void WebGLLayerChromium::setTextureUpdated() void WebGLLayerChromium::setContext(const GraphicsContext3D* context) { + if (m_context != context && layerRenderer()) { + if (m_context) + layerRenderer()->removeChildContext(m_context); + if (context) + layerRenderer()->addChildContext(const_cast<GraphicsContext3D*>(context)); + } + m_context = const_cast<GraphicsContext3D*>(context); unsigned int textureId = m_context->platformTexture(); @@ -95,5 +111,19 @@ void WebGLLayerChromium::setContext(const GraphicsContext3D* context) m_premultipliedAlpha = m_context->getContextAttributes().premultipliedAlpha; } +void WebGLLayerChromium::setLayerRenderer(LayerRendererChromium* newLayerRenderer) +{ + if (layerRenderer() != newLayerRenderer) { + if (m_context) { + if (layerRenderer()) + layerRenderer()->removeChildContext(m_context); + if (newLayerRenderer) + newLayerRenderer->addChildContext(m_context); + } + + LayerChromium::setLayerRenderer(newLayerRenderer); + } +} + } #endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.h b/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.h index 33db730..342275b 100644 --- a/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.h @@ -44,12 +44,17 @@ class GraphicsContext3D; class WebGLLayerChromium : public CanvasLayerChromium { public: static PassRefPtr<WebGLLayerChromium> create(GraphicsLayerChromium* owner = 0); + + virtual ~WebGLLayerChromium(); + virtual bool drawsContent() const { return m_context; } virtual void updateCompositorResources(); void setTextureUpdated(); void setContext(const GraphicsContext3D* context); + virtual void setLayerRenderer(LayerRendererChromium*); + protected: virtual const char* layerTypeAsString() const { return "WebGLLayer"; } diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.cpp index 649d049..d70e15c 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.cpp @@ -47,7 +47,7 @@ CCCanvasLayerImpl::~CCCanvasLayerImpl() { } -void CCCanvasLayerImpl::draw() +void CCCanvasLayerImpl::draw(const IntRect&) { ASSERT(layerRenderer()); const CCCanvasLayerImpl::Program* program = layerRenderer()->canvasLayerProgram(); @@ -77,4 +77,3 @@ void CCCanvasLayerImpl::dumpLayerProperties(TextStream& ts, int indent) const } #endif // USE(ACCELERATED_COMPOSITING) - diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.h b/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.h index 8cbf8d1..3aa917c 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.h @@ -42,7 +42,7 @@ public: typedef ProgramBinding<VertexShaderPosTex, FragmentShaderRGBATexFlipAlpha> Program; - virtual void draw(); + virtual void draw(const IntRect&); virtual void dumpLayerProperties(TextStream&, int indent) const; @@ -58,4 +58,3 @@ private: } #endif // CCCanvasLayerImpl_h - diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCCompletionEvent.h b/Source/WebCore/platform/graphics/chromium/cc/CCCompletionEvent.h new file mode 100644 index 0000000..a8ac151 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCCompletionEvent.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CCCompletionEvent_h +#define CCCompletionEvent_h + +#include <wtf/ThreadingPrimitives.h> + +namespace WebCore { + +class CCCompletionEvent { +public: + CCCompletionEvent() + { + m_mutex.lock(); + } + + ~CCCompletionEvent() + { + m_mutex.unlock(); + } + + void wait() + { + m_condition.wait(m_mutex); + } + + void signal() + { + MutexLocker lock(m_mutex); + m_condition.signal(); + } + +private: + Mutex m_mutex; + ThreadCondition m_condition; +}; + +} + +#endif diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp index 404944b..d22b098 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp @@ -44,13 +44,30 @@ namespace WebCore { using namespace std; CCHeadsUpDisplay::CCHeadsUpDisplay(LayerRendererChromium* owner) - : m_currentFrameNumber(0) + : m_currentFrameNumber(1) + , m_filteredFrameTime(0) , m_layerRenderer(owner) , m_showFPSCounter(false) , m_showPlatformLayerTree(false) { m_presentTimeHistoryInSec[0] = currentTime(); m_presentTimeHistoryInSec[1] = m_presentTimeHistoryInSec[0]; + for (int i = 2; i < kPresentHistorySize; i++) + m_presentTimeHistoryInSec[i] = 0; + + FontDescription mediumFontDesc; + mediumFontDesc.setGenericFamily(FontDescription::MonospaceFamily); + mediumFontDesc.setComputedSize(20); + + m_mediumFont = adoptPtr(new Font(mediumFontDesc, 0, 0)); + m_mediumFont->update(0); + + FontDescription smallFontDesc; + smallFontDesc.setGenericFamily(FontDescription::MonospaceFamily); + smallFontDesc.setComputedSize(10); + + m_smallFont = adoptPtr(new Font(smallFontDesc, 0, 0)); + m_smallFont->update(0); } CCHeadsUpDisplay::~CCHeadsUpDisplay() @@ -79,7 +96,7 @@ void CCHeadsUpDisplay::draw() PlatformCanvas canvas; canvas.resize(hudSize); { - PlatformCanvas::Painter painter(&canvas); + PlatformCanvas::Painter painter(&canvas, PlatformCanvas::Painter::GrayscaleText); drawHudContents(painter.context(), hudSize); } @@ -92,7 +109,7 @@ void CCHeadsUpDisplay::draw() } // Draw the HUD onto the default render surface. - const ContentLayerChromium::Program* program = m_layerRenderer->contentLayerProgram(); + const LayerTilerChromium::Program* program = m_layerRenderer->tilerProgram(); ASSERT(program && program->initialized()); GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); m_hudTexture->bindTexture(); @@ -111,59 +128,98 @@ void CCHeadsUpDisplay::draw() void CCHeadsUpDisplay::drawHudContents(GraphicsContext* ctx, const IntSize& hudSize) { - FontDescription mediumFontDesc; - mediumFontDesc.setGenericFamily(FontDescription::MonospaceFamily); - mediumFontDesc.setComputedSize(12); - Font mediumFont(mediumFontDesc, 0, 0); - mediumFont.update(0); - - FontDescription smallFontDesc; - smallFontDesc.setGenericFamily(FontDescription::MonospaceFamily); - smallFontDesc.setComputedSize(10); - Font smallFont(smallFontDesc, 0, 0); - smallFont.update(0); - - // We haven't finished rendering yet, so we don't now the "current" present time. - // So, consider the *last two* present times and use those as our present time. - double secForLastFrame = m_presentTimeHistoryInSec[(m_currentFrameNumber - 1) % 2] - m_presentTimeHistoryInSec[m_currentFrameNumber % 2]; - - int y = 14; - if (m_showPlatformLayerTree) { ctx->setFillColor(Color(0, 0, 0, 192), ColorSpaceDeviceRGB); ctx->fillRect(FloatRect(0, 0, hudSize.width(), hudSize.height())); } - // Draw fps. - String topLine = ""; - if (secForLastFrame > 0 && m_showFPSCounter) { - double fps = 1.0 / secForLastFrame; - topLine += String::format("FPS: %3.1f", fps); - } - if (topLine.length()) { - ctx->setFillColor(Color(0, 0, 0, 255), ColorSpaceDeviceRGB); - TextRun run(topLine); - ctx->fillRect(FloatRect(2, 2, mediumFont.width(run) + 2.0f, 15)); + int fpsCounterHeight = m_mediumFont->fontMetrics().floatHeight() + 2; + int fpsCounterTop = 2; + int platformLayerTreeTop; + if (m_showFPSCounter) + platformLayerTreeTop = fpsCounterTop + fpsCounterHeight + 2; + else + platformLayerTreeTop = 0; + + if (m_showFPSCounter) + drawFPSCounter(ctx, fpsCounterTop, fpsCounterHeight); + + if (m_showPlatformLayerTree) + drawPlatformLayerTree(ctx, platformLayerTreeTop); +} + +void CCHeadsUpDisplay::drawFPSCounter(GraphicsContext* ctx, int top, int height) +{ + // Note that since we haven't finished the current frame, the FPS counter + // actually reports the last frame's time. + double secForLastFrame = m_presentTimeHistoryInSec[(m_currentFrameNumber + kPresentHistorySize - 1) % kPresentHistorySize] - + m_presentTimeHistoryInSec[(m_currentFrameNumber + kPresentHistorySize - 2) % kPresentHistorySize]; + + // Filter the frame times to avoid spikes. + const float alpha = 0.1; + if (!m_filteredFrameTime) { + if (m_currentFrameNumber == 2) + m_filteredFrameTime = secForLastFrame; + } else + m_filteredFrameTime = ((1.0 - alpha) * m_filteredFrameTime) + (alpha * secForLastFrame); + + // Create & measure FPS text. + String text(String::format("FPS: %5.1f", 1.0 / m_filteredFrameTime)); + TextRun run(text); + float textWidth = m_mediumFont->width(run) + 2.0f; + float graphWidth = kPresentHistorySize; + + // Draw background. + ctx->setFillColor(Color(0, 0, 0, 255), ColorSpaceDeviceRGB); + ctx->fillRect(FloatRect(2, top, textWidth + graphWidth, height)); + + // Draw FPS text. + if (m_filteredFrameTime) { ctx->setFillColor(Color(255, 0, 0), ColorSpaceDeviceRGB); - ctx->drawText(mediumFont, run, IntPoint(3, y)); - y = 26; + ctx->drawText(*m_mediumFont, run, IntPoint(3, top + height - 6)); } - // Draw layer tree, if enabled. - if (m_showPlatformLayerTree) { - ctx->setFillColor(Color(255, 0, 0), ColorSpaceDeviceRGB); - Vector<String> lines; - m_layerRenderer->layerTreeAsText().split('\n', lines); - for (size_t i = 0; i < lines.size(); ++i) { - ctx->drawText(smallFont, TextRun(lines[i]), IntPoint(2, y)); - y += 12; - } + // Draw FPS graph. + const double loFPS = 0.0; + const double hiFPS = 120.0; + ctx->setStrokeStyle(SolidStroke); + ctx->setStrokeColor(Color(255, 0, 0), ColorSpaceDeviceRGB); + int graphLeft = static_cast<int>(textWidth + 3); + IntPoint prev(-1, 0); + int x = 0; + double h = static_cast<double>(height - 2); + for (int i = m_currentFrameNumber % kPresentHistorySize; i != (m_currentFrameNumber - 1) % kPresentHistorySize; i = (i + 1) % kPresentHistorySize) { + int j = (i + 1) % kPresentHistorySize; + double fps = 1.0 / (m_presentTimeHistoryInSec[j] - m_presentTimeHistoryInSec[i]); + double p = 1 - ((fps - loFPS) / (hiFPS - loFPS)); + if (p < 0) + p = 0; + if (p > 1) + p = 1; + IntPoint cur(graphLeft + x, 1 + top + p*h); + if (prev.x() != -1) + ctx->drawLine(prev, cur); + prev = cur; + x += 1; + } +} + +void CCHeadsUpDisplay::drawPlatformLayerTree(GraphicsContext* ctx, int top) +{ + float smallFontHeight = m_smallFont->fontMetrics().floatHeight(); + int y = top + smallFontHeight - 4; + ctx->setFillColor(Color(255, 0, 0), ColorSpaceDeviceRGB); + Vector<String> lines; + m_layerRenderer->layerTreeAsText().split('\n', lines); + for (size_t i = 0; i < lines.size(); ++i) { + ctx->drawText(*m_smallFont, TextRun(lines[i]), IntPoint(2, y)); + y += smallFontHeight; } } void CCHeadsUpDisplay::onPresent() { - m_presentTimeHistoryInSec[m_currentFrameNumber % 2] = currentTime(); + m_presentTimeHistoryInSec[m_currentFrameNumber % kPresentHistorySize] = currentTime(); m_currentFrameNumber += 1; } diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.h b/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.h index d56f8ab..09f198a 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.h @@ -27,8 +27,10 @@ #if USE(ACCELERATED_COMPOSITING) +#include "Font.h" #include "LayerRendererChromium.h" + namespace WebCore { class GeometryBinding; @@ -59,17 +61,26 @@ public: private: explicit CCHeadsUpDisplay(LayerRendererChromium* owner); void drawHudContents(GraphicsContext*, const IntSize& hudSize); + void drawFPSCounter(GraphicsContext*, int top, int height); + void drawPlatformLayerTree(GraphicsContext*, int top); + int m_currentFrameNumber; + double m_filteredFrameTime; + OwnPtr<LayerTexture> m_hudTexture; LayerRendererChromium* m_layerRenderer; - double m_presentTimeHistoryInSec[2]; + static const int kPresentHistorySize = 64; + double m_presentTimeHistoryInSec[kPresentHistorySize]; bool m_showFPSCounter; bool m_showPlatformLayerTree; + + OwnPtr<Font> m_smallFont; + OwnPtr<Font> m_mediumFont; }; } diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.cpp index 9411e5a..e2d651d 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.cpp @@ -126,12 +126,12 @@ bool CCLayerImpl::descendantsDrawsContent() // These belong on CCLayerImpl, but should be overridden by each type and not defer to the LayerChromium subtypes. bool CCLayerImpl::drawsContent() const { - return m_owner->drawsContent(); + return m_owner && m_owner->drawsContent(); } -void CCLayerImpl::draw() +void CCLayerImpl::draw(const IntRect& targetSurfaceRect) { - return m_owner->draw(); + return m_owner->draw(targetSurfaceRect); } void CCLayerImpl::updateCompositorResources() @@ -215,4 +215,3 @@ void CCLayerImpl::dumpLayerProperties(TextStream& ts, int indent) const } #endif // USE(ACCELERATED_COMPOSITING) - diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.h b/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.h index 96c4f1b..649f4dd 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.h @@ -50,6 +50,7 @@ public: } // When this class gets subclasses, remember to add 'virtual' here. virtual ~CCLayerImpl(); + void resetOwner() { m_owner = 0; } #ifndef NDEBUG int debugID() const { return m_debugID; } @@ -59,7 +60,7 @@ public: CCLayerImpl* maskLayer() const; CCLayerImpl* replicaLayer() const; - virtual void draw(); + virtual void draw(const IntRect& contentRect); virtual void updateCompositorResources(); void unreserveContentsTexture(); void bindContentsTexture(); @@ -205,4 +206,3 @@ private: } #endif // CCLayerImpl_h - diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCMainThread.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCMainThread.cpp new file mode 100644 index 0000000..cd36817 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCMainThread.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" + +#include "CCMainThread.h" + +#include <wtf/MainThread.h> + +using namespace WTF; + +namespace WebCore { + +void CCMainThread::performTask(void* userdata) +{ + Task* task = static_cast<Task*>(userdata); + task->performTask(); + delete task; +} + +void CCMainThread::postTask(PassOwnPtr<Task> task) +{ + callOnMainThread(performTask, task.leakPtr()); +} + +} diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCMainThread.h b/Source/WebCore/platform/graphics/chromium/cc/CCMainThread.h new file mode 100644 index 0000000..ca8e8c1 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCMainThread.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef CCMainThread_h +#define CCMainThread_h + +#include <wtf/Noncopyable.h> +#include <wtf/PassOwnPtr.h> + +namespace WebCore { + +// Task wrapper around WTF::callOnMainThreadThread +class CCMainThread { +public: + class Task { + WTF_MAKE_NONCOPYABLE(Task); + public: + virtual ~Task() { } + virtual void performTask() = 0; + void* instance() const { return m_instance; } + protected: + Task(void* instance) : m_instance(instance) { } + void* m_instance; + }; + + static void postTask(PassOwnPtr<Task>); // Executes the task on main thread asynchronously. +private: + static void performTask(void*); +}; + +} // namespace WebCore + +#endif // CCMainThread_h diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCMainThreadTask.h b/Source/WebCore/platform/graphics/chromium/cc/CCMainThreadTask.h new file mode 100644 index 0000000..7de8d71 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCMainThreadTask.h @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef CCMainThreadTask_h +#define CCMainThreadTask_h + +#include "CCMainThread.h" +#include "CrossThreadCopier.h" +#include "CrossThreadTask.h" +#include <wtf/PassOwnPtr.h> +#include <wtf/PassRefPtr.h> + +namespace WebCore { + +template<typename T> +class MainThreadTask0 : public CCMainThread::Task { +public: + typedef void (T::*Method)(); + typedef MainThreadTask0<T> MainThreadTaskImpl; + + static PassOwnPtr<MainThreadTaskImpl> create(T* instance, Method method) + { + return adoptPtr(new MainThreadTaskImpl(instance, method)); + } + +private: + MainThreadTask0(T* instance, Method method) + : CCMainThread::Task(instance) + , m_method(method) + { + } + + virtual void performTask() + { + (*static_cast<T*>(instance()).*m_method)(); + } + +private: + Method m_method; +}; + +template<typename T, typename P1, typename MP1> +class MainThreadTask1 : public CCMainThread::Task { +public: + typedef void (T::*Method)(MP1); + typedef MainThreadTask1<T, P1, MP1> MainThreadTaskImpl; + typedef typename CrossThreadTaskTraits<P1>::ParamType Param1; + + static PassOwnPtr<MainThreadTaskImpl> create(T* instance, Method method, Param1 parameter1) + { + return adoptPtr(new MainThreadTaskImpl(instance, method, parameter1)); + } + +private: + MainThreadTask1(T* instance, Method method, Param1 parameter1) + : CCMainThread::Task(instance) + , m_method(method) + , m_parameter1(parameter1) + { + } + + virtual void performTask() + { + (*static_cast<T*>(instance()).*m_method)(m_parameter1); + } + +private: + Method m_method; + P1 m_parameter1; +}; + +template<typename T, typename P1, typename MP1, typename P2, typename MP2> +class MainThreadTask2 : public CCMainThread::Task { +public: + typedef void (T::*Method)(MP1, MP2); + typedef MainThreadTask2<T, P1, MP1, P2, MP2> MainThreadTaskImpl; + typedef typename CrossThreadTaskTraits<P1>::ParamType Param1; + typedef typename CrossThreadTaskTraits<P2>::ParamType Param2; + + static PassOwnPtr<MainThreadTaskImpl> create(T* instance, Method method, Param1 parameter1, Param2 parameter2) + { + return adoptPtr(new MainThreadTaskImpl(instance, method, parameter1, parameter2)); + } + +private: + MainThreadTask2(T* instance, Method method, Param1 parameter1, Param2 parameter2) + : CCMainThread::Task(instance) + , m_method(method) + , m_parameter1(parameter1) + , m_parameter2(parameter2) + { + } + + virtual void performTask() + { + (*static_cast<T*>(instance()).*m_method)(m_parameter1, m_parameter2); + } + +private: + Method m_method; + P1 m_parameter1; + P2 m_parameter2; +}; + +template<typename T, typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3> +class MainThreadTask3 : public CCMainThread::Task { +public: + typedef void (T::*Method)(MP1, MP2, MP3); + typedef MainThreadTask3<T, P1, MP1, P2, MP2, P3, MP3> MainThreadTaskImpl; + typedef typename CrossThreadTaskTraits<P1>::ParamType Param1; + typedef typename CrossThreadTaskTraits<P2>::ParamType Param2; + typedef typename CrossThreadTaskTraits<P3>::ParamType Param3; + + static PassOwnPtr<MainThreadTaskImpl> create(T* instance, Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3) + { + return adoptPtr(new MainThreadTaskImpl(instance, method, parameter1, parameter2, parameter3)); + } + +private: + MainThreadTask3(T* instance, Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3) + : CCMainThread::Task(instance) + , m_method(method) + , m_parameter1(parameter1) + , m_parameter2(parameter2) + , m_parameter3(parameter3) + { + } + + virtual void performTask() + { + (*static_cast<T*>(instance()).*m_method)(m_parameter1, m_parameter2, m_parameter3); + } + +private: + Method m_method; + P1 m_parameter1; + P2 m_parameter2; + P3 m_parameter3; +}; + +template<typename T> +PassOwnPtr<CCMainThread::Task> createMainThreadTask( + T* const callee, + void (T::*method)()); + +template<typename T> +PassOwnPtr<CCMainThread::Task> createMainThreadTask( + T* const callee, + void (T::*method)()) +{ + return MainThreadTask0<T>::create( + callee, + method); +} + +template<typename T, typename P1, typename MP1> +PassOwnPtr<CCMainThread::Task> createMainThreadTask( + T* const callee, + void (T::*method)(MP1), + const P1& parameter1) +{ + return MainThreadTask1<T, typename CrossThreadCopier<P1>::Type, MP1>::create( + callee, + method, + CrossThreadCopier<P1>::copy(parameter1)); +} + +template<typename T, typename P1, typename MP1, typename P2, typename MP2> +PassOwnPtr<CCMainThread::Task> createMainThreadTask( + T* const callee, + void (T::*method)(MP1, MP2), + const P1& parameter1, + const P2& parameter2) +{ + return MainThreadTask2<T, typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2>::create( + callee, + method, + CrossThreadCopier<P1>::copy(parameter1), + CrossThreadCopier<P2>::copy(parameter2)); +} + +template<typename T, typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3> +PassOwnPtr<CCMainThread::Task> createMainThreadTask( + T* const callee, + void (T::*method)(MP1, MP2, MP3), + const P1& parameter1, + const P2& parameter2, + const P3& parameter3) +{ + return MainThreadTask3<T, typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2, typename CrossThreadCopier<P3>::Type, MP3>::create( + callee, + method, + CrossThreadCopier<P1>::copy(parameter1), + CrossThreadCopier<P2>::copy(parameter2), + CrossThreadCopier<P3>::copy(parameter3)); +} + +} // namespace WebCore + +#endif // CCMainThreadTask_h diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.cpp index 4aef639..a428829 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.cpp @@ -46,7 +46,7 @@ CCPluginLayerImpl::~CCPluginLayerImpl() { } -void CCPluginLayerImpl::draw() +void CCPluginLayerImpl::draw(const IntRect&) { ASSERT(layerRenderer()); const CCPluginLayerImpl::Program* program = layerRenderer()->pluginLayerProgram(); @@ -81,4 +81,3 @@ void CCPluginLayerImpl::dumpLayerProperties(TextStream& ts, int indent) const } #endif // USE(ACCELERATED_COMPOSITING) - diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.h b/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.h index 65eb5b7..4fd7457 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.h @@ -42,7 +42,7 @@ public: typedef ProgramBinding<VertexShaderPosTex, FragmentShaderRGBATexFlipAlpha> Program; - virtual void draw(); + virtual void draw(const IntRect&); virtual void dumpLayerProperties(TextStream&, int indent) const; @@ -57,4 +57,3 @@ private: } #endif // CCPluginLayerImpl_h - diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCThread.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCThread.cpp new file mode 100644 index 0000000..9566584 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCThread.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "CCThread.h" + +#include "LayerRendererChromium.h" +#include <wtf/CurrentTime.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/ThreadingPrimitives.h> + +namespace WebCore { + +using namespace WTF; + +CCThread::CCThread() +{ + MutexLocker lock(m_threadCreationMutex); + m_threadID = createThread(CCThread::compositorThreadStart, this, "Chromium Compositor"); +} + +CCThread::~CCThread() +{ + m_queue.kill(); + + // Stop thread. + void* exitCode; + waitForThreadCompletion(m_threadID, &exitCode); + m_threadID = 0; +} + +void CCThread::postTask(PassOwnPtr<Task> task) +{ + m_queue.append(task); +} + +void* CCThread::compositorThreadStart(void* userdata) +{ + CCThread* ccThread = static_cast<CCThread*>(userdata); + return ccThread->runLoop(); +} + +void* CCThread::runLoop() +{ + { + // Wait for CCThread::start() to complete to have m_threadID + // established before starting the main loop. + MutexLocker lock(m_threadCreationMutex); + } + + while (OwnPtr<Task> task = m_queue.waitForMessage()) + task->performTask(); + + return 0; +} + +} diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCThread.h b/Source/WebCore/platform/graphics/chromium/cc/CCThread.h new file mode 100644 index 0000000..177d3f3 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCThread.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CCThread_h +#define CCThread_h + +#include <wtf/MessageQueue.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/Threading.h> + +namespace WebCore { + +// The CCThread singleton owns the compositor thread and provides +// basic infrastructure for messaging between the two threads. +class CCThread { +public: + static PassOwnPtr<CCThread> create() + { + return adoptPtr(new CCThread()); + } + + virtual ~CCThread(); + + class Task { + WTF_MAKE_NONCOPYABLE(Task); + public: + virtual ~Task() { } + virtual void performTask() = 0; + void* instance() const { return m_instance; } + protected: + Task(void* instance) : m_instance(instance) { } + void* m_instance; + }; + + void postTask(PassOwnPtr<Task>); // Executes the task on context's thread asynchronously. + + WTF::ThreadIdentifier threadID() const { return m_threadID; } + +protected: + explicit CCThread(); + + static void* compositorThreadStart(void*); + void* runLoop(); + + WTF::ThreadIdentifier m_threadID; + MessageQueue<Task> m_queue; + + Mutex m_threadCreationMutex; +}; + +} + +#endif diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCThreadTask.h b/Source/WebCore/platform/graphics/chromium/cc/CCThreadTask.h new file mode 100644 index 0000000..71245d3 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCThreadTask.h @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef CCThreadTask_h +#define CCThreadTask_h + +#include "CCThread.h" +#include "CrossThreadCopier.h" +#include "CrossThreadTask.h" +#include <wtf/PassOwnPtr.h> +#include <wtf/PassRefPtr.h> + +namespace WebCore { + +template<typename T> +class CCThreadTask0 : public CCThread::Task { +public: + typedef void (T::*Method)(); + typedef CCThreadTask0<T> CCThreadTaskImpl; + + static PassOwnPtr<CCThreadTaskImpl> create(T* instance, Method method) + { + return adoptPtr(new CCThreadTaskImpl(instance, method)); + } + +private: + CCThreadTask0(T* instance, Method method) + : CCThread::Task(instance) + , m_method(method) + { + } + + virtual void performTask() + { + (*static_cast<T*>(instance()).*m_method)(); + } + +private: + Method m_method; +}; + +template<typename T, typename P1, typename MP1> +class CCThreadTask1 : public CCThread::Task { +public: + typedef void (T::*Method)(MP1); + typedef CCThreadTask1<T, P1, MP1> CCThreadTaskImpl; + typedef typename CrossThreadTaskTraits<P1>::ParamType Param1; + + static PassOwnPtr<CCThreadTaskImpl> create(T* instance, Method method, Param1 parameter1) + { + return adoptPtr(new CCThreadTaskImpl(instance, method, parameter1)); + } + +private: + CCThreadTask1(T* instance, Method method, Param1 parameter1) + : CCThread::Task(instance) + , m_method(method) + , m_parameter1(parameter1) + { + } + + virtual void performTask() + { + (*static_cast<T*>(instance()).*m_method)(m_parameter1); + } + +private: + Method m_method; + P1 m_parameter1; +}; + +template<typename T, typename P1, typename MP1, typename P2, typename MP2> +class CCThreadTask2 : public CCThread::Task { +public: + typedef void (T::*Method)(MP1, MP2); + typedef CCThreadTask2<T, P1, MP1, P2, MP2> CCThreadTaskImpl; + typedef typename CrossThreadTaskTraits<P1>::ParamType Param1; + typedef typename CrossThreadTaskTraits<P2>::ParamType Param2; + + static PassOwnPtr<CCThreadTaskImpl> create(T* instance, Method method, Param1 parameter1, Param2 parameter2) + { + return adoptPtr(new CCThreadTaskImpl(instance, method, parameter1, parameter2)); + } + +private: + CCThreadTask2(T* instance, Method method, Param1 parameter1, Param2 parameter2) + : CCThread::Task(instance) + , m_method(method) + , m_parameter1(parameter1) + , m_parameter2(parameter2) + { + } + + virtual void performTask() + { + (*static_cast<T*>(instance()).*m_method)(m_parameter1, m_parameter2); + } + +private: + Method m_method; + P1 m_parameter1; + P2 m_parameter2; +}; + +template<typename T, typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3> +class CCThreadTask3 : public CCThread::Task { +public: + typedef void (T::*Method)(MP1, MP2, MP3); + typedef CCThreadTask3<T, P1, MP1, P2, MP2, P3, MP3> CCThreadTaskImpl; + typedef typename CrossThreadTaskTraits<P1>::ParamType Param1; + typedef typename CrossThreadTaskTraits<P2>::ParamType Param2; + typedef typename CrossThreadTaskTraits<P3>::ParamType Param3; + + static PassOwnPtr<CCThreadTaskImpl> create(T* instance, Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3) + { + return adoptPtr(new CCThreadTaskImpl(instance, method, parameter1, parameter2, parameter3)); + } + +private: + CCThreadTask3(T* instance, Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3) + : CCThread::Task(instance) + , m_method(method) + , m_parameter1(parameter1) + , m_parameter2(parameter2) + , m_parameter3(parameter3) + { + } + + virtual void performTask() + { + (*static_cast<T*>(instance()).*m_method)(m_parameter1, m_parameter2, m_parameter3); + } + +private: + Method m_method; + P1 m_parameter1; + P2 m_parameter2; + P3 m_parameter3; +}; + + +template<typename T, typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3, typename P4, typename MP4> +class CCThreadTask4 : public CCThread::Task { +public: + typedef void (T::*Method)(MP1, MP2, MP3, MP4); + typedef CCThreadTask4<T, P1, MP1, P2, MP2, P3, MP3, P4, MP4> CCThreadTaskImpl; + typedef typename CrossThreadTaskTraits<P1>::ParamType Param1; + typedef typename CrossThreadTaskTraits<P2>::ParamType Param2; + typedef typename CrossThreadTaskTraits<P3>::ParamType Param3; + typedef typename CrossThreadTaskTraits<P4>::ParamType Param4; + + static PassOwnPtr<CCThreadTaskImpl> create(T* instance, Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3, Param4 parameter4) + { + return adoptPtr(new CCThreadTaskImpl(instance, method, parameter1, parameter2, parameter3, parameter4)); + } + +private: + CCThreadTask4(T* instance, Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3, Param4 parameter4) + : CCThread::Task(instance) + , m_method(method) + , m_parameter1(parameter1) + , m_parameter2(parameter2) + , m_parameter3(parameter3) + , m_parameter4(parameter4) + { + } + + virtual void performTask() + { + (*static_cast<T*>(instance()).*m_method)(m_parameter1, m_parameter2, m_parameter3, m_parameter4); + } + +private: + Method m_method; + P1 m_parameter1; + P2 m_parameter2; + P3 m_parameter3; + P4 m_parameter4; +}; + +template<typename T> +PassOwnPtr<CCThread::Task> createCCThreadTask( + T* const callee, + void (T::*method)()); + +template<typename T> +PassOwnPtr<CCThread::Task> createCCThreadTask( + T* const callee, + void (T::*method)()) +{ + return CCThreadTask0<T>::create( + callee, + method); +} + +template<typename T, typename P1, typename MP1> +PassOwnPtr<CCThread::Task> createCCThreadTask( + T* const callee, + void (T::*method)(MP1), + const P1& parameter1) +{ + return CCThreadTask1<T, typename CrossThreadCopier<P1>::Type, MP1>::create( + callee, + method, + CrossThreadCopier<P1>::copy(parameter1)); +} + +template<typename T, typename P1, typename MP1, typename P2, typename MP2> +PassOwnPtr<CCThread::Task> createCCThreadTask( + T* const callee, + void (T::*method)(MP1, MP2), + const P1& parameter1, + const P2& parameter2) +{ + return CCThreadTask2<T, typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2>::create( + callee, + method, + CrossThreadCopier<P1>::copy(parameter1), + CrossThreadCopier<P2>::copy(parameter2)); +} + +template<typename T, typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3> +PassOwnPtr<CCThread::Task> createCCThreadTask( + T* const callee, + void (T::*method)(MP1, MP2, MP3), + const P1& parameter1, + const P2& parameter2, + const P3& parameter3) +{ + return CCThreadTask3<T, typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2, typename CrossThreadCopier<P3>::Type, MP3>::create( + callee, + method, + CrossThreadCopier<P1>::copy(parameter1), + CrossThreadCopier<P2>::copy(parameter2), + CrossThreadCopier<P3>::copy(parameter3)); +} + +template<typename T, typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3, typename P4, typename MP4> +PassOwnPtr<CCThread::Task> createCCThreadTask( + T* const callee, + void (T::*method)(MP1, MP2, MP3, MP4), + const P1& parameter1, + const P2& parameter2, + const P3& parameter3, + const P4& parameter4) +{ + return CCThreadTask4<T, typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2, typename CrossThreadCopier<P3>::Type, MP3, typename CrossThreadCopier<P4>::Type, MP4>::create( + callee, + method, + CrossThreadCopier<P1>::copy(parameter1), + CrossThreadCopier<P2>::copy(parameter2), + CrossThreadCopier<P3>::copy(parameter3), + CrossThreadCopier<P4>::copy(parameter4)); + +} + +} // namespace WebCore + +#endif // CCThreadTask_h diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.cpp index eb3612b..99a148d 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.cpp @@ -75,7 +75,7 @@ void CCVideoLayerImpl::setTexture(size_t i, VideoLayerChromium::Texture texture) m_textures[i] = texture; } -void CCVideoLayerImpl::draw() +void CCVideoLayerImpl::draw(const IntRect&) { if (m_skipsDraw) return; @@ -170,4 +170,3 @@ void CCVideoLayerImpl::dumpLayerProperties(TextStream& ts, int indent) const } #endif // USE(ACCELERATED_COMPOSITING) - diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.h b/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.h index 62f8778..0e1d1f6 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.h @@ -47,7 +47,7 @@ public: typedef ProgramBinding<VertexShaderPosTexTransform, FragmentShaderRGBATexFlipAlpha> RGBAProgram; typedef ProgramBinding<VertexShaderPosTexYUVStretch, FragmentShaderYUVVideo> YUVProgram; - virtual void draw(); + virtual void draw(const IntRect&); virtual void dumpLayerProperties(TextStream&, int indent) const; @@ -72,4 +72,3 @@ private: } #endif // CCVideoLayerImpl_h - diff --git a/Source/WebCore/platform/graphics/filters/FEFlood.cpp b/Source/WebCore/platform/graphics/filters/FEFlood.cpp index 3c48cf9..d832d2b 100644 --- a/Source/WebCore/platform/graphics/filters/FEFlood.cpp +++ b/Source/WebCore/platform/graphics/filters/FEFlood.cpp @@ -49,9 +49,12 @@ Color FEFlood::floodColor() const return m_floodColor; } -void FEFlood::setFloodColor(const Color& color) +bool FEFlood::setFloodColor(const Color& color) { + if (m_floodColor == color) + return false; m_floodColor = color; + return true; } float FEFlood::floodOpacity() const @@ -59,9 +62,12 @@ float FEFlood::floodOpacity() const return m_floodOpacity; } -void FEFlood::setFloodOpacity(float floodOpacity) +bool FEFlood::setFloodOpacity(float floodOpacity) { + if (m_floodOpacity == floodOpacity) + return false; m_floodOpacity = floodOpacity; + return true; } void FEFlood::apply() diff --git a/Source/WebCore/platform/graphics/filters/FEFlood.h b/Source/WebCore/platform/graphics/filters/FEFlood.h index 2e8824f..cac4153 100644 --- a/Source/WebCore/platform/graphics/filters/FEFlood.h +++ b/Source/WebCore/platform/graphics/filters/FEFlood.h @@ -34,10 +34,10 @@ public: static PassRefPtr<FEFlood> create(Filter* filter, const Color&, float); Color floodColor() const; - void setFloodColor(const Color &); + bool setFloodColor(const Color &); float floodOpacity() const; - void setFloodOpacity(float); + bool setFloodOpacity(float); virtual void apply(); virtual void dump(); diff --git a/Source/WebCore/platform/graphics/filters/FELighting.cpp b/Source/WebCore/platform/graphics/filters/FELighting.cpp index ec1ca88..13a69fd 100644 --- a/Source/WebCore/platform/graphics/filters/FELighting.cpp +++ b/Source/WebCore/platform/graphics/filters/FELighting.cpp @@ -30,6 +30,13 @@ #include "FELighting.h" #include "LightSource.h" +#include "PointLightSource.h" +#include "SpotLightSource.h" + +#if CPU(ARM_NEON) && COMPILER(GCC) +#include "FELightingNEON.h" +#include <wtf/Vector.h> +#endif namespace WebCore { @@ -301,6 +308,9 @@ bool FELighting::drawLighting(ByteArray* pixels, int width, int height) if (width >= 3 && height >= 3) { // Interior pixels +#if CPU(ARM_NEON) && COMPILER(GCC) + drawInteriorPixels(data, paintingData); +#else for (int y = 1; y < data.heightDecreasedByOne; ++y) { offset = y * data.widthMultipliedByPixelSize + cPixelSize; for (int x = 1; x < data.widthDecreasedByOne; ++x, offset += cPixelSize) { @@ -308,6 +318,7 @@ bool FELighting::drawLighting(ByteArray* pixels, int width, int height) inlineSetPixel(offset, data, paintingData, x, y, cFactor1div4, cFactor1div4, normalVector); } } +#endif } int lastPixel = data.widthMultipliedByPixelSize * height; @@ -354,6 +365,118 @@ void FELighting::apply() drawLighting(srcPixelArray, absolutePaintSize.width(), absolutePaintSize.height()); } +#if CPU(ARM_NEON) && COMPILER(GCC) + +static int getPowerCoefficients(float exponent) +{ + // Calling a powf function from the assembly code would require to save + // and reload a lot of NEON registers. Since the base is in range [0..1] + // and only 8 bit precision is required, we use our own powf function. + // This is probably not the best, but it uses only a few registers and + // gives us enough precision (modifying the exponent field directly would + // also be possible). + + // First, we limit the exponent to maximum of 64, which gives us enough + // precision. We split the exponent to an integer and fraction part, + // since a^x = (a^y)*(a^z) where x = y+z. The integer exponent of the + // power is estimated by square, and the fraction exponent of the power + // is estimated by square root assembly instructions. + int i, result; + + if (exponent < 0) + exponent = 1 / (-exponent); + + if (exponent > 63.99) + exponent = 63.99; + + exponent /= 64; + result = 0; + for (i = 11; i >= 0; --i) { + exponent *= 2; + if (exponent >= 1) { + result |= 1 << i; + exponent -= 1; + } + } + return result; +} + +void FELighting::drawInteriorPixels(LightingData& data, LightSource::PaintingData& paintingData) +{ + WTF_ALIGNED(FELightingFloatArgumentsForNeon, floatArguments, 16); + + FELightingPaintingDataForNeon neonData = { + data.pixels->data(), + data.widthDecreasedByOne - 1, + data.heightDecreasedByOne - 1, + 0, + 0, + 0, + &floatArguments, + feLightingConstantsForNeon() + }; + + // Set light source arguments. + floatArguments.constOne = 1; + + floatArguments.colorRed = m_lightingColor.red(); + floatArguments.colorGreen = m_lightingColor.green(); + floatArguments.colorBlue = m_lightingColor.blue(); + floatArguments.padding4 = 0; + + if (m_lightSource->type() == LS_POINT) { + neonData.flags |= FLAG_POINT_LIGHT; + PointLightSource* pointLightSource = static_cast<PointLightSource*>(m_lightSource.get()); + floatArguments.lightX = pointLightSource->position().x(); + floatArguments.lightY = pointLightSource->position().y(); + floatArguments.lightZ = pointLightSource->position().z(); + floatArguments.padding2 = 0; + } else if (m_lightSource->type() == LS_SPOT) { + neonData.flags |= FLAG_SPOT_LIGHT; + SpotLightSource* spotLightSource = static_cast<SpotLightSource*>(m_lightSource.get()); + floatArguments.lightX = spotLightSource->position().x(); + floatArguments.lightY = spotLightSource->position().y(); + floatArguments.lightZ = spotLightSource->position().z(); + floatArguments.padding2 = 0; + + floatArguments.directionX = paintingData.directionVector.x(); + floatArguments.directionY = paintingData.directionVector.y(); + floatArguments.directionZ = paintingData.directionVector.z(); + floatArguments.padding3 = 0; + + floatArguments.coneCutOffLimit = paintingData.coneCutOffLimit; + floatArguments.coneFullLight = paintingData.coneFullLight; + floatArguments.coneCutOffRange = paintingData.coneCutOffLimit - paintingData.coneFullLight; + neonData.coneExponent = getPowerCoefficients(spotLightSource->specularExponent()); + if (spotLightSource->specularExponent() == 1) + neonData.flags |= FLAG_CONE_EXPONENT_IS_1; + } else { + ASSERT(m_lightSource.type == LS_DISTANT); + floatArguments.lightX = paintingData.lightVector.x(); + floatArguments.lightY = paintingData.lightVector.y(); + floatArguments.lightZ = paintingData.lightVector.z(); + floatArguments.padding2 = 1; + } + + // Set lighting arguments. + floatArguments.surfaceScale = data.surfaceScale; + floatArguments.minusSurfaceScaleDividedByFour = -data.surfaceScale / 4; + if (m_lightingType == FELighting::DiffuseLighting) + floatArguments.diffuseConstant = m_diffuseConstant; + else { + neonData.flags |= FLAG_SPECULAR_LIGHT; + floatArguments.diffuseConstant = m_specularConstant; + neonData.specularExponent = getPowerCoefficients(m_specularExponent); + if (m_specularExponent == 1) + neonData.flags |= FLAG_SPECULAR_EXPONENT_IS_1; + } + if (floatArguments.diffuseConstant == 1) + neonData.flags |= FLAG_DIFFUSE_CONST_IS_1; + + neonDrawLighting(&neonData); +} +#endif // CPU(ARM_NEON) && COMPILER(GCC) + } // namespace WebCore #endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/FELighting.h b/Source/WebCore/platform/graphics/filters/FELighting.h index fa1c0aa..3dc46e9 100644 --- a/Source/WebCore/platform/graphics/filters/FELighting.h +++ b/Source/WebCore/platform/graphics/filters/FELighting.h @@ -33,6 +33,7 @@ #include "FilterEffect.h" #include "LightSource.h" #include <wtf/ByteArray.h> +#include <wtf/Platform.h> // Common base class for FEDiffuseLighting and FESpecularLighting @@ -79,6 +80,10 @@ protected: void setPixel(int offset, LightingData&, LightSource::PaintingData&, int lightX, int lightY, float factorX, float factorY, IntPoint& normalVector); +#if CPU(ARM_NEON) && COMPILER(GCC) + void drawInteriorPixels(LightingData&, LightSource::PaintingData&); +#endif + LightingType m_lightingType; RefPtr<LightSource> m_lightSource; diff --git a/Source/WebCore/platform/graphics/filters/FESpecularLighting.cpp b/Source/WebCore/platform/graphics/filters/FESpecularLighting.cpp index a20eb8c..2c7b1eb 100644 --- a/Source/WebCore/platform/graphics/filters/FESpecularLighting.cpp +++ b/Source/WebCore/platform/graphics/filters/FESpecularLighting.cpp @@ -54,9 +54,12 @@ Color FESpecularLighting::lightingColor() const return m_lightingColor; } -void FESpecularLighting::setLightingColor(const Color& lightingColor) +bool FESpecularLighting::setLightingColor(const Color& lightingColor) { + if (m_lightingColor == lightingColor) + return false; m_lightingColor = lightingColor; + return true; } float FESpecularLighting::surfaceScale() const diff --git a/Source/WebCore/platform/graphics/filters/FESpecularLighting.h b/Source/WebCore/platform/graphics/filters/FESpecularLighting.h index 9d3ea2d..9fa3add 100644 --- a/Source/WebCore/platform/graphics/filters/FESpecularLighting.h +++ b/Source/WebCore/platform/graphics/filters/FESpecularLighting.h @@ -34,7 +34,7 @@ public: virtual ~FESpecularLighting(); Color lightingColor() const; - void setLightingColor(const Color&); + bool setLightingColor(const Color&); float surfaceScale() const; bool setSurfaceScale(float); diff --git a/Source/WebCore/platform/graphics/filters/arm/FELightingNEON.cpp b/Source/WebCore/platform/graphics/filters/arm/FELightingNEON.cpp new file mode 100644 index 0000000..3807f1f --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/arm/FELightingNEON.cpp @@ -0,0 +1,464 @@ +/* + * Copyright (C) 2011 University of Szeged + * Copyright (C) 2011 Zoltan Herczeg + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FELightingNEON.h" + +#if CPU(ARM_NEON) && COMPILER(GCC) + +#include <wtf/Vector.h> + +namespace WebCore { + +// These constants are copied to the following SIMD registers: +// ALPHAX_Q ALPHAY_Q REMAPX_D REMAPY_D + +WTF_ALIGNED(short, s_FELightingConstantsForNeon[], 16) = { + // Alpha coefficients. + -2, 1, 0, -1, 2, 1, 0, -1, + 0, -1, -2, -1, 0, 1, 2, 1, + // Remapping indicies. + 0x0f0e, 0x0302, 0x0504, 0x0706, + 0x0b0a, 0x1312, 0x1514, 0x1716, +}; + +short* feLightingConstantsForNeon() +{ + return s_FELightingConstantsForNeon; +} + +#define ASSTRING(str) #str +#define TOSTRING(value) ASSTRING(value) + +#define PIXELS_OFFSET TOSTRING(0) +#define WIDTH_OFFSET TOSTRING(4) +#define HEIGHT_OFFSET TOSTRING(8) +#define FLAGS_OFFSET TOSTRING(12) +#define SPECULAR_EXPONENT_OFFSET TOSTRING(16) +#define CONE_EXPONENT_OFFSET TOSTRING(20) +#define FLOAT_ARGUMENTS_OFFSET TOSTRING(24) +#define DRAWING_CONSTANTS_OFFSET TOSTRING(28) +#define NL "\n" + +// Register allocation +#define PAINTING_DATA_R "r11" +#define RESET_WIDTH_R PAINTING_DATA_R +#define PIXELS_R "r4" +#define WIDTH_R "r5" +#define HEIGHT_R "r6" +#define FLAGS_R "r7" +#define SPECULAR_EXPONENT_R "r8" +#define CONE_EXPONENT_R "r10" +#define SCANLINE_R "r12" + +#define TMP1_Q "q0" +#define TMP1_D0 "d0" +#define TMP1_S0 "s0" +#define TMP1_S1 "s1" +#define TMP1_D1 "d1" +#define TMP1_S2 "s2" +#define TMP1_S3 "s3" +#define TMP2_Q "q1" +#define TMP2_D0 "d2" +#define TMP2_S0 "s4" +#define TMP2_S1 "s5" +#define TMP2_D1 "d3" +#define TMP2_S2 "s6" +#define TMP2_S3 "s7" +#define TMP3_Q "q2" +#define TMP3_D0 "d4" +#define TMP3_S0 "s8" +#define TMP3_S1 "s9" +#define TMP3_D1 "d5" +#define TMP3_S2 "s10" +#define TMP3_S3 "s11" + +#define COSINE_OF_ANGLE "s12" +#define POWF_INT_S "s13" +#define POWF_FRAC_S "s14" +#define SPOT_COLOR_Q "q4" + +// Because of VMIN and VMAX CONST_ZERO_S and CONST_ONE_S +// must be placed on the same side of the double vector + +// Current pixel position +#define POSITION_Q "q5" +#define POSITION_X_S "s20" +#define POSITION_Y_S "s21" +#define POSITION_Z_S "s22" +#define CONST_ZERO_HI_D "d11" +#define CONST_ZERO_S "s23" + +// ------------------------------- +// Variable arguments +// Misc arguments +#define READ1_RANGE "d12-d15" +#define READ2_RANGE "d16-d19" +#define READ3_RANGE "d20-d21" + +#define SCALE_S "s24" +#define SCALE_DIV4_S "s25" +#define DIFFUSE_CONST_S "s26" + +// Light source position +#define CONE_CUT_OFF_S "s28" +#define CONE_FULL_LIGHT_S "s29" +#define CONE_CUT_OFF_RANGE_S "s30" +#define CONST_ONE_HI_D "d15" +#define CONST_ONE_S "s31" + +#define LIGHT_Q "q8" +#define DIRECTION_Q "q9" +#define COLOR_Q "q10" +// ------------------------------- +// Constant coefficients +#define READ4_RANGE "d22-d25" +#define READ5_RANGE "d26-d27" + +#define ALPHAX_Q "q11" +#define ALPHAY_Q "q12" +#define REMAPX_D "d26" +#define REMAPY_D "d27" +// ------------------------------- + +#define ALL_ROWS_D "{d28,d29,d30}" +#define TOP_ROW_D "d28" +#define MIDDLE_ROW_D "d29" +#define BOTTOM_ROW_D "d30" + +#define GET_LENGTH(source, temp) \ + "vmul.f32 " temp##_Q ", " source##_Q ", " source##_Q NL \ + "vadd.f32 " source##_S3 ", " temp##_S0 ", " temp##_S1 NL \ + "vadd.f32 " source##_S3 ", " source##_S3 ", " temp##_S2 NL \ + "vsqrt.f32 " source##_S3 ", " source##_S3 NL + +// destination##_S3 can contain the multiply of length. +#define DOT_PRODUCT(destination, source1, source2) \ + "vmul.f32 " destination##_Q ", " source1##_Q ", " source2##_Q NL \ + "vadd.f32 " destination##_S0 ", " destination##_S0 ", " destination##_S1 NL \ + "vadd.f32 " destination##_S0 ", " destination##_S0 ", " destination##_S2 NL + +#define MULTIPLY_BY_DIFFUSE_CONST(normalVectorLength, dotProductLength) \ + "tst " FLAGS_R ", #" TOSTRING(FLAG_DIFFUSE_CONST_IS_1) NL \ + "vmuleq.f32 " TMP2_S1 ", " DIFFUSE_CONST_S ", " normalVectorLength NL \ + "vdiveq.f32 " TMP2_S1 ", " TMP2_S1 ", " dotProductLength NL \ + "vdivne.f32 " TMP2_S1 ", " normalVectorLength ", " dotProductLength NL + +#define POWF_SQR(value, exponent, current, remaining) \ + "tst " exponent ", #" ASSTRING(current) NL \ + "vmulne.f32 " value ", " value ", " POWF_INT_S NL \ + "tst " exponent ", #" ASSTRING(remaining) NL \ + "vmulne.f32 " POWF_INT_S ", " POWF_INT_S ", " POWF_INT_S NL + +#define POWF_SQRT(value, exponent, current, remaining) \ + "tst " exponent ", #" ASSTRING(remaining) NL \ + "vsqrtne.f32 " POWF_FRAC_S ", " POWF_FRAC_S NL \ + "tst " exponent ", #" ASSTRING(current) NL \ + "vmulne.f32 " value ", " value ", " POWF_FRAC_S NL + +// This simplified powf function is sufficiently accurate. +#define POWF(value, exponent) \ + "tst " exponent ", #0xfc0" NL \ + "vmovne.f32 " POWF_INT_S ", " value NL \ + "tst " exponent ", #0x03f" NL \ + "vmovne.f32 " POWF_FRAC_S ", " value NL \ + "vmov.f32 " value ", " CONST_ONE_S NL \ + \ + POWF_SQR(value, exponent, 0x040, 0xf80) \ + POWF_SQR(value, exponent, 0x080, 0xf00) \ + POWF_SQR(value, exponent, 0x100, 0xe00) \ + POWF_SQR(value, exponent, 0x200, 0xc00) \ + POWF_SQR(value, exponent, 0x400, 0x800) \ + "tst " exponent ", #0x800" NL \ + "vmulne.f32 " value ", " value ", " POWF_INT_S NL \ + \ + POWF_SQRT(value, exponent, 0x20, 0x3f) \ + POWF_SQRT(value, exponent, 0x10, 0x1f) \ + POWF_SQRT(value, exponent, 0x08, 0x0f) \ + POWF_SQRT(value, exponent, 0x04, 0x07) \ + POWF_SQRT(value, exponent, 0x02, 0x03) \ + POWF_SQRT(value, exponent, 0x01, 0x01) + +// The following algorithm is an ARM-NEON optimized version of +// the main loop found in FELighting.cpp. Since the whole code +// is redesigned to be as effective as possible (ARM specific +// thinking), it is four times faster than its C++ counterpart. + +asm ( // NOLINT +".globl " TOSTRING(neonDrawLighting) NL +TOSTRING(neonDrawLighting) ":" NL + // Because of the clever register allocation, nothing is stored on the stack + // except the saved registers. + // Stack must be aligned to 8 bytes. + "stmdb sp!, {r4-r8, r10, r11, lr}" NL + "vstmdb sp!, {d8-d15}" NL + "mov " PAINTING_DATA_R ", r0" NL + + // The following two arguments are loaded to SIMD registers. + "ldr r0, [" PAINTING_DATA_R ", #" FLOAT_ARGUMENTS_OFFSET "]" NL + "ldr r1, [" PAINTING_DATA_R ", #" DRAWING_CONSTANTS_OFFSET "]" NL + "ldr " PIXELS_R ", [" PAINTING_DATA_R ", #" PIXELS_OFFSET "]" NL + "ldr " WIDTH_R ", [" PAINTING_DATA_R ", #" WIDTH_OFFSET "]" NL + "ldr " HEIGHT_R ", [" PAINTING_DATA_R ", #" HEIGHT_OFFSET "]" NL + "ldr " FLAGS_R ", [" PAINTING_DATA_R ", #" FLAGS_OFFSET "]" NL + "ldr " SPECULAR_EXPONENT_R ", [" PAINTING_DATA_R ", #" SPECULAR_EXPONENT_OFFSET "]" NL + "ldr " CONE_EXPONENT_R ", [" PAINTING_DATA_R ", #" CONE_EXPONENT_OFFSET "]" NL + + // Load all data to the SIMD registers with the least number of instructions. + "vld1.f32 { " READ1_RANGE " }, [r0]!" NL + "vld1.f32 { " READ2_RANGE " }, [r0]!" NL + "vld1.f32 { " READ3_RANGE " }, [r0]!" NL + "vld1.s16 {" READ4_RANGE "}, [r1]!" NL + "vld1.s16 {" READ5_RANGE "}, [r1]!" NL + + // Initializing local variables. + "mov " SCANLINE_R ", " WIDTH_R ", lsl #2" NL + "add " SCANLINE_R ", " SCANLINE_R ", #8" NL + "add " PIXELS_R ", " PIXELS_R ", " SCANLINE_R NL + "add " PIXELS_R ", " PIXELS_R ", #3" NL + "mov r0, #0" NL + "vmov.f32 " CONST_ZERO_S ", r0" NL + "vmov.f32 " POSITION_Y_S ", " CONST_ONE_S NL + "tst " FLAGS_R ", #" TOSTRING(FLAG_SPOT_LIGHT) NL + "vmov.f32 " SPOT_COLOR_Q ", " COLOR_Q NL + "mov " RESET_WIDTH_R ", " WIDTH_R NL + +".mainloop:" NL + "mov r3, #3" NL + "vmov.f32 " POSITION_X_S ", " CONST_ONE_S NL + +".scanline:" NL + // The ROW registers are storing the alpha channel of the last three pixels. + // The alpha channel is stored as signed short (sint16) values. The fourth value + // is garbage. The following instructions are shifting out the unnecessary alpha + // values and load the next ones. + "ldrb r0, [" PIXELS_R ", -" SCANLINE_R "]" NL + "ldrb r1, [" PIXELS_R ", +" SCANLINE_R "]" NL + "ldrb r2, [" PIXELS_R "], #4" NL + "vext.s16 " TOP_ROW_D ", " TOP_ROW_D ", " TOP_ROW_D ", #3" NL + "vext.s16 " MIDDLE_ROW_D ", " MIDDLE_ROW_D ", " MIDDLE_ROW_D ", #3" NL + "vext.s16 " BOTTOM_ROW_D ", " BOTTOM_ROW_D ", " BOTTOM_ROW_D ", #3" NL + "vmov.s16 " TOP_ROW_D "[1], r0" NL + "vmov.s16 " MIDDLE_ROW_D "[1], r2" NL + "vmov.s16 " BOTTOM_ROW_D "[1], r1" NL + + // The two border pixels (rightmost and leftmost) are skipped when + // the next scanline is reached. It also jumps, when the algorithm + // is started, and the first free alpha values are loaded to each row. + "subs r3, r3, #1" NL + "bne .scanline" NL + + // The light vector goes to TMP1_Q. It is constant in case of distant light. + // The fourth value contains the length of the light vector. + "tst " FLAGS_R ", #" TOSTRING(FLAG_POINT_LIGHT | FLAG_SPOT_LIGHT) NL + "beq .distantLight" NL + + "vmov.s16 r3, " MIDDLE_ROW_D "[2]" NL + "vmov.f32 " POSITION_Z_S ", r3" NL + "vcvt.f32.s32 " POSITION_Z_S ", " POSITION_Z_S NL + "vmul.f32 " POSITION_Z_S ", " POSITION_Z_S ", " SCALE_S NL + + "vsub.f32 " TMP1_Q ", " LIGHT_Q ", " POSITION_Q NL + GET_LENGTH(TMP1, TMP2) + + "tst " FLAGS_R ", #" TOSTRING(FLAG_SPOT_LIGHT) NL + "bne .cosineOfAngle" NL +".visiblePixel:" NL + + // | -1 0 1 | | -1 -2 -1 | + // X = | -2 0 2 | Y = | 0 0 0 | + // | -1 0 1 | | 1 2 1 | + + // Multiply the alpha values by the X and Y matrices. + + // Moving the 8 alpha value to TMP3. + "vtbl.8 " TMP3_D0 ", " ALL_ROWS_D ", " REMAPX_D NL + "vtbl.8 " TMP3_D1 ", " ALL_ROWS_D ", " REMAPY_D NL + + "vmul.s16 " TMP2_Q ", " TMP3_Q ", " ALPHAX_Q NL + "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D1 NL + "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D0 NL + "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D0 NL + "vmov.s16 r0, " TMP2_D0 "[0]" NL + + "vmul.s16 " TMP2_Q ", " TMP3_Q ", " ALPHAY_Q NL + "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D1 NL + "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D0 NL + "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D0 NL + "vmov.s16 r1, " TMP2_D0 "[0]" NL + + // r0 and r1 contains the X and Y coordinates of the + // normal vector, respectively. + + // Calculating the spot light strength. + "tst " FLAGS_R ", #" TOSTRING(FLAG_SPOT_LIGHT) NL + "beq .endLight" NL + + "vneg.f32 " TMP3_S1 ", " COSINE_OF_ANGLE NL + "tst " FLAGS_R ", #" TOSTRING(FLAG_CONE_EXPONENT_IS_1) NL + "beq .coneExpPowf" NL +".coneExpPowfFinished:" NL + + // Smoothing the cone edge if necessary. + "vcmp.f32 " COSINE_OF_ANGLE ", " CONE_FULL_LIGHT_S NL + "fmstat" NL + "bhi .cutOff" NL +".cutOffFinished:" NL + + "vmin.f32 " TMP3_D0 ", " TMP3_D0 ", " CONST_ONE_HI_D NL + "vmul.f32 " COLOR_Q ", " SPOT_COLOR_Q ", " TMP3_D0 "[1]" NL + +".endLight:" NL + // Summarize: + // r0 and r1 contains the normalVector. + // TMP1_Q contains the light vector and its length. + // COLOR_Q contains the color of the light vector. + + // Test whether both r0 and r1 are zero (Normal vector is (0, 0, 1)). + "orrs r2, r0, r1" NL + "bne .normalVectorIsNonZero" NL + + "tst " FLAGS_R ", #" TOSTRING(FLAG_SPECULAR_LIGHT) NL + "bne .specularLight1" NL + + // Calculate diffuse light strength. + MULTIPLY_BY_DIFFUSE_CONST(TMP1_S2, TMP1_S3) + "b .lightStrengthCalculated" NL + +".specularLight1:" NL + // Calculating specular light strength. + "vadd.f32 " TMP1_S2 ", " TMP1_S2 ", " TMP1_S3 NL + GET_LENGTH(TMP1, TMP2) + + // When the exponent is 1, we don't need to call an expensive powf function. + "tst " FLAGS_R ", #" TOSTRING(FLAG_SPECULAR_EXPONENT_IS_1) NL + "vdiveq.f32 " TMP2_S1 ", " TMP1_S2 ", " TMP1_S3 NL + "beq .specularExpPowf" NL + + MULTIPLY_BY_DIFFUSE_CONST(TMP1_S2, TMP1_S3) + "b .lightStrengthCalculated" NL + +".normalVectorIsNonZero:" NL + // Normal vector goes to TMP2, and its length is calculated as well. + "vmov.s32 " TMP2_S0 ", r0" NL + "vcvt.f32.s32 " TMP2_S0 ", " TMP2_S0 NL + "vmul.f32 " TMP2_S0 ", " TMP2_S0 ", " SCALE_DIV4_S NL + "vmov.s32 " TMP2_S1 ", r1" NL + "vcvt.f32.s32 " TMP2_S1 ", " TMP2_S1 NL + "vmul.f32 " TMP2_S1 ", " TMP2_S1 ", " SCALE_DIV4_S NL + "vmov.f32 " TMP2_S2 ", " CONST_ONE_S NL + GET_LENGTH(TMP2, TMP3) + + "tst " FLAGS_R ", #" TOSTRING(FLAG_SPECULAR_LIGHT) NL + "bne .specularLight2" NL + + // Calculating diffuse light strength. + DOT_PRODUCT(TMP3, TMP2, TMP1) + MULTIPLY_BY_DIFFUSE_CONST(TMP3_S0, TMP3_S3) + "b .lightStrengthCalculated" NL + +".specularLight2:" NL + // Calculating specular light strength. + "vadd.f32 " TMP1_S2 ", " TMP1_S2 ", " TMP1_S3 NL + GET_LENGTH(TMP1, TMP3) + DOT_PRODUCT(TMP3, TMP2, TMP1) + + // When the exponent is 1, we don't need to call an expensive powf function. + "tst " FLAGS_R ", #" TOSTRING(FLAG_SPECULAR_EXPONENT_IS_1) NL + "vdiveq.f32 " TMP2_S1 ", " TMP3_S0 ", " TMP3_S3 NL + "beq .specularExpPowf" NL + MULTIPLY_BY_DIFFUSE_CONST(TMP3_S0, TMP3_S3) + +".lightStrengthCalculated:" NL + // TMP2_S1 contains the light strength. Clamp it to [0, 1] + "vmax.f32 " TMP2_D0 ", " TMP2_D0 ", " CONST_ZERO_HI_D NL + "vmin.f32 " TMP2_D0 ", " TMP2_D0 ", " CONST_ONE_HI_D NL + "vmul.f32 " TMP3_Q ", " COLOR_Q ", " TMP2_D0 "[1]" NL + "vcvt.u32.f32 " TMP3_Q ", " TMP3_Q NL + "vmov.u32 r2, r3, " TMP3_S0 ", " TMP3_S1 NL + // The color values are stored in-place. + "strb r2, [" PIXELS_R ", #-11]" NL + "strb r3, [" PIXELS_R ", #-10]" NL + "vmov.u32 r2, " TMP3_S2 NL + "strb r2, [" PIXELS_R ", #-9]" NL + + // Continue to the next pixel. +".blackPixel:" NL + "vadd.f32 " POSITION_X_S ", " CONST_ONE_S NL + "mov r3, #1" NL + "subs " WIDTH_R ", " WIDTH_R ", #1" NL + "bne .scanline" NL + + // If the end of the scanline is reached, we continue + // to the next scanline. + "vadd.f32 " POSITION_Y_S ", " CONST_ONE_S NL + "mov " WIDTH_R ", " RESET_WIDTH_R NL + "subs " HEIGHT_R ", " HEIGHT_R ", #1" NL + "bne .mainloop" NL + + // Return. + "vldmia sp!, {d8-d15}" NL + "ldmia sp!, {r4-r8, r10, r11, pc}" NL + +".distantLight:" NL + // In case of distant light, the light vector is constant, + // we simply copy it. + "vmov.f32 " TMP1_Q ", " LIGHT_Q NL + "b .visiblePixel" NL + +".cosineOfAngle:" NL + // If the pixel is outside of the cone angle, it is simply a black pixel. + DOT_PRODUCT(TMP3, TMP1, DIRECTION) + "vdiv.f32 " COSINE_OF_ANGLE ", " TMP3_S0 ", " TMP1_S3 NL + "vcmp.f32 " COSINE_OF_ANGLE ", " CONE_CUT_OFF_S NL + "fmstat" NL + "bls .visiblePixel" NL + "mov r0, #0" NL + "strh r0, [" PIXELS_R ", #-11]" NL + "strb r0, [" PIXELS_R ", #-9]" NL + "b .blackPixel" NL + +".cutOff:" NL + // Smoothing the light strength on the cone edge. + "vsub.f32 " TMP3_S0 ", " CONE_CUT_OFF_S ", " COSINE_OF_ANGLE NL + "vdiv.f32 " TMP3_S0 ", " TMP3_S0 ", " CONE_CUT_OFF_RANGE_S NL + "vmul.f32 " TMP3_S1 ", " TMP3_S1 ", " TMP3_S0 NL + "b .cutOffFinished" NL + +".coneExpPowf:" NL + POWF(TMP3_S1, CONE_EXPONENT_R) + "b .coneExpPowfFinished" NL + +".specularExpPowf:" NL + POWF(TMP2_S1, SPECULAR_EXPONENT_R) + "tst " FLAGS_R ", #" TOSTRING(FLAG_DIFFUSE_CONST_IS_1) NL + "vmuleq.f32 " TMP2_S1 ", " TMP2_S1 ", " DIFFUSE_CONST_S NL + "b .lightStrengthCalculated" NL +); // NOLINT + +} // namespace WebCore + +#endif // CPU(ARM_NEON) && COMPILER(GCC) diff --git a/Source/WebCore/platform/graphics/filters/arm/FELightingNEON.h b/Source/WebCore/platform/graphics/filters/arm/FELightingNEON.h new file mode 100644 index 0000000..d83b7fe --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/arm/FELightingNEON.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2011 University of Szeged + * Copyright (C) 2011 Zoltan Herczeg + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FELightingNeon_h +#define FELightingNeon_h + +#include <wtf/Platform.h> + +#if CPU(ARM_NEON) && COMPILER(GCC) + +namespace WebCore { + +// Otherwise: Distant Light. +#define FLAG_POINT_LIGHT 0x01 +#define FLAG_SPOT_LIGHT 0x02 +#define FLAG_CONE_EXPONENT_IS_1 0x04 + +// Otherwise: Diffuse light. +#define FLAG_SPECULAR_LIGHT 0x10 +#define FLAG_DIFFUSE_CONST_IS_1 0x20 +#define FLAG_SPECULAR_EXPONENT_IS_1 0x40 + +// Must be aligned to 16 bytes. +struct FELightingFloatArgumentsForNeon { + float surfaceScale; + float minusSurfaceScaleDividedByFour; + float diffuseConstant; + float padding1; + + float coneCutOffLimit; + float coneFullLight; + float coneCutOffRange; + float constOne; + + float lightX; + float lightY; + float lightZ; + float padding2; + + float directionX; + float directionY; + float directionZ; + float padding3; + + float colorRed; + float colorGreen; + float colorBlue; + float padding4; +}; + +struct FELightingPaintingDataForNeon { + unsigned char* pixels; + int widthDecreasedByTwo; + int heightDecreasedByTwo; + // Combination of FLAG constants above. + int flags; + int specularExponent; + int coneExponent; + FELightingFloatArgumentsForNeon* floatArguments; + short* paintingConstants; +}; + +short* feLightingConstantsForNeon(); + +extern "C" { +void neonDrawLighting(FELightingPaintingDataForNeon*); +} + +} // namespace WebCore + +#endif // CPU(ARM_NEON) && COMPILER(GCC) + +#endif // FELightingNeon_h diff --git a/Source/WebCore/platform/graphics/gpu/BicubicShader.cpp b/Source/WebCore/platform/graphics/gpu/BicubicShader.cpp index 40c9843..f6f428d 100644 --- a/Source/WebCore/platform/graphics/gpu/BicubicShader.cpp +++ b/Source/WebCore/platform/graphics/gpu/BicubicShader.cpp @@ -55,11 +55,12 @@ PassOwnPtr<BicubicShader> BicubicShader::create(GraphicsContext3D* context) static const char* vertexShaderSource = "uniform mat3 matrix;\n" "uniform mat3 texMatrix;\n" - "attribute vec3 position;\n" + "attribute vec2 position;\n" "varying vec2 texCoord;\n" "void main() {\n" - " texCoord = (texMatrix * position).xy;\n" - " gl_Position = vec4(matrix * position, 1.0);\n" + " vec3 pos = vec3(position, 1.0);\n" + " texCoord = (texMatrix * pos).xy;\n" + " gl_Position = vec4(matrix * pos, 1.0);\n" "}\n"; static const char* fragmentShaderSource = "#ifdef GL_ES\n" @@ -127,7 +128,7 @@ void BicubicShader::use(const AffineTransform& transform, const AffineTransform& m_context->uniform1i(m_imageLocation, 0); m_context->uniform1f(m_alphaLocation, alpha); - m_context->vertexAttribPointer(m_positionLocation, 3, GraphicsContext3D::FLOAT, false, 0, 0); + m_context->vertexAttribPointer(m_positionLocation, 2, GraphicsContext3D::FLOAT, false, 0, 0); m_context->enableVertexAttribArray(m_positionLocation); } diff --git a/Source/WebCore/platform/graphics/gpu/ConvolutionShader.cpp b/Source/WebCore/platform/graphics/gpu/ConvolutionShader.cpp index f0b6bd9..b11d966 100644 --- a/Source/WebCore/platform/graphics/gpu/ConvolutionShader.cpp +++ b/Source/WebCore/platform/graphics/gpu/ConvolutionShader.cpp @@ -58,13 +58,14 @@ PassOwnPtr<ConvolutionShader> ConvolutionShader::create(GraphicsContext3D* conte "uniform mat3 matrix;\n" "uniform mat3 texMatrix;\n" "uniform vec2 imageIncrement;\n" - "attribute vec3 position;\n" + "attribute vec2 position;\n" "varying vec2 imageCoord;\n" "void main() {\n" + " vec3 pos = vec3(position, 1.0);\n" " // Offset image coords by half of kernel width, in image texels\n" - " gl_Position = vec4(matrix * position, 1.0);\n" + " gl_Position = vec4(matrix * pos, 1.0);\n" " float scale = (float(KERNEL_WIDTH) - 1.0) / 2.0;\n" - " imageCoord = (texMatrix * position).xy - vec2(scale, scale) * imageIncrement;\n" + " imageCoord = (texMatrix * pos).xy - vec2(scale, scale) * imageIncrement;\n" "}\n"; char vertexShaderSource[1024]; snprintf(vertexShaderSource, sizeof(vertexShaderSource), vertexShaderRaw, kernelWidth); @@ -115,7 +116,7 @@ void ConvolutionShader::use(const AffineTransform& transform, const AffineTransf kernelWidth = m_kernelWidth; m_context->uniform1fv(m_kernelLocation, const_cast<float*>(kernel), kernelWidth); - m_context->vertexAttribPointer(m_positionLocation, 3, GraphicsContext3D::FLOAT, false, 0, 0); + m_context->vertexAttribPointer(m_positionLocation, 2, GraphicsContext3D::FLOAT, false, 0, 0); m_context->enableVertexAttribArray(m_positionLocation); } diff --git a/Source/WebCore/platform/graphics/gpu/DrawingBuffer.cpp b/Source/WebCore/platform/graphics/gpu/DrawingBuffer.cpp index 2a83fcf..8e293f7 100644 --- a/Source/WebCore/platform/graphics/gpu/DrawingBuffer.cpp +++ b/Source/WebCore/platform/graphics/gpu/DrawingBuffer.cpp @@ -144,112 +144,128 @@ void DrawingBuffer::resizeDepthStencil(int sampleCount) m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0); } -void DrawingBuffer::reset(const IntSize& newSize) +void DrawingBuffer::clearFramebuffer() { - m_size = newSize; + m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO ? m_multisampleFBO : m_fbo); + const GraphicsContext3D::Attributes& attributes = m_context->getContextAttributes(); + float clearDepth = 0; + int clearStencil = 0; + unsigned char depthMask = false; + unsigned int stencilMask = 0xffffffff; + unsigned char isScissorEnabled = false; + unsigned long clearMask = GraphicsContext3D::COLOR_BUFFER_BIT; + if (attributes.depth) { + m_context->getFloatv(GraphicsContext3D::DEPTH_CLEAR_VALUE, &clearDepth); + m_context->clearDepth(1); + m_context->getBooleanv(GraphicsContext3D::DEPTH_WRITEMASK, &depthMask); + m_context->depthMask(true); + clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT; + } + if (attributes.stencil) { + m_context->getIntegerv(GraphicsContext3D::STENCIL_CLEAR_VALUE, &clearStencil); + m_context->clearStencil(0); + m_context->getIntegerv(GraphicsContext3D::STENCIL_WRITEMASK, reinterpret_cast<int*>(&stencilMask)); + m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, 0xffffffff); + clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT; + } + isScissorEnabled = m_context->isEnabled(GraphicsContext3D::SCISSOR_TEST); + m_context->disable(GraphicsContext3D::SCISSOR_TEST); + + float clearColor[4]; + m_context->getFloatv(GraphicsContext3D::COLOR_CLEAR_VALUE, clearColor); + m_context->clearColor(0, 0, 0, 0); + m_context->clear(clearMask); + m_context->clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); + + if (attributes.depth) { + m_context->clearDepth(clearDepth); + m_context->depthMask(depthMask); + } + if (attributes.stencil) { + m_context->clearStencil(clearStencil); + m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, stencilMask); + } + if (isScissorEnabled) + m_context->enable(GraphicsContext3D::SCISSOR_TEST); + else + m_context->disable(GraphicsContext3D::SCISSOR_TEST); +} +bool DrawingBuffer::reset(const IntSize& newSize) +{ if (!m_context) - return; - + return false; + m_context->makeContextCurrent(); - - const GraphicsContext3D::Attributes& attributes = m_context->getContextAttributes(); - unsigned long internalColorFormat, colorFormat, internalRenderbufferFormat; - if (attributes.alpha) { - internalColorFormat = GraphicsContext3D::RGBA; - colorFormat = GraphicsContext3D::RGBA; - internalRenderbufferFormat = Extensions3D::RGBA8_OES; - } else { - internalColorFormat = GraphicsContext3D::RGB; - colorFormat = GraphicsContext3D::RGB; - internalRenderbufferFormat = Extensions3D::RGB8_OES; - } + int maxTextureSize = 0; + m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &maxTextureSize); + if (newSize.height() > maxTextureSize || newSize.width() > maxTextureSize) { + clear(); + return false; + } - // resize multisample FBO - if (multisample()) { - int maxSampleCount = 0; - - m_context->getIntegerv(Extensions3D::MAX_SAMPLES, &maxSampleCount); - int sampleCount = std::min(8, maxSampleCount); + const GraphicsContext3D::Attributes& attributes = m_context->getContextAttributes(); - m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO); + if (newSize != m_size) { + m_size = newSize; - m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_multisampleColorBuffer); - m_context->getExtensions()->renderbufferStorageMultisample(GraphicsContext3D::RENDERBUFFER, sampleCount, internalRenderbufferFormat, m_size.width(), m_size.height()); - m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::RENDERBUFFER, m_multisampleColorBuffer); - resizeDepthStencil(sampleCount); - if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) { - // Cleanup - clear(); - return; + unsigned long internalColorFormat, colorFormat, internalRenderbufferFormat; + if (attributes.alpha) { + internalColorFormat = GraphicsContext3D::RGBA; + colorFormat = GraphicsContext3D::RGBA; + internalRenderbufferFormat = Extensions3D::RGBA8_OES; + } else { + internalColorFormat = GraphicsContext3D::RGB; + colorFormat = GraphicsContext3D::RGB; + internalRenderbufferFormat = Extensions3D::RGB8_OES; } - } - // resize regular FBO - m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo); - m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_colorBuffer); - m_context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, internalColorFormat, m_size.width(), m_size.height(), 0, colorFormat, GraphicsContext3D::UNSIGNED_BYTE); - m_context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_colorBuffer, 0); - m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0); - if (!multisample()) - resizeDepthStencil(0); - if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) { - // Cleanup - clear(); - return; - } + // resize multisample FBO + if (multisample()) { + int maxSampleCount = 0; + + m_context->getIntegerv(Extensions3D::MAX_SAMPLES, &maxSampleCount); + int sampleCount = std::min(8, maxSampleCount); - if (multisample()) - m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO); + m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO); - if (!m_context->getExtensions()->supports("GL_CHROMIUM_resource_safe")) { - // Initialize renderbuffers (depth/stencil). - float clearDepth = 0; - int clearStencil = 0; - unsigned char depthMask = true; - unsigned int stencilMask = 0xffffffff; - unsigned char isScissorEnabled = false; - unsigned long clearMask = 0; - if (attributes.depth) { - m_context->getFloatv(GraphicsContext3D::DEPTH_CLEAR_VALUE, &clearDepth); - m_context->clearDepth(1); - m_context->getBooleanv(GraphicsContext3D::DEPTH_WRITEMASK, &depthMask); - m_context->depthMask(true); - clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT; - } - if (attributes.stencil) { - m_context->getIntegerv(GraphicsContext3D::STENCIL_CLEAR_VALUE, &clearStencil); - m_context->clearStencil(0); - m_context->getIntegerv(GraphicsContext3D::STENCIL_WRITEMASK, reinterpret_cast<int*>(&stencilMask)); - m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, 0xffffffff); - clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT; + m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_multisampleColorBuffer); + m_context->getExtensions()->renderbufferStorageMultisample(GraphicsContext3D::RENDERBUFFER, sampleCount, internalRenderbufferFormat, m_size.width(), m_size.height()); + m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::RENDERBUFFER, m_multisampleColorBuffer); + resizeDepthStencil(sampleCount); + if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) { + // Cleanup + clear(); + return false; + } } - if (clearMask) { - isScissorEnabled = m_context->isEnabled(GraphicsContext3D::SCISSOR_TEST); - m_context->disable(GraphicsContext3D::SCISSOR_TEST); - m_context->clear(clearMask); + // resize regular FBO + m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo); - if (attributes.depth) { - m_context->clearDepth(clearDepth); - m_context->depthMask(depthMask); - } - if (attributes.stencil) { - m_context->clearStencil(clearStencil); - m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, stencilMask); - } - if (isScissorEnabled) - m_context->enable(GraphicsContext3D::SCISSOR_TEST); - else - m_context->disable(GraphicsContext3D::SCISSOR_TEST); + m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_colorBuffer); + + m_context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, internalColorFormat, m_size.width(), m_size.height(), 0, colorFormat, GraphicsContext3D::UNSIGNED_BYTE); + + m_context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_colorBuffer, 0); + m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0); + + if (!multisample()) + resizeDepthStencil(0); + if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) { + // Cleanup + clear(); + return false; } } - m_context->flush(); - + clearFramebuffer(); + didReset(); + + return true; } void DrawingBuffer::commit(long x, long y, long width, long height) diff --git a/Source/WebCore/platform/graphics/gpu/DrawingBuffer.h b/Source/WebCore/platform/graphics/gpu/DrawingBuffer.h index 606484e..caf3aa5 100644 --- a/Source/WebCore/platform/graphics/gpu/DrawingBuffer.h +++ b/Source/WebCore/platform/graphics/gpu/DrawingBuffer.h @@ -44,6 +44,7 @@ #if ENABLE(SKIA_GPU) class GrContext; +struct GrPlatformSurfaceDesc; #endif namespace WebCore { @@ -60,7 +61,10 @@ public: ~DrawingBuffer(); - void reset(const IntSize&); + void clearFramebuffer(); + + // Returns true if the buffer was successfully resized. + bool reset(const IntSize&); void bind(); IntSize size() const { return m_size; } Platform3DObject colorBuffer() const { return m_colorBuffer; } @@ -101,6 +105,7 @@ public: #if ENABLE(SKIA_GPU) void setGrContext(GrContext* ctx); + void getGrPlatformSurfaceDesc(GrPlatformSurfaceDesc*); #endif PassRefPtr<GraphicsContext3D> graphicsContext3D() const { return m_context; } diff --git a/Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp b/Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp index 5b155a5..b228cbf 100644 --- a/Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp +++ b/Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp @@ -562,6 +562,108 @@ int numXRayCrossingsForCubic(const XRay& xRay, const FloatPoint cubic[4], bool& return numCrossings; } +/* + * Based on C code from the article + * "Testing the Convexity of a Polygon" + * by Peter Schorn and Frederick Fisher, + * (schorn@inf.ethz.ch, fred@kpc.com) + * in "Graphics Gems IV", Academic Press, 1994 + */ + +static inline int convexCompare(const FloatSize& delta) +{ + return (delta.width() > 0) ? -1 : /* x coord diff, second pt > first pt */ + (delta.width() < 0) ? 1 : /* x coord diff, second pt < first pt */ + (delta.height() > 0) ? -1 : /* x coord same, second pt > first pt */ + (delta.height() < 0) ? 1 : /* x coord same, second pt > first pt */ + 0; /* second pt equals first point */ +} + +static inline float convexCross(const FloatSize& p, const FloatSize& q) +{ + return p.width() * q.height() - p.height() * q.width(); +} + +static inline bool convexCheckTriple(const FloatSize& dcur, const FloatSize& dprev, int* curDir, int* dirChanges, int* angleSign) +{ + int thisDir = convexCompare(dcur); + if (thisDir == -*curDir) + ++*dirChanges; + *curDir = thisDir; + float cross = convexCross(dprev, dcur); + if (cross > 0) { + if (*angleSign == -1) + return false; + *angleSign = 1; + } else if (cross < 0) { + if (*angleSign == 1) + return false; + *angleSign = -1; + } + return true; +} + +bool isConvex(const FloatPoint* vertices, int nVertices) +{ + int dirChanges = 0, angleSign = 0; + FloatPoint second, third; + FloatSize dprev, dcur; + + /* Get different point, return if less than 3 diff points. */ + if (nVertices < 3) + return false; + int i = 1; + while (true) { + second = vertices[i++]; + dprev = second - vertices[0]; + if (dprev.width() || dprev.height()) + break; + /* Check if out of points. Check here to avoid slowing down cases + * without repeated points. + */ + if (i >= nVertices) + return false; + } + FloatPoint saveSecond = second; + int curDir = convexCompare(dprev); /* Find initial direction */ + while (i < nVertices) { + /* Get different point, break if no more points */ + third = vertices[i++]; + dcur = third - second; + if (!dcur.width() && !dcur.height()) + continue; + + /* Check current three points */ + if (!convexCheckTriple(dcur, dprev, &curDir, &dirChanges, &angleSign)) + return false; + second = third; /* Remember ptr to current point. */ + dprev = dcur; /* Remember current delta. */ + } + + /* Must check for direction changes from last vertex back to first */ + third = vertices[0]; /* Prepare for 'ConvexCheckTriple' */ + dcur = third - second; + if (convexCompare(dcur)) { + if (!convexCheckTriple(dcur, dprev, &curDir, &dirChanges, &angleSign)) + return false; + second = third; /* Remember ptr to current point. */ + dprev = dcur; /* Remember current delta. */ + } + + /* and check for direction changes back to second vertex */ + dcur = saveSecond - second; + if (!convexCheckTriple(dcur, dprev, &curDir, &dirChanges, &angleSign)) + return false; + + /* Decide on polygon type given accumulated status */ + if (dirChanges > 2) + return false; + + if (angleSign > 0 || angleSign < 0) + return true; + return false; +} + } // namespace LoopBlinnMathUtils } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.h b/Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.h index b9d19c5..361d901 100644 --- a/Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.h +++ b/Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.h @@ -101,6 +101,9 @@ bool xRayCrossesLine(const XRay& xRay, const FloatPoint lineEndpoints[2], bool& ambiguous); + +bool isConvex(const FloatPoint* vertices, int nVertices); + } // namespace LoopBlinnMathUtils } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/gpu/Shader.cpp b/Source/WebCore/platform/graphics/gpu/Shader.cpp index 1b9bfd5..13c5ebf 100644 --- a/Source/WebCore/platform/graphics/gpu/Shader.cpp +++ b/Source/WebCore/platform/graphics/gpu/Shader.cpp @@ -140,7 +140,7 @@ String Shader::generateVertex(Shader::VertexType vertexType, Shader::FillType fi case TwoDimensional: builder.append( "uniform mat3 matrix;\n" - "attribute vec3 position;\n"); + "attribute vec2 position;\n"); break; case LoopBlinnInterior: builder.append( @@ -167,7 +167,7 @@ String Shader::generateVertex(Shader::VertexType vertexType, Shader::FillType fi if (vertexType == TwoDimensional) { builder.append( - "gl_Position = vec4(matrix * position, 1.0);\n"); + "gl_Position = vec4(matrix * vec3(position, 1.0), 1.0);\n"); } else { builder.append( "gl_Position = worldViewProjection * vec4(position, 0.0, 1.0);\n"); @@ -179,7 +179,7 @@ String Shader::generateVertex(Shader::VertexType vertexType, Shader::FillType fi if (fillType == TextureFill) { builder.append( - "texCoord = texMatrix * position;\n"); + "texCoord = texMatrix * vec3(position, 1.0);\n"); } builder.append( diff --git a/Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp b/Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp index 662d6a8..b7b94c4 100644 --- a/Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp +++ b/Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp @@ -346,10 +346,10 @@ void SharedGraphicsContext3D::enableStencil(bool enable) void SharedGraphicsContext3D::useQuadVertices() { if (!m_quadVertices) { - float vertices[] = { 0.0f, 0.0f, 1.0f, - 1.0f, 0.0f, 1.0f, - 0.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f }; + float vertices[] = { 0.0f, 0.0f, + 1.0f, 0.0f, + 0.0f, 1.0f, + 1.0f, 1.0f }; m_quadVertices = m_context->createBuffer(); m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_quadVertices); m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, sizeof(vertices), vertices, GraphicsContext3D::STATIC_DRAW); diff --git a/Source/WebCore/platform/graphics/gpu/SolidFillShader.cpp b/Source/WebCore/platform/graphics/gpu/SolidFillShader.cpp index 78381f0..0a6e084 100644 --- a/Source/WebCore/platform/graphics/gpu/SolidFillShader.cpp +++ b/Source/WebCore/platform/graphics/gpu/SolidFillShader.cpp @@ -69,7 +69,7 @@ void SolidFillShader::use(const AffineTransform& transform, const Color& color) affineTo3x3(transform, matrix); m_context->uniformMatrix3fv(m_matrixLocation, false /*transpose*/, matrix, 1 /*count*/); - m_context->vertexAttribPointer(m_positionLocation, 3, GraphicsContext3D::FLOAT, false, 0, 0); + m_context->vertexAttribPointer(m_positionLocation, 2, GraphicsContext3D::FLOAT, false, 0, 0); m_context->enableVertexAttribArray(m_positionLocation); } diff --git a/Source/WebCore/platform/graphics/gpu/TexShader.cpp b/Source/WebCore/platform/graphics/gpu/TexShader.cpp index 9eb5c16..ac141a5 100644 --- a/Source/WebCore/platform/graphics/gpu/TexShader.cpp +++ b/Source/WebCore/platform/graphics/gpu/TexShader.cpp @@ -72,7 +72,7 @@ void TexShader::use(const AffineTransform& transform, const AffineTransform& tex m_context->uniform1i(m_samplerLocation, sampler); m_context->uniform1f(m_alphaLocation, alpha); - m_context->vertexAttribPointer(m_positionLocation, 3, GraphicsContext3D::FLOAT, false, 0, 0); + m_context->vertexAttribPointer(m_positionLocation, 2, GraphicsContext3D::FLOAT, false, 0, 0); m_context->enableVertexAttribArray(m_positionLocation); diff --git a/Source/WebCore/platform/graphics/gpu/TilingData.cpp b/Source/WebCore/platform/graphics/gpu/TilingData.cpp index 1370543..2415ee4 100644 --- a/Source/WebCore/platform/graphics/gpu/TilingData.cpp +++ b/Source/WebCore/platform/graphics/gpu/TilingData.cpp @@ -44,6 +44,9 @@ namespace WebCore { static int computeNumTiles(int maxTextureSize, int totalSize, int borderTexels) { + if (maxTextureSize - 2 * borderTexels <= 0) + return totalSize > 0 && maxTextureSize >= totalSize ? 1 : 0; + int numTiles = max(1, 1 + (totalSize - 1 - 2 * borderTexels) / (maxTextureSize - 2 * borderTexels)); return totalSize > 0 ? numTiles : 0; } diff --git a/Source/WebCore/platform/graphics/gstreamer/ImageGStreamer.h b/Source/WebCore/platform/graphics/gstreamer/ImageGStreamer.h index 6e53cfc..332908d 100644 --- a/Source/WebCore/platform/graphics/gstreamer/ImageGStreamer.h +++ b/Source/WebCore/platform/graphics/gstreamer/ImageGStreamer.h @@ -27,7 +27,7 @@ #include <gst/video/video.h> #include <wtf/PassRefPtr.h> -#if PLATFORM(CAIRO) +#if USE(CAIRO) #include <cairo.h> #endif @@ -48,7 +48,7 @@ class ImageGStreamer : public RefCounted<ImageGStreamer> { private: RefPtr<BitmapImage> m_image; -#if PLATFORM(CAIRO) +#if USE(CAIRO) ImageGStreamer(GstBuffer*&, IntSize, cairo_format_t&); #endif diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp index 2fb4cef..56c2f30 100644 --- a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp @@ -81,194 +81,74 @@ static int greatestCommonDivisor(int a, int b) return ABS(a); } -gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data) +static gboolean mediaPlayerPrivateMessageCallback(GstBus*, GstMessage* message, MediaPlayerPrivateGStreamer* player) { - GOwnPtr<GError> err; - GOwnPtr<gchar> debug; - MediaPlayer::NetworkState error; - MediaPlayerPrivateGStreamer* mp = reinterpret_cast<MediaPlayerPrivateGStreamer*>(data); - bool issueError = true; - bool attemptNextLocation = false; - GstElement* pipeline = mp->pipeline(); - - if (message->structure) { - const gchar* messageTypeName = gst_structure_get_name(message->structure); - - // Redirect messages are sent from elements, like qtdemux, to - // notify of the new location(s) of the media. - if (!g_strcmp0(messageTypeName, "redirect")) { - mp->mediaLocationChanged(message); - return true; - } - } - - switch (GST_MESSAGE_TYPE(message)) { - case GST_MESSAGE_ERROR: - if (mp && mp->pipelineReset()) - break; - gst_message_parse_error(message, &err.outPtr(), &debug.outPtr()); - LOG_VERBOSE(Media, "Error: %d, %s", err->code, err->message); - - error = MediaPlayer::Empty; - if (err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND - || err->code == GST_STREAM_ERROR_WRONG_TYPE - || err->code == GST_STREAM_ERROR_FAILED - || err->code == GST_CORE_ERROR_MISSING_PLUGIN - || err->code == GST_RESOURCE_ERROR_NOT_FOUND) - error = MediaPlayer::FormatError; - else if (err->domain == GST_STREAM_ERROR) { - // Let the mediaPlayerClient handle the stream error, in - // this case the HTMLMediaElement will emit a stalled - // event. - if (err->code == GST_STREAM_ERROR_TYPE_NOT_FOUND) { - LOG_VERBOSE(Media, "Decode error, let the Media element emit a stalled event."); - break; - } - error = MediaPlayer::DecodeError; - attemptNextLocation = true; - } else if (err->domain == GST_RESOURCE_ERROR) - error = MediaPlayer::NetworkError; - - if (mp) { - if (attemptNextLocation) - issueError = !mp->loadNextLocation(); - if (issueError) - mp->loadingFailed(error); - } - break; - case GST_MESSAGE_EOS: - LOG_VERBOSE(Media, "End of Stream"); - mp->didEnd(); - break; - case GST_MESSAGE_STATE_CHANGED: - // Ignore state changes if load is delayed (preload=none). The - // player state will be updated once commitLoad() is called. - if (mp->loadDelayed()) { - LOG_VERBOSE(Media, "Media load has been delayed. Ignoring state changes for now"); - break; - } - - // Ignore state changes from internal elements. They are - // forwarded to playbin2 anyway. - if (GST_MESSAGE_SRC(message) == reinterpret_cast<GstObject*>(pipeline)) - mp->updateStates(); - break; - case GST_MESSAGE_BUFFERING: - mp->processBufferingStats(message); - break; - case GST_MESSAGE_DURATION: - LOG_VERBOSE(Media, "Duration changed"); - mp->durationChanged(); - break; - default: - LOG_VERBOSE(Media, "Unhandled GStreamer message type: %s", - GST_MESSAGE_TYPE_NAME(message)); - break; - } - return true; + return player->handleMessage(message); } -void mediaPlayerPrivateSourceChangedCallback(GObject *object, GParamSpec *pspec, gpointer data) +static void mediaPlayerPrivateSourceChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player) { - MediaPlayerPrivateGStreamer* mp = reinterpret_cast<MediaPlayerPrivateGStreamer*>(data); - GOwnPtr<GstElement> element; - - g_object_get(mp->m_playBin, "source", &element.outPtr(), NULL); - gst_object_replace((GstObject**) &mp->m_source, (GstObject*) element.get()); - - if (WEBKIT_IS_WEB_SRC(element.get())) { - Frame* frame = mp->m_player->frameView() ? mp->m_player->frameView()->frame() : 0; - - if (frame) - webKitWebSrcSetFrame(WEBKIT_WEB_SRC(element.get()), frame); - } + player->sourceChanged(); } -void mediaPlayerPrivateVolumeChangedCallback(GObject *element, GParamSpec *pspec, gpointer data) +static void mediaPlayerPrivateVolumeChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player) { // This is called when playbin receives the notify::volume signal. - MediaPlayerPrivateGStreamer* mp = reinterpret_cast<MediaPlayerPrivateGStreamer*>(data); - mp->volumeChanged(); + player->volumeChanged(); } -gboolean mediaPlayerPrivateVolumeChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player) +static gboolean mediaPlayerPrivateVolumeChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player) { // This is the callback of the timeout source created in ::volumeChanged. player->notifyPlayerOfVolumeChange(); return FALSE; } -void mediaPlayerPrivateMuteChangedCallback(GObject *element, GParamSpec *pspec, gpointer data) +static void mediaPlayerPrivateMuteChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player) { // This is called when playbin receives the notify::mute signal. - MediaPlayerPrivateGStreamer* mp = reinterpret_cast<MediaPlayerPrivateGStreamer*>(data); - mp->muteChanged(); + player->muteChanged(); } -gboolean mediaPlayerPrivateMuteChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player) +static gboolean mediaPlayerPrivateMuteChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player) { // This is the callback of the timeout source created in ::muteChanged. player->notifyPlayerOfMute(); return FALSE; } -void mediaPlayerPrivateVideoTagsChangedCallback(GObject* element, gint streamId, MediaPlayerPrivateGStreamer* player) +static void mediaPlayerPrivateVideoSinkCapsChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player) { - player->videoTagsChanged(streamId); + player->videoChanged(); } -void mediaPlayerPrivateAudioTagsChangedCallback(GObject* element, gint streamId, MediaPlayerPrivateGStreamer* player) +static void mediaPlayerPrivateVideoChangedCallback(GObject*, MediaPlayerPrivateGStreamer* player) { - player->audioTagsChanged(streamId); + player->videoChanged(); } -gboolean mediaPlayerPrivateAudioTagsChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player) +static void mediaPlayerPrivateAudioChangedCallback(GObject*, MediaPlayerPrivateGStreamer* player) { - // This is the callback of the timeout source created in ::audioTagsChanged. - player->notifyPlayerOfAudioTags(); - return FALSE; + player->audioChanged(); } -gboolean mediaPlayerPrivateVideoTagsChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player) +static gboolean mediaPlayerPrivateAudioChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player) { - // This is the callback of the timeout source created in ::videoTagsChanged. - player->notifyPlayerOfVideoTags(); + // This is the callback of the timeout source created in ::audioChanged. + player->notifyPlayerOfAudio(); return FALSE; } -static float playbackPosition(GstElement* playbin) +static gboolean mediaPlayerPrivateVideoChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player) { - - float ret = 0.0f; - - GstQuery* query = gst_query_new_position(GST_FORMAT_TIME); - if (!gst_element_query(playbin, query)) { - LOG_VERBOSE(Media, "Position query failed..."); - gst_query_unref(query); - return ret; - } - - gint64 position; - gst_query_parse_position(query, 0, &position); - - // Position is available only if the pipeline is not in GST_STATE_NULL or - // GST_STATE_READY state. - if (position != static_cast<gint64>(GST_CLOCK_TIME_NONE)) - ret = static_cast<float>(position) / static_cast<float>(GST_SECOND); - - LOG_VERBOSE(Media, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position)); - - gst_query_unref(query); - - return ret; + // This is the callback of the timeout source created in ::videoChanged. + player->notifyPlayerOfVideo(); + return FALSE; } - -void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer *buffer, MediaPlayerPrivateGStreamer* playerPrivate) +static void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer *buffer, MediaPlayerPrivateGStreamer* playerPrivate) { - g_return_if_fail(GST_IS_BUFFER(buffer)); - gst_buffer_replace(&playerPrivate->m_buffer, buffer); - playerPrivate->repaint(); + playerPrivate->triggerRepaint(buffer); } MediaPlayerPrivateInterface* MediaPlayerPrivateGStreamer::create(MediaPlayer* player) @@ -347,8 +227,9 @@ MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer(MediaPlayer* player) , m_muteTimerHandler(0) , m_hasVideo(false) , m_hasAudio(false) - , m_audioTagsTimerHandler(0) - , m_videoTagsTimerHandler(0) + , m_audioTimerHandler(0) + , m_videoTimerHandler(0) + , m_webkitAudioSink(0) { if (doGstInit()) createGSTPlayBin(); @@ -392,11 +273,11 @@ MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer() if (m_volumeTimerHandler) g_source_remove(m_volumeTimerHandler); - if (m_videoTagsTimerHandler) - g_source_remove(m_videoTagsTimerHandler); + if (m_videoTimerHandler) + g_source_remove(m_videoTimerHandler); - if (m_audioTagsTimerHandler) - g_source_remove(m_audioTagsTimerHandler); + if (m_audioTimerHandler) + g_source_remove(m_audioTimerHandler); } void MediaPlayerPrivateGStreamer::load(const String& url) @@ -425,6 +306,32 @@ void MediaPlayerPrivateGStreamer::commitLoad() updateStates(); } +float MediaPlayerPrivateGStreamer::playbackPosition() const +{ + float ret = 0.0f; + + GstQuery* query = gst_query_new_position(GST_FORMAT_TIME); + if (!gst_element_query(m_playBin, query)) { + LOG_VERBOSE(Media, "Position query failed..."); + gst_query_unref(query); + return ret; + } + + gint64 position; + gst_query_parse_position(query, 0, &position); + + // Position is available only if the pipeline is not in GST_STATE_NULL or + // GST_STATE_READY state. + if (position != static_cast<gint64>(GST_CLOCK_TIME_NONE)) + ret = static_cast<float>(position) / static_cast<float>(GST_SECOND); + + LOG_VERBOSE(Media, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position)); + + gst_query_unref(query); + + return ret; +} + bool MediaPlayerPrivateGStreamer::changePipelineState(GstState newState) { ASSERT(newState == GST_STATE_PLAYING || newState == GST_STATE_PAUSED); @@ -504,14 +411,14 @@ float MediaPlayerPrivateGStreamer::currentTime() const if (m_seeking) return m_seekTime; - return playbackPosition(m_playBin); + return playbackPosition(); } void MediaPlayerPrivateGStreamer::seek(float time) { // Avoid useless seeking. - if (time == playbackPosition(m_playBin)) + if (time == playbackPosition()) return; if (!m_playBin) @@ -582,6 +489,7 @@ IntSize MediaPlayerPrivateGStreamer::naturalSize() const || !gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator, &pixelAspectRatioDenominator)) { gst_object_unref(GST_OBJECT(pad)); + // The video-sink has likely not yet negotiated its caps. return IntSize(); } @@ -618,39 +526,40 @@ IntSize MediaPlayerPrivateGStreamer::naturalSize() const return IntSize(static_cast<int>(width), static_cast<int>(height)); } -void MediaPlayerPrivateGStreamer::videoTagsChanged(gint streamId) +void MediaPlayerPrivateGStreamer::videoChanged() { - if (m_videoTagsTimerHandler) - g_source_remove(m_videoTagsTimerHandler); - m_videoTagsTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateVideoTagsChangeTimeoutCallback), this); + if (m_videoTimerHandler) + g_source_remove(m_videoTimerHandler); + m_videoTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateVideoChangeTimeoutCallback), this); } -void MediaPlayerPrivateGStreamer::notifyPlayerOfVideoTags() +void MediaPlayerPrivateGStreamer::notifyPlayerOfVideo() { - m_videoTagsTimerHandler = 0; + m_videoTimerHandler = 0; - gint currentVideo = -1; + gint videoTracks = 0; if (m_playBin) - g_object_get(m_playBin, "current-video", ¤tVideo, NULL); - m_hasVideo = currentVideo > -1; + g_object_get(m_playBin, "n-video", &videoTracks, NULL); + + m_hasVideo = videoTracks > 0; m_player->mediaPlayerClient()->mediaPlayerEngineUpdated(m_player); } -void MediaPlayerPrivateGStreamer::audioTagsChanged(gint streamId) +void MediaPlayerPrivateGStreamer::audioChanged() { - if (m_audioTagsTimerHandler) - g_source_remove(m_audioTagsTimerHandler); - m_audioTagsTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateAudioTagsChangeTimeoutCallback), this); + if (m_audioTimerHandler) + g_source_remove(m_audioTimerHandler); + m_audioTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateAudioChangeTimeoutCallback), this); } -void MediaPlayerPrivateGStreamer::notifyPlayerOfAudioTags() +void MediaPlayerPrivateGStreamer::notifyPlayerOfAudio() { - m_audioTagsTimerHandler = 0; + m_audioTimerHandler = 0; - gint currentAudio = -1; + gint audioTracks = 0; if (m_playBin) - g_object_get(m_playBin, "current-audio", ¤tAudio, NULL); - m_hasAudio = currentAudio > -1; + g_object_get(m_playBin, "n-audio", &audioTracks, NULL); + m_hasAudio = audioTracks > 0; m_player->mediaPlayerClient()->mediaPlayerEngineUpdated(m_player); } @@ -704,13 +613,19 @@ void MediaPlayerPrivateGStreamer::setRate(float rate) m_playbackRate = rate; m_changingRate = true; - float currentPosition = static_cast<float>(playbackPosition(m_playBin) * GST_SECOND); + + if (!rate) { + gst_element_set_state(m_playBin, GST_STATE_PAUSED); + return; + } + + float currentPosition = static_cast<float>(playbackPosition() * GST_SECOND); GstSeekFlags flags = (GstSeekFlags)(GST_SEEK_FLAG_FLUSH); gint64 start, end; bool mute = false; LOG_VERBOSE(Media, "Set Rate to %f", rate); - if (rate >= 0) { + if (rate > 0) { // Mute the sound if the playback rate is too extreme. // TODO: in other cases we should perform pitch adjustments. mute = (bool) (rate < 0.8 || rate > 2); @@ -788,6 +703,89 @@ PassRefPtr<TimeRanges> MediaPlayerPrivateGStreamer::buffered() const return timeRanges.release(); } +gboolean MediaPlayerPrivateGStreamer::handleMessage(GstMessage* message) +{ + GOwnPtr<GError> err; + GOwnPtr<gchar> debug; + MediaPlayer::NetworkState error; + bool issueError = true; + bool attemptNextLocation = false; + + if (message->structure) { + const gchar* messageTypeName = gst_structure_get_name(message->structure); + + // Redirect messages are sent from elements, like qtdemux, to + // notify of the new location(s) of the media. + if (!g_strcmp0(messageTypeName, "redirect")) { + mediaLocationChanged(message); + return TRUE; + } + } + + switch (GST_MESSAGE_TYPE(message)) { + case GST_MESSAGE_ERROR: + if (m_resetPipeline) + break; + gst_message_parse_error(message, &err.outPtr(), &debug.outPtr()); + LOG_VERBOSE(Media, "Error: %d, %s", err->code, err->message); + + error = MediaPlayer::Empty; + if (err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND + || err->code == GST_STREAM_ERROR_WRONG_TYPE + || err->code == GST_STREAM_ERROR_FAILED + || err->code == GST_CORE_ERROR_MISSING_PLUGIN + || err->code == GST_RESOURCE_ERROR_NOT_FOUND) + error = MediaPlayer::FormatError; + else if (err->domain == GST_STREAM_ERROR) { + // Let the mediaPlayerClient handle the stream error, in + // this case the HTMLMediaElement will emit a stalled + // event. + if (err->code == GST_STREAM_ERROR_TYPE_NOT_FOUND) { + LOG_VERBOSE(Media, "Decode error, let the Media element emit a stalled event."); + break; + } + error = MediaPlayer::DecodeError; + attemptNextLocation = true; + } else if (err->domain == GST_RESOURCE_ERROR) + error = MediaPlayer::NetworkError; + + if (attemptNextLocation) + issueError = !loadNextLocation(); + if (issueError) + loadingFailed(error); + break; + case GST_MESSAGE_EOS: + LOG_VERBOSE(Media, "End of Stream"); + didEnd(); + break; + case GST_MESSAGE_STATE_CHANGED: + // Ignore state changes if load is delayed (preload=none). The + // player state will be updated once commitLoad() is called. + if (m_delayingLoad) { + LOG_VERBOSE(Media, "Media load has been delayed. Ignoring state changes for now"); + break; + } + + // Ignore state changes from internal elements. They are + // forwarded to playbin2 anyway. + if (GST_MESSAGE_SRC(message) == reinterpret_cast<GstObject*>(m_playBin)) + updateStates(); + break; + case GST_MESSAGE_BUFFERING: + processBufferingStats(message); + break; + case GST_MESSAGE_DURATION: + LOG_VERBOSE(Media, "Duration changed"); + durationChanged(); + break; + default: + LOG_VERBOSE(Media, "Unhandled GStreamer message type: %s", + GST_MESSAGE_TYPE_NAME(message)); + break; + } + return TRUE; +} + void MediaPlayerPrivateGStreamer::processBufferingStats(GstMessage* message) { // This is the immediate buffering that needs to happen so we have @@ -952,6 +950,75 @@ unsigned MediaPlayerPrivateGStreamer::totalBytes() const return static_cast<unsigned>(length); } +unsigned MediaPlayerPrivateGStreamer::decodedFrameCount() const +{ + guint64 decodedFrames = 0; + if (m_fpsSink) + g_object_get(m_fpsSink, "frames-rendered", &decodedFrames, NULL); + return static_cast<unsigned>(decodedFrames); +} + +unsigned MediaPlayerPrivateGStreamer::droppedFrameCount() const +{ + guint64 framesDropped = 0; + if (m_fpsSink) + g_object_get(m_fpsSink, "frames-dropped", &framesDropped, NULL); + return static_cast<unsigned>(framesDropped); +} + +unsigned MediaPlayerPrivateGStreamer::audioDecodedByteCount() const +{ + GstQuery* query = gst_query_new_position(GST_FORMAT_BYTES); + gint64 position = 0; + + if (m_webkitAudioSink && gst_element_query(m_webkitAudioSink, query)) + gst_query_parse_position(query, 0, &position); + + gst_query_unref(query); + return static_cast<unsigned>(position); +} + +unsigned MediaPlayerPrivateGStreamer::videoDecodedByteCount() const +{ + GstQuery* query = gst_query_new_position(GST_FORMAT_BYTES); + gint64 position = 0; + + if (gst_element_query(m_webkitVideoSink, query)) + gst_query_parse_position(query, 0, &position); + + gst_query_unref(query); + return static_cast<unsigned>(position); +} + +void MediaPlayerPrivateGStreamer::updateAudioSink() +{ + if (!m_playBin) + return; + + GOwnPtr<GstElement> element; + + g_object_get(m_playBin, "audio-sink", &element.outPtr(), NULL); + gst_object_replace(reinterpret_cast<GstObject**>(&m_webkitAudioSink), + reinterpret_cast<GstObject*>(element.get())); +} + + +void MediaPlayerPrivateGStreamer::sourceChanged() +{ + GOwnPtr<GstElement> element; + + g_object_get(m_playBin, "source", &element.outPtr(), NULL); + gst_object_replace(reinterpret_cast<GstObject**>(&m_source), + reinterpret_cast<GstObject*>(element.get())); + + if (WEBKIT_IS_WEB_SRC(element.get())) { + Frame* frame = m_player->frameView() ? m_player->frameView()->frame() : 0; + + if (frame) + webKitWebSrcSetFrame(WEBKIT_WEB_SRC(element.get()), frame); + } +} + void MediaPlayerPrivateGStreamer::cancelLoad() { if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded) @@ -1011,6 +1078,8 @@ void MediaPlayerPrivateGStreamer::updateStates() // information from GStreamer, while we sync states where // needed. if (state == GST_STATE_PAUSED) { + if (!m_webkitAudioSink) + updateAudioSink(); if (m_buffering && m_bufferingPercentage == 100) { m_buffering = false; m_bufferingPercentage = 0; @@ -1347,8 +1416,11 @@ void MediaPlayerPrivateGStreamer::setVisible(bool visible) { } -void MediaPlayerPrivateGStreamer::repaint() + +void MediaPlayerPrivateGStreamer::triggerRepaint(GstBuffer* buffer) { + g_return_if_fail(GST_IS_BUFFER(buffer)); + gst_buffer_replace(&m_buffer, buffer); m_player->repaint(); } @@ -1359,6 +1431,7 @@ void MediaPlayerPrivateGStreamer::paint(GraphicsContext* context, const IntRect& if (!m_player->visible()) return; + if (!m_buffer) return; @@ -1477,6 +1550,9 @@ static HashSet<String> mimeTypeCache() || (g_str_equal(mimetype[0], "application") && handledApplicationSubtypes.contains(String(mimetype[1])))) cache.add(String(name)); + else if (g_str_equal(name, "application/x-hls")) + cache.add(String("application/vnd.apple.mpegurl")); + g_strfreev(mimetype); } @@ -1584,8 +1660,8 @@ void MediaPlayerPrivateGStreamer::createGSTPlayBin() g_signal_connect(m_playBin, "notify::volume", G_CALLBACK(mediaPlayerPrivateVolumeChangedCallback), this); g_signal_connect(m_playBin, "notify::source", G_CALLBACK(mediaPlayerPrivateSourceChangedCallback), this); g_signal_connect(m_playBin, "notify::mute", G_CALLBACK(mediaPlayerPrivateMuteChangedCallback), this); - g_signal_connect(m_playBin, "video-tags-changed", G_CALLBACK(mediaPlayerPrivateVideoTagsChangedCallback), this); - g_signal_connect(m_playBin, "audio-tags-changed", G_CALLBACK(mediaPlayerPrivateAudioTagsChangedCallback), this); + g_signal_connect(m_playBin, "video-changed", G_CALLBACK(mediaPlayerPrivateVideoChangedCallback), this); + g_signal_connect(m_playBin, "audio-changed", G_CALLBACK(mediaPlayerPrivateAudioChangedCallback), this); m_webkitVideoSink = webkit_video_sink_new(); @@ -1613,39 +1689,44 @@ void MediaPlayerPrivateGStreamer::createGSTPlayBin() gst_object_unref(GST_OBJECT(srcPad)); gst_object_unref(GST_OBJECT(sinkPad)); - WTFLogChannel* channel = getChannelFromName("Media"); - if (channel->state == WTFLogChannelOn) { - m_fpsSink = gst_element_factory_make("fpsdisplaysink", "sink"); - if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_fpsSink), "video-sink")) { - g_object_set(m_fpsSink, "video-sink", m_webkitVideoSink, NULL); - gst_bin_add(GST_BIN(m_videoSinkBin), m_fpsSink); -#if GST_CHECK_VERSION(0, 10, 30) - // Faster elements linking, if possible. - gst_element_link_pads_full(queue, "src", m_fpsSink, "sink", GST_PAD_LINK_CHECK_NOTHING); -#else - gst_element_link(queue, m_fpsSink); -#endif - } else { + GstElement* actualVideoSink = 0; + m_fpsSink = gst_element_factory_make("fpsdisplaysink", "sink"); + if (m_fpsSink) { + // The verbose property has been added in -bad 0.10.22. Making + // this whole code depend on it because we don't want + // fpsdiplaysink to spit data on stdout. + GstElementFactory* factory = GST_ELEMENT_FACTORY(GST_ELEMENT_GET_CLASS(m_fpsSink)->elementfactory); + if (gst_plugin_feature_check_version(GST_PLUGIN_FEATURE(factory), 0, 10, 22)) { + g_object_set(m_fpsSink, "silent", TRUE , NULL); + + // Turn off text overlay unless logging is enabled. + WTFLogChannel* channel = getChannelFromName("Media"); + if (channel->state != WTFLogChannelOn) + g_object_set(m_fpsSink, "text-overlay", FALSE , NULL); + + if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_fpsSink), "video-sink")) { + g_object_set(m_fpsSink, "video-sink", m_webkitVideoSink, NULL); + gst_bin_add(GST_BIN(m_videoSinkBin), m_fpsSink); + actualVideoSink = m_fpsSink; + } else + m_fpsSink = 0; + } else m_fpsSink = 0; - gst_bin_add(GST_BIN(m_videoSinkBin), m_webkitVideoSink); -#if GST_CHECK_VERSION(0, 10, 30) - // Faster elements linking, if possible. - gst_element_link_pads_full(queue, "src", m_webkitVideoSink, "sink", GST_PAD_LINK_CHECK_NOTHING); -#else - gst_element_link(queue, m_webkitVideoSink); -#endif - LOG_VERBOSE(Media, "Can't display FPS statistics, you need gst-plugins-bad >= 0.10.18"); - } - } else { + } + + if (!m_fpsSink) { gst_bin_add(GST_BIN(m_videoSinkBin), m_webkitVideoSink); + actualVideoSink = m_webkitVideoSink; + } + + ASSERT(actualVideoSink); #if GST_CHECK_VERSION(0, 10, 30) // Faster elements linking, if possible. gst_element_link_pads_full(queue, "src", identity, "sink", GST_PAD_LINK_CHECK_NOTHING); - gst_element_link_pads_full(identity, "src", m_webkitVideoSink, "sink", GST_PAD_LINK_CHECK_NOTHING); + gst_element_link_pads_full(identity, "src", actualVideoSink, "sink", GST_PAD_LINK_CHECK_NOTHING); #else - gst_element_link_many(queue, identity, m_webkitVideoSink, NULL); + gst_element_link_many(queue, identity, actualVideoSink, NULL); #endif - } // Add a ghostpad to the bin so it can proxy to tee. GstPad* pad = gst_element_get_static_pad(videoTee, "sink"); @@ -1654,6 +1735,14 @@ void MediaPlayerPrivateGStreamer::createGSTPlayBin() // Set the bin as video sink of playbin. g_object_set(m_playBin, "video-sink", m_videoSinkBin, NULL); + + + pad = gst_element_get_static_pad(m_webkitVideoSink, "sink"); + if (pad) { + g_signal_connect(pad, "notify::caps", G_CALLBACK(mediaPlayerPrivateVideoSinkCapsChangedCallback), this); + gst_object_unref(GST_OBJECT(pad)); + } + } } diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h index 8003887..024fad0 100644 --- a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h +++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h @@ -35,7 +35,6 @@ typedef struct _WebKitVideoSink WebKitVideoSink; typedef struct _GstBuffer GstBuffer; typedef struct _GstMessage GstMessage; typedef struct _GstElement GstElement; -typedef struct _GstBus GstBus; namespace WebCore { @@ -45,25 +44,11 @@ class IntRect; class GStreamerGWorld; class MediaPlayerPrivateGStreamer; -gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data); -void mediaPlayerPrivateVolumeChangedCallback(GObject* element, GParamSpec* pspec, gpointer data); -void mediaPlayerPrivateMuteChangedCallback(GObject* element, GParamSpec* pspec, gpointer data); -void mediaPlayerPrivateSourceChangedCallback(GObject* element, GParamSpec* pspec, gpointer data); -void mediaPlayerPrivateVideoTagsChangedCallback(GObject* element, gint, MediaPlayerPrivateGStreamer*); -void mediaPlayerPrivateAudioTagsChangedCallback(GObject* element, gint, MediaPlayerPrivateGStreamer*); -gboolean mediaPlayerPrivateAudioTagsChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player); -gboolean mediaPlayerPrivateVideoTagsChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player); - -gboolean mediaPlayerPrivateVolumeChangeTimeoutCallback(MediaPlayerPrivateGStreamer*); -gboolean mediaPlayerPrivateMuteChangeTimeoutCallback(MediaPlayerPrivateGStreamer*); - class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { - friend gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data); - friend void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer* buffer, MediaPlayerPrivateGStreamer* playerPrivate); - friend void mediaPlayerPrivateSourceChangedCallback(GObject* element, GParamSpec* pspec, gpointer data); public: static void registerMediaEngine(MediaEngineRegistrar); + gboolean handleMessage(GstMessage*); IntSize naturalSize() const; bool hasVideo() const { return m_hasVideo; } @@ -72,7 +57,6 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { void load(const String &url); void commitLoad(); void cancelLoad(); - bool loadNextLocation(); void prepareToPlay(); void play(); @@ -96,7 +80,6 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { void muteChanged(); void notifyPlayerOfMute(); - bool loadDelayed() const { return m_delayingLoad; } void setPreload(MediaPlayer::Preload); void fillTimerFired(Timer<MediaPlayerPrivateGStreamer>*); @@ -111,7 +94,6 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { void setVisible(bool); void setSize(const IntSize&); - void mediaLocationChanged(GstMessage*); void loadStateChanged(); void sizeChanged(); void timeChanged(); @@ -119,6 +101,7 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { void durationChanged(); void loadingFailed(MediaPlayer::NetworkState); + void triggerRepaint(GstBuffer*); void repaint(); void paint(GraphicsContext*, const IntRect&); @@ -127,13 +110,17 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { bool supportsFullscreen() const; PlatformMedia platformMedia() const; - GstElement* pipeline() const { return m_playBin; } - bool pipelineReset() const { return m_resetPipeline; } + void videoChanged(); + void audioChanged(); + void notifyPlayerOfVideo(); + void notifyPlayerOfAudio(); + + void sourceChanged(); - void videoTagsChanged(gint); - void audioTagsChanged(gint); - void notifyPlayerOfVideoTags(); - void notifyPlayerOfAudioTags(); + unsigned decodedFrameCount() const; + unsigned droppedFrameCount() const; + unsigned audioDecodedByteCount() const; + unsigned videoDecodedByteCount() const; private: MediaPlayerPrivateGStreamer(MediaPlayer*); @@ -145,6 +132,10 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs); static bool isAvailable(); + void updateAudioSink(); + + float playbackPosition() const; + void cacheDuration(); void updateStates(); float maxTimeLoaded() const; @@ -152,7 +143,10 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { void createGSTPlayBin(); bool changePipelineState(GstState state); - void processBufferingStats(GstMessage* message); + bool loadNextLocation(); + void mediaLocationChanged(GstMessage*); + + void processBufferingStats(GstMessage*); private: MediaPlayer* m_player; @@ -191,8 +185,9 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { guint m_muteTimerHandler; bool m_hasVideo; bool m_hasAudio; - guint m_audioTagsTimerHandler; - guint m_videoTagsTimerHandler; + guint m_audioTimerHandler; + guint m_videoTimerHandler; + GstElement* m_webkitAudioSink; }; } diff --git a/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowPrivate.h b/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowPrivate.h index 0ae4587..7b441f4 100644 --- a/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowPrivate.h +++ b/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowPrivate.h @@ -20,21 +20,37 @@ #ifndef PlatformVideoWindowPrivate_h #define PlatformVideoWindowPrivate_h +#include <QTimer> #include <QWidget> class QKeyEvent; namespace WebCore { +class HTMLVideoElement; + class FullScreenVideoWindow: public QWidget { Q_OBJECT public: FullScreenVideoWindow(); + void setVideoElement(HTMLVideoElement*); signals: void closed(); protected: - void keyPressEvent(QKeyEvent* ev); - bool event(QEvent* ev); + void closeEvent(QCloseEvent*); + void keyPressEvent(QKeyEvent*); + bool event(QEvent*); + +public slots: + void showFullScreen(); + +private slots: + void hideCursor(); + +private: + void showCursor(); + QTimer m_cursorTimer; + HTMLVideoElement* m_mediaElement; }; diff --git a/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowQt.cpp b/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowQt.cpp index 872d055..7270785 100644 --- a/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowQt.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowQt.cpp @@ -20,6 +20,7 @@ #include "config.h" #include "PlatformVideoWindow.h" +#include "HTMLVideoElement.h" #include "PlatformVideoWindowPrivate.h" #include <QApplication> @@ -28,29 +29,55 @@ #include <QPalette> using namespace WebCore; +static const int gHideMouseCursorDelay = 3000; + FullScreenVideoWindow::FullScreenVideoWindow() : QWidget(0, Qt::Window) + , m_mediaElement(0) { setAttribute(Qt::WA_NativeWindow); - // Setting these values ensures smooth resizing since it - // will prevent the system from clearing the background. + setWindowModality(Qt::ApplicationModal); setAttribute(Qt::WA_NoSystemBackground, true); setAttribute(Qt::WA_PaintOnScreen, true); + + m_cursorTimer.setSingleShot(true); + connect(&m_cursorTimer, SIGNAL(timeout()), this, SLOT(hideCursor())); +} + +void FullScreenVideoWindow::setVideoElement(HTMLVideoElement* element) +{ + m_mediaElement = element; +} + +void FullScreenVideoWindow::closeEvent(QCloseEvent*) +{ + m_cursorTimer.stop(); + setMouseTracking(false); + releaseMouse(); + QApplication::restoreOverrideCursor(); } void FullScreenVideoWindow::keyPressEvent(QKeyEvent* ev) { - if (ev->key() == Qt::Key_Escape) { - close(); + if (m_mediaElement && ev->key() == Qt::Key_Space) { + if (!m_mediaElement->paused()) + m_mediaElement->pause(true); + else + m_mediaElement->play(true); + } else if (ev->key() == Qt::Key_Escape) emit closed(); - } + QWidget::keyPressEvent(ev); } bool FullScreenVideoWindow::event(QEvent* ev) { switch (ev->type()) { + case QEvent::MouseMove: + showCursor(); + ev->accept(); + return true; case QEvent::MouseButtonDblClick: - close(); + emit closed(); ev->accept(); return true; default: @@ -58,6 +85,26 @@ bool FullScreenVideoWindow::event(QEvent* ev) } } +void FullScreenVideoWindow::showFullScreen() +{ + QWidget::showFullScreen(); + setMouseTracking(true); + raise(); + setFocus(); + hideCursor(); +} + +void FullScreenVideoWindow::hideCursor() +{ + QApplication::setOverrideCursor(QCursor(Qt::BlankCursor)); +} + +void FullScreenVideoWindow::showCursor() +{ + QApplication::restoreOverrideCursor(); + m_cursorTimer.start(gHideMouseCursorDelay); +} + PlatformVideoWindow::PlatformVideoWindow() { diff --git a/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp index 66ea9ba..e48998f 100644 --- a/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp @@ -791,7 +791,7 @@ void StreamingClient::didReceiveResponse(ResourceHandle*, const ResourceResponse gst_element_found_tags_for_pad(GST_ELEMENT(m_src), m_src->priv->srcpad, tags); } -void StreamingClient::didReceiveData(ResourceHandle* handle, const char* data, int length, int lengthReceived) +void StreamingClient::didReceiveData(ResourceHandle* handle, const char* data, int length, int encodedDataLength) { WebKitWebSrcPrivate* priv = m_src->priv; diff --git a/Source/WebCore/platform/graphics/gtk/DrawingBufferGtk.cpp b/Source/WebCore/platform/graphics/gtk/DrawingBufferGtk.cpp new file mode 100644 index 0000000..17fc334 --- /dev/null +++ b/Source/WebCore/platform/graphics/gtk/DrawingBufferGtk.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(ACCELERATED_2D_CANVAS) || ENABLE(WEBGL) + +#include "DrawingBuffer.h" + +#include "Extensions3D.h" + +namespace WebCore { + +DrawingBuffer::DrawingBuffer(GraphicsContext3D* context, + const IntSize& size, + bool multisampleExtensionSupported, + bool packedDepthStencilExtensionSupported) + : m_context(context) + , m_size(-1, -1) + , m_multisampleExtensionSupported(multisampleExtensionSupported) + , m_packedDepthStencilExtensionSupported(packedDepthStencilExtensionSupported) + , m_fbo(context->createFramebuffer()) + , m_colorBuffer(0) + , m_depthStencilBuffer(0) + , m_multisampleFBO(0) + , m_multisampleColorBuffer(0) +{ + ASSERT(m_fbo); + if (!m_fbo) { + clear(); + return; + } + + // create a texture to render into + m_colorBuffer = context->createTexture(); + context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_colorBuffer); + context->texParameterf(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR); + context->texParameterf(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR); + context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE); + context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE); + context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0); + + // Create the FBO + m_fbo = context->createFramebuffer(); + ASSERT(m_fbo); + if (!m_fbo) { + clear(); + return; + } + + createSecondaryBuffers(); + reset(size); +} + +DrawingBuffer::~DrawingBuffer() +{ + clear(); +} + +void DrawingBuffer::didReset() +{ +} + +Platform3DObject DrawingBuffer::platformColorBuffer() const +{ + return m_colorBuffer; +} + +} + +#endif diff --git a/Source/WebCore/platform/graphics/gtk/FontGtk.cpp b/Source/WebCore/platform/graphics/gtk/FontGtk.cpp index d14b052..977aa62 100644 --- a/Source/WebCore/platform/graphics/gtk/FontGtk.cpp +++ b/Source/WebCore/platform/graphics/gtk/FontGtk.cpp @@ -35,9 +35,10 @@ #include "CairoUtilities.h" #include "ContextShadow.h" -#include "PlatformContextCairo.h" +#include "GOwnPtr.h" #include "GraphicsContext.h" #include "NotImplemented.h" +#include "PlatformContextCairo.h" #include "SimpleFontData.h" #include "TextRun.h" #include <cairo.h> @@ -84,75 +85,71 @@ IntRect getPangoRegionExtents(PangoRegionType region) #define IS_HIGH_SURROGATE(u) ((UChar)(u) >= (UChar)0xd800 && (UChar)(u) <= (UChar)0xdbff) #define IS_LOW_SURROGATE(u) ((UChar)(u) >= (UChar)0xdc00 && (UChar)(u) <= (UChar)0xdfff) -static void utf16_to_utf8(const UChar* aText, gint aLength, char* &text, gint &length) +static gchar* utf16ToUtf8(const UChar* aText, gint aLength, gint &length) { - gboolean need_copy = FALSE; - int i; + gboolean needCopy = FALSE; - for (i = 0; i < aLength; i++) { - if (!aText[i] || IS_LOW_SURROGATE(aText[i])) { - need_copy = TRUE; - break; - } - else if (IS_HIGH_SURROGATE(aText[i])) { - if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1])) - i++; - else { - need_copy = TRUE; - break; - } + for (int i = 0; i < aLength; i++) { + if (!aText[i] || IS_LOW_SURROGATE(aText[i])) { + needCopy = TRUE; + break; + } + + if (IS_HIGH_SURROGATE(aText[i])) { + if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1])) + i++; + else { + needCopy = TRUE; + break; + } + } } - } - - if (need_copy) { - /* Pango doesn't correctly handle nuls. We convert them to 0xff. */ - /* Also "validate" UTF-16 text to make sure conversion doesn't fail. */ - - UChar* p = (UChar*)g_memdup(aText, aLength * sizeof(aText[0])); - - /* don't need to reset i */ - for (i = 0; i < aLength; i++) { - if (!p[i] || IS_LOW_SURROGATE(p[i])) - p[i] = 0xFFFD; - else if (IS_HIGH_SURROGATE(p[i])) { - if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1])) - i++; - else - p[i] = 0xFFFD; - } + GOwnPtr<UChar> copiedString; + if (needCopy) { + /* Pango doesn't correctly handle nuls. We convert them to 0xff. */ + /* Also "validate" UTF-16 text to make sure conversion doesn't fail. */ + + copiedString.set(static_cast<UChar*>(g_memdup(aText, aLength * sizeof(aText[0])))); + UChar* p = copiedString.get(); + + /* don't need to reset i */ + for (int i = 0; i < aLength; i++) { + if (!p[i] || IS_LOW_SURROGATE(p[i])) + p[i] = 0xFFFD; + else if (IS_HIGH_SURROGATE(p[i])) { + if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1])) + i++; + else + p[i] = 0xFFFD; + } + } + + aText = p; } - aText = p; - } - - glong items_written; - text = g_utf16_to_utf8(reinterpret_cast<const gunichar2*>(aText), aLength, NULL, &items_written, NULL); - length = items_written; - - if (need_copy) - g_free((gpointer)aText); + gchar* utf8Text; + glong itemsWritten; + utf8Text = g_utf16_to_utf8(static_cast<const gunichar2*>(aText), aLength, 0, &itemsWritten, 0); + length = itemsWritten; + return utf8Text; } static gchar* convertUniCharToUTF8(const UChar* characters, gint length, int from, int to) { - gchar* utf8 = 0; - gint new_length = 0; - utf16_to_utf8(characters, length, utf8, new_length); - if (!utf8) - return NULL; + gint newLength = 0; + GOwnPtr<gchar> utf8Text(utf16ToUtf8(characters, length, newLength)); + if (!utf8Text) + return 0; + gchar* pos = utf8Text.get(); if (from > 0) { // discard the first 'from' characters // FIXME: we should do this before the conversion probably - gchar* str_left = g_utf8_offset_to_pointer(utf8, from); - gchar* tmp = g_strdup(str_left); - g_free(utf8); - utf8 = tmp; + pos = g_utf8_offset_to_pointer(utf8Text.get(), from); } - gchar* pos = utf8; gint len = strlen(pos); GString* ret = g_string_new_len(NULL, len); diff --git a/Source/WebCore/platform/graphics/gtk/GraphicsContext3DGtk.cpp b/Source/WebCore/platform/graphics/gtk/GraphicsContext3DGtk.cpp new file mode 100644 index 0000000..8e03ad7 --- /dev/null +++ b/Source/WebCore/platform/graphics/gtk/GraphicsContext3DGtk.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2011 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GraphicsContext3D.h" + +#if ENABLE(WEBGL) + +#include "Extensions3DOpenGL.h" +#include "GraphicsContext3DInternal.h" +#include "OpenGLShims.h" +#include "ShaderLang.h" +#include <wtf/NotFound.h> + +namespace WebCore { + +PassRefPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attributes attributes, HostWindow* hostWindow, GraphicsContext3D::RenderStyle renderStyle) +{ + // This implementation doesn't currently support rendering directly to the HostWindow. + if (renderStyle == RenderDirectlyToHostWindow) + return 0; + + GraphicsContext3DInternal* internal = GraphicsContext3DInternal::create(); + if (!internal) + return 0; + + RefPtr<GraphicsContext3D> context = adoptRef(new GraphicsContext3D(attributes, hostWindow, false)); + context->m_internal.set(internal); + return context.release(); +} + +GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attributes, HostWindow*, bool) + : m_currentWidth(0) + , m_currentHeight(0) + , m_attrs(attributes) + , m_texture(0) + , m_fbo(0) + , m_depthStencilBuffer(0) + , m_boundFBO(0) + , m_multisampleFBO(0) + , m_multisampleDepthStencilBuffer(0) + , m_multisampleColorBuffer(0) +{ + GraphicsContext3DInternal::addActiveGraphicsContext(this); + + validateAttributes(); + + // Create a texture to render into. + ::glGenTextures(1, &m_texture); + ::glBindTexture(GL_TEXTURE_2D, m_texture); + ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + ::glBindTexture(GL_TEXTURE_2D, 0); + + // Create an FBO. + ::glGenFramebuffersEXT(1, &m_fbo); + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); + + m_boundFBO = m_fbo; + if (!m_attrs.antialias && (m_attrs.stencil || m_attrs.depth)) + ::glGenRenderbuffersEXT(1, &m_depthStencilBuffer); + + // Create a multisample FBO. + if (m_attrs.antialias) { + ::glGenFramebuffersEXT(1, &m_multisampleFBO); + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO); + m_boundFBO = m_multisampleFBO; + ::glGenRenderbuffersEXT(1, &m_multisampleColorBuffer); + if (m_attrs.stencil || m_attrs.depth) + ::glGenRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer); + } + + // ANGLE initialization. + ShBuiltInResources ANGLEResources; + ShInitBuiltInResources(&ANGLEResources); + + getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &ANGLEResources.MaxVertexAttribs); + getIntegerv(GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS, &ANGLEResources.MaxVertexUniformVectors); + getIntegerv(GraphicsContext3D::MAX_VARYING_VECTORS, &ANGLEResources.MaxVaryingVectors); + getIntegerv(GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxVertexTextureImageUnits); + getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxCombinedTextureImageUnits); + getIntegerv(GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxTextureImageUnits); + getIntegerv(GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS, &ANGLEResources.MaxFragmentUniformVectors); + + // Always set to 1 for OpenGL ES. + ANGLEResources.MaxDrawBuffers = 1; + m_compiler.setResources(ANGLEResources); + + ::glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + ::glEnable(GL_POINT_SPRITE); + ::glClearColor(0, 0, 0, 0); +} + +GraphicsContext3D::~GraphicsContext3D() +{ + GraphicsContext3DInternal::removeActiveGraphicsContext(this); + if (!m_internal->m_context) + return; + + makeContextCurrent(); + ::glDeleteTextures(1, &m_texture); + if (m_attrs.antialias) { + ::glDeleteRenderbuffersEXT(1, &m_multisampleColorBuffer); + if (m_attrs.stencil || m_attrs.depth) + ::glDeleteRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer); + ::glDeleteFramebuffersEXT(1, &m_multisampleFBO); + } else { + if (m_attrs.stencil || m_attrs.depth) + ::glDeleteRenderbuffersEXT(1, &m_depthStencilBuffer); + } + ::glDeleteFramebuffersEXT(1, &m_fbo); +} + +void GraphicsContext3D::makeContextCurrent() +{ + if (!m_internal) + return; + m_internal->makeContextCurrent(); +} + +PlatformGraphicsContext3D GraphicsContext3D::platformGraphicsContext3D() +{ + return m_internal->m_context; +} + +bool GraphicsContext3D::isGLES2Compliant() const +{ + return false; +} + +} + +#endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/gtk/GraphicsContext3DInternal.cpp b/Source/WebCore/platform/graphics/gtk/GraphicsContext3DInternal.cpp new file mode 100644 index 0000000..de24554 --- /dev/null +++ b/Source/WebCore/platform/graphics/gtk/GraphicsContext3DInternal.cpp @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2011 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * 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; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "GraphicsContext3DInternal.h" + +#if ENABLE(WEBGL) + +#include "GraphicsContext3D.h" +#include "OpenGLShims.h" +#include <GL/glx.h> +#include <dlfcn.h> + +// We do not want to call glXMakeContextCurrent using different Display pointers, +// because it might lead to crashes in some drivers (fglrx). We use a shared display +// pointer here. +static Display* gSharedDisplay = 0; +static Display* sharedDisplay() +{ + if (!gSharedDisplay) + gSharedDisplay = XOpenDisplay(0); + return gSharedDisplay; +} + +namespace WebCore { + +// Because of driver bugs, exiting the program when there are active pbuffers +// can crash the X server (this has been observed with the official Nvidia drivers). +// We need to ensure that we clean everything up on exit. There are several reasons +// that GraphicsContext3Ds will still be alive at exit, including user error (memory +// leaks) and the page cache. In any case, we don't want the X server to crash. +static bool cleaningUpAtExit = false; +static Vector<GraphicsContext3D*>& activeGraphicsContexts() +{ + DEFINE_STATIC_LOCAL(Vector<GraphicsContext3D*>, contexts, ()); + return contexts; +} + +void GraphicsContext3DInternal::addActiveGraphicsContext(GraphicsContext3D* context) +{ + static bool addedAtExitHandler = false; + if (!addedAtExitHandler) { + atexit(&GraphicsContext3DInternal::cleanupActiveContextsAtExit); + addedAtExitHandler = true; + } + activeGraphicsContexts().append(context); +} + +void GraphicsContext3DInternal::removeActiveGraphicsContext(GraphicsContext3D* context) +{ + if (cleaningUpAtExit) + return; + + Vector<GraphicsContext3D*>& contexts = activeGraphicsContexts(); + size_t location = contexts.find(context); + if (location != WTF::notFound) + contexts.remove(location); +} + +void GraphicsContext3DInternal::cleanupActiveContextsAtExit() +{ + cleaningUpAtExit = true; + + Vector<GraphicsContext3D*>& contexts = activeGraphicsContexts(); + for (size_t i = 0; i < contexts.size(); i++) + contexts[i]->~GraphicsContext3D(); + + if (!gSharedDisplay) + return; + XCloseDisplay(gSharedDisplay); + gSharedDisplay = 0; +} + +GraphicsContext3DInternal* GraphicsContext3DInternal::create() +{ + if (!sharedDisplay()) + return 0; + + static bool initialized = false; + static bool success = true; + if (!initialized) { + success = initializeOpenGLShims(); + initialized = true; + } + if (!success) + return 0; + + GraphicsContext3DInternal* internal = createPbufferContext(); + if (!internal) + internal = createPixmapContext(); + if (!internal) + return 0; + + // The GraphicsContext3D constructor requires that this context is the current OpenGL context. + internal->makeContextCurrent(); + return internal; +} + +GraphicsContext3DInternal* GraphicsContext3DInternal::createPbufferContext() +{ + int fbConfigAttributes[] = { + GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_ALPHA_SIZE, 1, + GLX_DEPTH_SIZE, 1, + GLX_STENCIL_SIZE, 1, + GLX_SAMPLE_BUFFERS, 1, + GLX_DOUBLEBUFFER, GL_FALSE, + GLX_SAMPLES, 4, + 0 + }; + int returnedElements; + GLXFBConfig* configs = glXChooseFBConfig(sharedDisplay(), 0, fbConfigAttributes, &returnedElements); + if (!configs) { + fbConfigAttributes[20] = 0; // Attempt without anti-aliasing. + configs = glXChooseFBConfig(sharedDisplay(), 0, fbConfigAttributes, &returnedElements); + } + if (!returnedElements) { + XFree(configs); + return 0; + } + + // We will be rendering to a texture, so our pbuffer does not need to be large. + static const int pbufferAttributes[] = { GLX_PBUFFER_WIDTH, 1, GLX_PBUFFER_HEIGHT, 1, 0 }; + GLXPbuffer pbuffer = glXCreatePbuffer(sharedDisplay(), configs[0], pbufferAttributes); + if (!pbuffer) { + XFree(configs); + return 0; + } + + GLXContext context = glXCreateNewContext(sharedDisplay(), configs[0], GLX_RGBA_TYPE, 0, GL_TRUE); + XFree(configs); + if (!context) + return 0; + return new GraphicsContext3DInternal(context, pbuffer); +} + +GraphicsContext3DInternal* GraphicsContext3DInternal::createPixmapContext() +{ + static int visualAttributes[] = { + GLX_RGBA, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_ALPHA_SIZE, 1, + GLX_DOUBLEBUFFER, + 0 + }; + + XVisualInfo* visualInfo = glXChooseVisual(sharedDisplay(), DefaultScreen(sharedDisplay()), visualAttributes); + if (!visualInfo) + return 0; + + GLXContext context = glXCreateContext(sharedDisplay(), visualInfo, 0, GL_TRUE); + if (!context) { + XFree(visualInfo); + return 0; + } + + Pixmap pixmap = XCreatePixmap(sharedDisplay(), DefaultRootWindow(sharedDisplay()), 1, 1, visualInfo->depth); + if (!pixmap) { + XFree(visualInfo); + return 0; + } + + GLXPixmap glxPixmap = glXCreateGLXPixmap(sharedDisplay(), visualInfo, pixmap); + if (!glxPixmap) { + XFreePixmap(sharedDisplay(), pixmap); + XFree(visualInfo); + return 0; + } + + return new GraphicsContext3DInternal(context, pixmap, glxPixmap); +} + +GraphicsContext3DInternal::GraphicsContext3DInternal(GLXContext context, GLXPbuffer pbuffer) + : m_context(context) + , m_pbuffer(pbuffer) + , m_pixmap(0) + , m_glxPixmap(0) +{ +} + +GraphicsContext3DInternal::GraphicsContext3DInternal(GLXContext context, Pixmap pixmap, GLXPixmap glxPixmap) + : m_context(context) + , m_pbuffer(0) + , m_pixmap(pixmap) + , m_glxPixmap(glxPixmap) +{ +} + +GraphicsContext3DInternal::~GraphicsContext3DInternal() +{ + if (m_context) { + // This may be necessary to prevent crashes with NVidia's closed source drivers. Originally + // from Mozilla's 3D canvas implementation at: http://bitbucket.org/ilmari/canvas3d/ + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + ::glXMakeContextCurrent(sharedDisplay(), 0, 0, 0); + ::glXDestroyContext(sharedDisplay(), m_context); + m_context = 0; + } + + if (m_pbuffer) { + ::glXDestroyPbuffer(sharedDisplay(), m_pbuffer); + m_pbuffer = 0; + } + if (m_glxPixmap) { + glXDestroyGLXPixmap(sharedDisplay(), m_glxPixmap); + m_glxPixmap = 0; + } + if (m_pixmap) { + XFreePixmap(sharedDisplay(), m_pixmap); + m_pixmap = 0; + } +} + +void GraphicsContext3DInternal::makeContextCurrent() +{ + if (::glXGetCurrentContext() == m_context) + return; + if (!m_context) + return; + if (m_pbuffer) { + ::glXMakeCurrent(sharedDisplay(), m_pbuffer, m_context); + return; + } + + ASSERT(m_glxPixmap); + ::glXMakeCurrent(sharedDisplay(), m_glxPixmap, m_context); +} + +} // namespace WebCore + +#endif // ENABLE_WEBGL diff --git a/Source/WebCore/platform/graphics/gtk/GraphicsContext3DInternal.h b/Source/WebCore/platform/graphics/gtk/GraphicsContext3DInternal.h new file mode 100644 index 0000000..f4a60d9 --- /dev/null +++ b/Source/WebCore/platform/graphics/gtk/GraphicsContext3DInternal.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2011 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * 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; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GraphicsContext3DInternal_h +#define GraphicsContext3DInternal_h + +typedef struct __GLXcontextRec *GLXContext; +typedef unsigned long GLXPbuffer; +typedef unsigned long GLXPixmap; +typedef unsigned char GLubyte; +typedef unsigned long Pixmap; + +namespace WebCore { + +class GraphicsContext3D; + +class GraphicsContext3DInternal { + public: + static GraphicsContext3DInternal* create(); + ~GraphicsContext3DInternal(); + void makeContextCurrent(); + + private: + friend class GraphicsContext3D; + static GraphicsContext3DInternal* createPbufferContext(); + static GraphicsContext3DInternal* createPixmapContext(); + GraphicsContext3DInternal(GLXContext, GLXPbuffer); + GraphicsContext3DInternal(GLXContext, Pixmap, GLXPixmap); + + static void addActiveGraphicsContext(GraphicsContext3D*); + static void removeActiveGraphicsContext(GraphicsContext3D*); + static void cleanupActiveContextsAtExit(); + + GLXContext m_context; + GLXPbuffer m_pbuffer; + Pixmap m_pixmap; + GLXPixmap m_glxPixmap; +}; + +} + +#endif // GraphicsContext3DIternal_h diff --git a/Source/WebCore/platform/graphics/haiku/ImageBufferData.h b/Source/WebCore/platform/graphics/haiku/ImageBufferDataHaiku.h index 7c676cd..10285fc 100644 --- a/Source/WebCore/platform/graphics/haiku/ImageBufferData.h +++ b/Source/WebCore/platform/graphics/haiku/ImageBufferDataHaiku.h @@ -25,9 +25,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ImageBufferData_h -#define ImageBufferData_h - #include <Bitmap.h> #include <View.h> @@ -45,6 +42,3 @@ public: }; } // namespace WebCore - -#endif // ImageBufferData_h - diff --git a/Source/WebCore/platform/graphics/mac/ComplexTextController.h b/Source/WebCore/platform/graphics/mac/ComplexTextController.h index 44a7994..281e49f 100644 --- a/Source/WebCore/platform/graphics/mac/ComplexTextController.h +++ b/Source/WebCore/platform/graphics/mac/ComplexTextController.h @@ -116,9 +116,6 @@ private: static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef, URefCon, void*, ATSULayoutOperationCallbackStatus*); #endif -#if USE(CORE_TEXT) - RetainPtr<CTRunRef> m_coreTextRun; -#endif unsigned m_glyphCount; const SimpleFontData* m_fontData; const UChar* m_characters; @@ -159,6 +156,10 @@ private: Vector<UChar, 256> m_smallCapsBuffer; +#if USE(CORE_TEXT) + // Retain lines rather than their runs for better performance. + Vector<RetainPtr<CTLineRef> > m_coreTextLines; +#endif Vector<RefPtr<ComplexTextRun>, 16> m_complexTextRuns; Vector<CGSize, 256> m_adjustedAdvances; Vector<CGGlyph, 256> m_adjustedGlyphs; diff --git a/Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp b/Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp index d2fbaf5..1473b1e 100644 --- a/Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp +++ b/Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp @@ -43,33 +43,32 @@ extern const CFStringRef kCTTypesetterOptionForcedEmbeddingLevel; namespace WebCore { ComplexTextController::ComplexTextRun::ComplexTextRun(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, CFRange runRange) - : m_coreTextRun(ctRun) - , m_fontData(fontData) + : m_fontData(fontData) , m_characters(characters) , m_stringLocation(stringLocation) , m_stringLength(stringLength) , m_indexEnd(runRange.location + runRange.length) , m_isMonotonic(true) { - m_glyphCount = CTRunGetGlyphCount(m_coreTextRun.get()); - m_coreTextIndices = CTRunGetStringIndicesPtr(m_coreTextRun.get()); + m_glyphCount = CTRunGetGlyphCount(ctRun); + m_coreTextIndices = CTRunGetStringIndicesPtr(ctRun); if (!m_coreTextIndices) { m_coreTextIndicesVector.grow(m_glyphCount); - CTRunGetStringIndices(m_coreTextRun.get(), CFRangeMake(0, 0), m_coreTextIndicesVector.data()); + CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), m_coreTextIndicesVector.data()); m_coreTextIndices = m_coreTextIndicesVector.data(); } - m_glyphs = CTRunGetGlyphsPtr(m_coreTextRun.get()); + m_glyphs = CTRunGetGlyphsPtr(ctRun); if (!m_glyphs) { m_glyphsVector.grow(m_glyphCount); - CTRunGetGlyphs(m_coreTextRun.get(), CFRangeMake(0, 0), m_glyphsVector.data()); + CTRunGetGlyphs(ctRun, CFRangeMake(0, 0), m_glyphsVector.data()); m_glyphs = m_glyphsVector.data(); } - m_advances = CTRunGetAdvancesPtr(m_coreTextRun.get()); + m_advances = CTRunGetAdvancesPtr(ctRun); if (!m_advances) { m_advancesVector.grow(m_glyphCount); - CTRunGetAdvances(m_coreTextRun.get(), CFRangeMake(0, 0), m_advancesVector.data()); + CTRunGetAdvances(ctRun, CFRangeMake(0, 0), m_advancesVector.data()); m_advances = m_advancesVector.data(); } } @@ -159,6 +158,8 @@ void ComplexTextController::collectComplexTextRunsForCharactersCoreText(const UC line.adoptCF(wkCreateCTLineWithUniCharProvider(&provideStringAndAttributes, 0, &info)); } + m_coreTextLines.append(line.get()); + CFArrayRef runArray = CTLineGetGlyphRuns(line.get()); CFIndex runCount = CFArrayGetCount(runArray); diff --git a/Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm b/Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm index 997c976..2a469a7 100644 --- a/Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm +++ b/Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm @@ -90,8 +90,8 @@ PassRefPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attri GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow, bool) : m_currentWidth(0) , m_currentHeight(0) - , m_attrs(attrs) , m_contextObj(0) + , m_attrs(attrs) , m_texture(0) , m_compositorTexture(0) , m_fbo(0) diff --git a/Source/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/Source/WebCore/platform/graphics/mac/SimpleFontDataMac.mm index cd34000..f34d53b 100644 --- a/Source/WebCore/platform/graphics/mac/SimpleFontDataMac.mm +++ b/Source/WebCore/platform/graphics/mac/SimpleFontDataMac.mm @@ -241,6 +241,7 @@ void SimpleFontData::platformInit() NSString *familyName = [m_platformData.font() familyName]; if ([familyName isEqualToString:@"Times"] || [familyName isEqualToString:@"Helvetica"] || [familyName isEqualToString:@"Courier"]) ascent += floorf(((ascent + descent) * 0.15f) + 0.5f); +#if defined(BUILDING_ON_LEOPARD) else if ([familyName isEqualToString:@"Geeza Pro"]) { // Geeza Pro has glyphs that draw slightly above the ascent or far below the descent. Adjust // those vertical metrics to better match reality, so that diacritics at the bottom of one line @@ -248,6 +249,7 @@ void SimpleFontData::platformInit() ascent *= 1.08f; descent *= 2.f; } +#endif // Compute and store line spacing, before the line metrics hacks are applied. m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap)); diff --git a/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp b/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp index e09534e..4c7164e 100644 --- a/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp +++ b/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp @@ -35,6 +35,8 @@ #if PLATFORM(MAC) #include "ANGLE/ShaderLang.h" #include <OpenGL/gl.h> +#elif PLATFORM(GTK) +#include "OpenGLShims.h" #endif namespace WebCore { @@ -116,6 +118,17 @@ void Extensions3DOpenGL::ensureEnabled(const String& name) #endif } +bool Extensions3DOpenGL::isEnabled(const String& name) +{ +#if PLATFORM(MAC) + if (name == "GL_OES_standard_derivatives") { + ANGLEWebKitBridge& compiler = m_context->m_compiler; + return compiler.getResources().OES_standard_derivatives; + } +#endif + return supports(name); +} + int Extensions3DOpenGL::getGraphicsResetStatusARB() { return GraphicsContext3D::NO_ERROR; @@ -134,7 +147,7 @@ void Extensions3DOpenGL::renderbufferStorageMultisample(unsigned long target, un Platform3DObject Extensions3DOpenGL::createVertexArrayOES() { m_context->makeContextCurrent(); -#if defined GL_APPLE_vertex_array_object && GL_APPLE_vertex_array_object +#if !PLATFORM(GTK) && defined(GL_APPLE_vertex_array_object) && GL_APPLE_vertex_array_object GLuint array = 0; glGenVertexArraysAPPLE(1, &array); return array; @@ -149,7 +162,7 @@ void Extensions3DOpenGL::deleteVertexArrayOES(Platform3DObject array) return; m_context->makeContextCurrent(); -#if defined GL_APPLE_vertex_array_object && GL_APPLE_vertex_array_object +#if !PLATFORM(GTK) && defined(GL_APPLE_vertex_array_object) && GL_APPLE_vertex_array_object glDeleteVertexArraysAPPLE(1, &array); #endif } @@ -160,7 +173,7 @@ GC3Dboolean Extensions3DOpenGL::isVertexArrayOES(Platform3DObject array) return GL_FALSE; m_context->makeContextCurrent(); -#if defined GL_APPLE_vertex_array_object && GL_APPLE_vertex_array_object +#if !PLATFORM(GTK) && defined(GL_APPLE_vertex_array_object) && GL_APPLE_vertex_array_object return glIsVertexArrayAPPLE(array); #else return GL_FALSE; @@ -173,7 +186,7 @@ void Extensions3DOpenGL::bindVertexArrayOES(Platform3DObject array) return; m_context->makeContextCurrent(); -#if defined GL_APPLE_vertex_array_object && GL_APPLE_vertex_array_object +#if !PLATFORM(GTK) && defined(GL_APPLE_vertex_array_object) && GL_APPLE_vertex_array_object glBindVertexArrayAPPLE(array); #endif } diff --git a/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.h b/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.h index 9188507..e545fbc 100644 --- a/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.h +++ b/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.h @@ -41,6 +41,7 @@ public: // Extensions3D methods. virtual bool supports(const String&); virtual void ensureEnabled(const String&); + virtual bool isEnabled(const String&); virtual int getGraphicsResetStatusARB(); virtual void blitFramebuffer(long srcX0, long srcY0, long srcX1, long srcY1, long dstX0, long dstY0, long dstX1, long dstY1, unsigned long mask, unsigned long filter); virtual void renderbufferStorageMultisample(unsigned long target, unsigned long samples, unsigned long internalformat, unsigned long width, unsigned long height); diff --git a/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp b/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp index f831550..af46293 100644 --- a/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp +++ b/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp @@ -42,14 +42,16 @@ #include "Int32Array.h" #include "NotImplemented.h" #include "Uint8Array.h" +#include <cstring> +#include <wtf/UnusedParam.h> +#include <wtf/text/CString.h> #if PLATFORM(MAC) #include <OpenGL/gl.h> +#elif PLATFORM(GTK) +#include "OpenGLShims.h" #endif -#include <wtf/UnusedParam.h> -#include <wtf/text/CString.h> - namespace WebCore { void GraphicsContext3D::validateAttributes() @@ -163,7 +165,7 @@ PassRefPtr<ImageData> GraphicsContext3D::paintRenderingResultsToImageData() void GraphicsContext3D::reshape(int width, int height) { - if (!m_contextObj) + if (!platformGraphicsContext3D()) return; if (width == m_currentWidth && height == m_currentHeight) diff --git a/Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp b/Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp index 9765937..1493966 100644 --- a/Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp +++ b/Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp @@ -388,7 +388,7 @@ void TextureMapperGL::drawTexture(const BitmapTexture& texture, const IntRect& t GL_CMD(glBindTexture(GL_TEXTURE_2D, textureGL.m_id)) GL_CMD(glBindBuffer(GL_ARRAY_BUFFER, 0)) const GLfloat unitRect[] = {0, 0, 1, 0, 1, 1, 0, 1}; - GL_CMD(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, unitRect)) + GL_CMD(glVertexAttribPointer(gInVertexAttributeIndex, 2, GL_FLOAT, GL_FALSE, 0, unitRect)) TransformationMatrix matrix = TransformationMatrix(data().projectionMatrix).multiply(modelViewMatrix).multiply(TransformationMatrix( targetRect.width(), 0, 0, 0, @@ -641,7 +641,7 @@ void TextureMapperGL::paintToTarget(const BitmapTexture& aSurface, const IntSize GL_CMD(glUniformMatrix4fv(programInfo.vars[TextureMapperGLData::ShaderInfo::InSourceMatrixVariable], 1, GL_FALSE, m4src)) GL_CMD(glBindBuffer(GL_ARRAY_BUFFER, 0)) const GLfloat unitRect[] = {0, 0, 1, 0, 1, 1, 0, 1}; - GL_CMD(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, unitRect)) + GL_CMD(glVertexAttribPointer(gInVertexAttributeIndex, 2, GL_FLOAT, GL_FALSE, 0, unitRect)) GL_CMD(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)) GL_CMD(glEnable(GL_BLEND)) setClip(visibleRect); diff --git a/Source/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp b/Source/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp index 7f4547d..6afe3d9 100644 --- a/Source/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp +++ b/Source/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp @@ -70,7 +70,7 @@ struct TableDirectoryEntry { BigEndianULong length; }; -#if !PLATFORM(CG) || !defined(COREGRAPHICS_INCLUDES_CORESERVICES_HEADER) +#if !USE(CG) || !defined(COREGRAPHICS_INCLUDES_CORESERVICES_HEADER) // Fixed type is not defined on non-CG and Windows platforms. |version| in sfntHeader // and headTable and |fontRevision| in headTable are of Fixed, but they're // not actually refered to anywhere. Therefore, we just have to match diff --git a/Source/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp b/Source/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp index 75dbadb..1595692 100644 --- a/Source/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp +++ b/Source/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp @@ -257,7 +257,7 @@ void GraphicsContext::drawLineForTextChecking(const IntPoint& origin, int width, UNUSED_PARAM(style); } -FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect, RoundingMode) { if (paintingDisabled()) return FloatRect(); diff --git a/Source/WebCore/platform/graphics/pango/FontPlatformData.h b/Source/WebCore/platform/graphics/pango/FontPlatformData.h index 180d23b..bd9251b 100644 --- a/Source/WebCore/platform/graphics/pango/FontPlatformData.h +++ b/Source/WebCore/platform/graphics/pango/FontPlatformData.h @@ -68,6 +68,7 @@ public: bool syntheticOblique() const { return m_syntheticOblique; } FontOrientation orientation() const { return Horizontal; } // FIXME: Implement. + void setOrientation(FontOrientation) { } // FIXME: Implement. cairo_scaled_font_t* scaledFont() const { return m_scaledFont; } diff --git a/Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp b/Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp index 3adc93f..45d5e9c 100644 --- a/Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp +++ b/Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp @@ -52,6 +52,11 @@ void Extensions3DQt::ensureEnabled(const String& name) ASSERT(supports(name)); } +bool Extensions3DQt::isEnabled(const String& name) +{ + return supports(name); +} + int Extensions3DQt::getGraphicsResetStatusARB() { return GraphicsContext3D::NO_ERROR; diff --git a/Source/WebCore/platform/graphics/qt/Extensions3DQt.h b/Source/WebCore/platform/graphics/qt/Extensions3DQt.h index c67fbed..1bc47b8 100644 --- a/Source/WebCore/platform/graphics/qt/Extensions3DQt.h +++ b/Source/WebCore/platform/graphics/qt/Extensions3DQt.h @@ -37,6 +37,7 @@ public: // Extensions3D methods. virtual bool supports(const String&); virtual void ensureEnabled(const String&); + virtual bool isEnabled(const String&); virtual int getGraphicsResetStatusARB(); virtual void blitFramebuffer(long srcX0, long srcY0, long srcX1, long srcY1, long dstX0, long dstY0, long dstX1, long dstY1, unsigned long mask, unsigned long filter); virtual void renderbufferStorageMultisample(unsigned long target, unsigned long samples, unsigned long internalformat, unsigned long width, unsigned long height); diff --git a/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp b/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp index 4daa4dc..e92f927 100644 --- a/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp +++ b/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp @@ -447,6 +447,12 @@ GraphicsContext3DInternal::GraphicsContext3DInternal(GraphicsContext3D::Attribut GraphicsContext3DInternal::~GraphicsContext3DInternal() { + m_glWidget->makeCurrent(); + if (m_glWidget->isValid()) { + ::glDeleteTextures(1, &m_texture); + deleteRenderbuffers(1, &m_depthBuffer); + deleteFramebuffers(1, &m_canvasFbo); + } delete m_glWidget; m_glWidget = 0; } @@ -588,7 +594,7 @@ void* GraphicsContext3DInternal::getProcAddress(const String& proc) for (int i = 0; i < 3; i++) { String nameWithExt = proc + ext[i]; - void* addr = m_glWidget->context()->getProcAddress(nameWithExt.utf8().data()); + void* addr = m_glWidget->context()->getProcAddress(QString(nameWithExt)); if (addr) return addr; } @@ -656,7 +662,7 @@ PassRefPtr<ImageData> GraphicsContext3D::paintRenderingResultsToImageData() void GraphicsContext3D::reshape(int width, int height) { - if (width == m_currentWidth && height == m_currentHeight || (!m_internal)) + if ((width == m_currentWidth && height == m_currentHeight) || (!m_internal)) return; m_currentWidth = width; diff --git a/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp index e3e0fa6..a3a08eb 100644 --- a/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp +++ b/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -900,7 +900,7 @@ void GraphicsContext::drawLineForTextChecking(const FloatPoint&, float, TextChec notImplemented(); } -FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect, RoundingMode) { // It is not enough just to round to pixels in device space. The rotation part of the // affine transform matrix to device space can mess with this conversion if we have a diff --git a/Source/WebCore/platform/graphics/qt/ImageBufferData.h b/Source/WebCore/platform/graphics/qt/ImageBufferDataQt.h index 602197e..8b49829 100644 --- a/Source/WebCore/platform/graphics/qt/ImageBufferData.h +++ b/Source/WebCore/platform/graphics/qt/ImageBufferDataQt.h @@ -23,16 +23,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ImageBufferData_h -#define ImageBufferData_h - #include "Image.h" -#include <wtf/RefPtr.h> +#include "OwnPtr.h" #include <QPainter> #include <QPixmap> - -#include "OwnPtr.h" +#include <wtf/RefPtr.h> namespace WebCore { @@ -49,6 +45,4 @@ public: RefPtr<Image> m_image; }; -} // namespace WebCore - -#endif // ImageBufferData_h +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp index bc43acf..e7efdf9 100644 --- a/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp +++ b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp @@ -84,7 +84,17 @@ MediaPlayer::SupportsType MediaPlayerPrivateQt::supportsType(const String& mime, if (!mime.startsWith("audio/") && !mime.startsWith("video/")) return MediaPlayer::IsNotSupported; - if (QMediaPlayer::hasSupport(mime, QStringList(codec)) >= QtMultimediaKit::ProbablySupported) + // Parse and trim codecs. + QString codecStr = codec; + QStringList codecList = codecStr.split(QLatin1Char(','), QString::SkipEmptyParts); + QStringList codecListTrimmed; + foreach (const QString& codecStrNotTrimmed, codecList) { + QString codecStrTrimmed = codecStrNotTrimmed.trimmed(); + if (!codecStrTrimmed.isEmpty()) + codecListTrimmed.append(codecStrTrimmed); + } + + if (QMediaPlayer::hasSupport(mime, codecListTrimmed) >= QtMultimediaKit::ProbablySupported) return MediaPlayer::IsSupported; return MediaPlayer::MayBeSupported; diff --git a/Source/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp b/Source/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp index 5d0b302..9bf1030 100644 --- a/Source/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp +++ b/Source/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2008, 2009, 2010, 2011 Nokia Corporation and/or its subsidiary(-ies) Copyright (C) 2008 Holger Hans Peter Freyther This library is free software; you can redistribute it and/or @@ -48,11 +48,29 @@ void SimpleFontData::platformInit() } QFontMetricsF fm(m_platformData.font()); - m_fontMetrics.setAscent(fm.ascent()); - m_fontMetrics.setDescent(fm.descent()); + + // Qt subtracts 1 from the descent to account for the baseline, + // we add it back here to get correct metrics for WebKit. + float descent = fm.descent() + 1; + float ascent = fm.ascent(); + + float lineSpacing = fm.lineSpacing(); + + // The line spacing should always be >= (ascent + descent), but this + // may be false in some cases due to misbehaving platform libraries. + // Workaround from SimpleFontPango.cpp and SimpleFontFreeType.cpp + if (lineSpacing < ascent + descent) + lineSpacing = ascent + descent; + + // QFontMetricsF::leading() may return negative values on platforms + // such as FreeType. Calculate the line gap manually instead. + float lineGap = lineSpacing - ascent - descent; + + m_fontMetrics.setAscent(ascent); + m_fontMetrics.setDescent(descent); + m_fontMetrics.setLineSpacing(lineSpacing); m_fontMetrics.setXHeight(fm.xHeight()); - m_fontMetrics.setLineGap(fm.leading()); - m_fontMetrics.setLineSpacing(fm.lineSpacing()); + m_fontMetrics.setLineGap(lineGap); m_spaceWidth = fm.width(QLatin1Char(' ')); } diff --git a/Source/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp b/Source/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp index 5950c35..0fb44e7 100644 --- a/Source/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp @@ -30,6 +30,7 @@ #include "GraphicsContext3D.h" +#include "BitmapImage.h" #include "Image.h" #include "ImageSource.h" #include "NativeImageSkia.h" @@ -50,15 +51,17 @@ bool GraphicsContext3D::getImageData(Image* image, if (!image) return false; OwnPtr<NativeImageSkia> pixels; - NativeImageSkia* skiaImage = 0; + NativeImageSkia* skiaImage = image->nativeImageForCurrentFrame(); AlphaOp neededAlphaOp = AlphaDoNothing; - if (image->data()) { + bool hasAlpha = skiaImage ? !skiaImage->isOpaque() : true; + if ((!skiaImage || ignoreGammaAndColorProfile || (hasAlpha && !premultiplyAlpha)) && image->data()) { ImageSource decoder(ImageSource::AlphaNotPremultiplied, ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied); + // Attempt to get raw unpremultiplied image data decoder.setData(image->data(), true); if (!decoder.frameCount() || !decoder.frameIsCompleteAtIndex(0)) return false; - bool hasAlpha = decoder.frameHasAlphaAtIndex(0); + hasAlpha = decoder.frameHasAlphaAtIndex(0); pixels = adoptPtr(decoder.createFrameAtIndex(0)); if (!pixels.get() || !pixels->isDataComplete() || !pixels->width() || !pixels->height()) return false; @@ -68,12 +71,8 @@ bool GraphicsContext3D::getImageData(Image* image, skiaImage = pixels.get(); if (hasAlpha && premultiplyAlpha) neededAlphaOp = AlphaDoPremultiply; - } else { - // This is a special case for texImage2D with HTMLCanvasElement input. - skiaImage = image->nativeImageForCurrentFrame(); - if (!premultiplyAlpha) - neededAlphaOp = AlphaDoUnmultiply; - } + } else if (!premultiplyAlpha && hasAlpha) + neededAlphaOp = AlphaDoUnmultiply; if (!skiaImage) return false; SkBitmap& skiaImageRef = *skiaImage; diff --git a/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp index df680eb..f285c9b 100644 --- a/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp @@ -44,8 +44,10 @@ #include "PlatformContextSkia.h" #include "SkBitmap.h" -#include "SkBlurDrawLooper.h" +#include "SkBlurMaskFilter.h" +#include "SkColorFilter.h" #include "SkCornerPathEffect.h" +#include "SkLayerDrawLooper.h" #include "SkShader.h" #include "SkiaUtils.h" #include "skia/ext/platform_canvas.h" @@ -853,6 +855,7 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, SkPaint paint; platformContext()->setupPaintForFilling(&paint); + paint.setColor(color.rgb()); platformContext()->canvas()->drawPath(path, paint); } @@ -867,7 +870,7 @@ AffineTransform GraphicsContext::getCTM() const SkScalarToDouble(m.getTranslateY())); } -FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect, RoundingMode) { return rect; } @@ -1043,16 +1046,15 @@ void GraphicsContext::setPlatformShadow(const FloatSize& size, double height = size.height(); double blur = blurFloat; - uint32_t blurFlags = SkBlurDrawLooper::kHighQuality_BlurFlag | - SkBlurDrawLooper::kOverrideColor_BlurFlag; + uint32_t mfFlags = SkBlurMaskFilter::kHighQuality_BlurFlag; if (m_state.shadowsIgnoreTransforms) { // Currently only the GraphicsContext associated with the // CanvasRenderingContext for HTMLCanvasElement have shadows ignore // Transforms. So with this flag set, we know this state is associated // with a CanvasRenderingContext. - blurFlags |= SkBlurDrawLooper::kIgnoreTransform_BlurFlag; - + mfFlags |= SkBlurMaskFilter::kIgnoreTransform_BlurFlag; + // CG uses natural orientation for Y axis, but the HTML5 canvas spec // does not. // So we now flip the height since it was flipped in @@ -1068,9 +1070,32 @@ void GraphicsContext::setPlatformShadow(const FloatSize& size, // TODO(tc): Should we have a max value for the blur? CG clamps at 1000.0 // for perf reasons. - SkDrawLooper* dl = new SkBlurDrawLooper(blur / 2, width, height, c, blurFlags); + + SkLayerDrawLooper* dl = new SkLayerDrawLooper; + SkAutoUnref aur(dl); + + // top layer, we just draw unchanged + dl->addLayer(); + + // lower layer contains our offset, blur, and colorfilter + SkLayerDrawLooper::LayerInfo info; + + info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit; // our blur + info.fPaintBits |= SkLayerDrawLooper::kColorFilter_Bit; + info.fColorMode = SkXfermode::kDst_Mode; + info.fOffset.set(width, height); + info.fPostTranslate = m_state.shadowsIgnoreTransforms; + + SkMaskFilter* mf = SkBlurMaskFilter::Create(blur / 2, SkBlurMaskFilter::kNormal_BlurStyle, mfFlags); + + SkColorFilter* cf = SkColorFilter::CreateModeFilter(c, SkXfermode::kSrcIn_Mode); + + SkPaint* paint = dl->addLayer(info); + SkSafeUnref(paint->setMaskFilter(mf)); + SkSafeUnref(paint->setColorFilter(cf)); + + // dl is now built, just install it platformContext()->setDrawLooper(dl); - dl->unref(); } void GraphicsContext::setPlatformStrokeColor(const Color& strokecolor, ColorSpace colorSpace) diff --git a/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp index b89c68d..2352672 100644 --- a/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp @@ -66,19 +66,21 @@ ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode, bool& s : m_data(size) , m_size(size) { - if (!m_data.m_canvas.initialize(size.width(), size.height(), false)) { + SkCanvas* canvas = skia::CreateBitmapCanvas(size.width(), size.height(), false); + if (!canvas) { success = false; return; } - m_data.m_platformContext.setCanvas(&m_data.m_canvas); + m_data.m_canvas = canvas; + m_data.m_platformContext.setCanvas(m_data.m_canvas.get()); m_context.set(new GraphicsContext(&m_data.m_platformContext)); m_context->platformContext()->setDrawingToImageBuffer(true); // Make the background transparent. It would be nice if this wasn't // required, but the canvas is currently filled with the magic transparency // color. Can we have another way to manage this? - m_data.m_canvas.drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode); + m_data.m_canvas->drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode); success = true; } @@ -117,6 +119,7 @@ void ImageBuffer::draw(GraphicsContext* context, ColorSpace styleColorSpace, con { if (m_data.m_platformContext.useGPU() && context->platformContext()->useGPU()) { if (context->platformContext()->canAccelerate()) { + m_data.m_platformContext.prepareForHardwareDraw(); DrawingBuffer* sourceDrawingBuffer = m_data.m_platformContext.gpuCanvas()->drawingBuffer(); unsigned sourceTexture = static_cast<unsigned>(sourceDrawingBuffer->platformColorBuffer()); FloatRect destRectNormalized(normalizeRect(destRect)); @@ -344,6 +347,8 @@ void ImageBuffer::putPremultipliedImageData(ByteArray* source, const IntSize& so template <typename T> static String ImageToDataURL(T& source, const String& mimeType, const double* quality) { + ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType)); + Vector<unsigned char> encodedImage; if (mimeType == "image/jpeg") { int compressionQuality = JPEGImageEncoder::DefaultCompressionQuality; @@ -365,9 +370,6 @@ static String ImageToDataURL(T& source, const String& mimeType, const double* qu String ImageBuffer::toDataURL(const String& mimeType, const double* quality) const { - ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType)); - - Vector<unsigned char> encodedImage; SkDevice* device = context()->platformContext()->canvas()->getDevice(); SkBitmap bitmap = device->accessBitmap(false); diff --git a/Source/WebCore/platform/graphics/skia/ImageSkia.cpp b/Source/WebCore/platform/graphics/skia/ImageSkia.cpp index 72bec29..6987e00 100644 --- a/Source/WebCore/platform/graphics/skia/ImageSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/ImageSkia.cpp @@ -66,6 +66,7 @@ enum ResamplingMode { RESAMPLE_AWESOME, }; +#if !ENABLE(SKIA_GPU) static ResamplingMode computeResamplingMode(PlatformContextSkia* platformContext, const NativeImageSkia& bitmap, int srcWidth, int srcHeight, float destWidth, float destHeight) { if (platformContext->hasImageResamplingHint()) { @@ -150,6 +151,7 @@ static ResamplingMode computeResamplingMode(PlatformContextSkia* platformContext return RESAMPLE_LINEAR; } +#endif // Draws the given bitmap to the given canvas. The subset of the source bitmap // identified by src_rect is drawn to the given destination rect. The bitmap @@ -262,12 +264,17 @@ static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImag paint.setAlpha(platformContext->getNormalizedAlpha()); paint.setLooper(platformContext->getDrawLooper()); - skia::PlatformCanvas* canvas = platformContext->canvas(); + SkCanvas* canvas = platformContext->canvas(); - ResamplingMode resampling = platformContext->isPrinting() ? RESAMPLE_NONE : + ResamplingMode resampling; +#if ENABLE(SKIA_GPU) + resampling = RESAMPLE_LINEAR; +#else + resampling = platformContext->printing() ? RESAMPLE_NONE : computeResamplingMode(platformContext, bitmap, srcRect.width(), srcRect.height(), SkScalarToFloat(destRect.width()), SkScalarToFloat(destRect.height())); +#endif if (resampling == RESAMPLE_AWESOME) { drawResampledBitmap(*canvas, paint, bitmap, srcRect, destRect); } else { @@ -363,13 +370,17 @@ void Image::drawPattern(GraphicsContext* context, // Compute the resampling mode. ResamplingMode resampling; - if (context->platformContext()->isPrinting()) +#if ENABLE(SKIA_GPU) + resampling = RESAMPLE_LINEAR; +#else + if (context->platformContext()->printing()) resampling = RESAMPLE_LINEAR; else { resampling = computeResamplingMode(context->platformContext(), *bitmap, srcRect.width(), srcRect.height(), destBitmapWidth, destBitmapHeight); } +#endif // Load the transform WebKit requested. SkMatrix matrix(patternTransform); diff --git a/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp index 8e1937f..4cc5457 100644 --- a/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp @@ -213,8 +213,9 @@ SkColor PlatformContextSkia::State::applyAlpha(SkColor c) const // PlatformContextSkia --------------------------------------------------------- // Danger: canvas can be NULL. -PlatformContextSkia::PlatformContextSkia(skia::PlatformCanvas* canvas) +PlatformContextSkia::PlatformContextSkia(SkCanvas* canvas) : m_canvas(canvas) + , m_printing(false) , m_drawingToImageBuffer(false) , m_useGPU(false) #if ENABLE(ACCELERATED_2D_CANVAS) @@ -232,15 +233,18 @@ PlatformContextSkia::~PlatformContextSkia() if (m_gpuCanvas) { #if ENABLE(SKIA_GPU) // make sure everything related to this platform context has been flushed - if (!m_useGPU) - m_gpuCanvas->context()->grContext()->flush(0); + if (!m_useGPU) { + SharedGraphicsContext3D* context = m_gpuCanvas->context(); + context->makeContextCurrent(); + context->grContext()->flush(0); + } #endif m_gpuCanvas->drawingBuffer()->setWillPublishCallback(0); } #endif } -void PlatformContextSkia::setCanvas(skia::PlatformCanvas* canvas) +void PlatformContextSkia::setCanvas(SkCanvas* canvas) { m_canvas = canvas; } @@ -609,12 +613,12 @@ const SkBitmap* PlatformContextSkia::bitmap() const return &m_canvas->getDevice()->accessBitmap(false); } -bool PlatformContextSkia::isPrinting() +bool PlatformContextSkia::isNativeFontRenderingAllowed() { #if ENABLE(SKIA_GPU) - return true; + return false; #else - return m_canvas->getTopPlatformDevice().IsVectorial(); + return skia::SupportsPlatformPaint(m_canvas); #endif } @@ -738,7 +742,12 @@ void PlatformContextSkia::setSharedGraphicsContext3D(SharedGraphicsContext3D* co gr->resetContext(); drawingBuffer->setGrContext(gr); - SkDeviceFactory* factory = new SkGpuDeviceFactory(gr, SkGpuDevice::Current3DApiRenderTarget()); + GrPlatformSurfaceDesc drawBufDesc; + drawingBuffer->getGrPlatformSurfaceDesc(&drawBufDesc); + GrTexture* drawBufTex = static_cast<GrTexture*>(gr->createPlatformSurface(drawBufDesc)); + SkDeviceFactory* factory = new SkGpuDeviceFactory(gr, drawBufTex); + drawBufTex->unref(); + SkDevice* device = factory->newDevice(m_canvas, SkBitmap::kARGB_8888_Config, drawingBuffer->size().width(), drawingBuffer->size().height(), false, false); m_canvas->setDevice(device)->unref(); m_canvas->setDeviceFactory(factory); diff --git a/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h b/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h index d7dd6a9..fc82221 100644 --- a/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h +++ b/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h @@ -72,12 +72,12 @@ class PlatformContextSkia { public: // For printing, there shouldn't be any canvas. canvas can be NULL. If you // supply a NULL canvas, you can also call setCanvas later. - PlatformContextSkia(skia::PlatformCanvas*); + PlatformContextSkia(SkCanvas*); ~PlatformContextSkia(); // Sets the canvas associated with this context. Use when supplying NULL // to the constructor. - void setCanvas(skia::PlatformCanvas*); + void setCanvas(SkCanvas*); // If false we're rendering to a GraphicsContext for a web page, if false // we're not (as is the case when rendering to a canvas object). @@ -146,7 +146,8 @@ public: // by the current alpha. SkColor effectiveStrokeColor() const; - skia::PlatformCanvas* canvas() { return m_canvas; } + // Returns the canvas used for painting, NOT guaranteed to be non-null. + SkCanvas* canvas() { return m_canvas; } InterpolationQuality interpolationQuality() const; void setInterpolationQuality(InterpolationQuality interpolationQuality); @@ -159,17 +160,16 @@ public: const SkBitmap* bitmap() const; - // Returns the canvas used for painting, NOT guaranteed to be non-NULL. - // - // Warning: This function is deprecated so the users are reminded that they - // should use this layer of indirection instead of using the canvas - // directly. This is to help with the eventual serialization. - skia::PlatformCanvas* canvas() const; - // Returns if the context is a printing context instead of a display // context. Bitmap shouldn't be resampled when printing to keep the best // possible quality. - bool isPrinting(); + bool printing() const { return m_printing; } + void setPrinting(bool p) { m_printing = p; } + + // Returns if the context allows rendering of fonts using native platform + // APIs. If false is returned font rendering is performed using the skia + // text drawing APIs. + bool isNativeFontRenderingAllowed(); void getImageResamplingHint(IntSize* srcSize, FloatSize* dstSize) const; void setImageResamplingHint(const IntSize& srcSize, const FloatSize& dstSize); @@ -186,10 +186,10 @@ public: GLES2Canvas* gpuCanvas() const { return 0; } #endif // Call these before making a call that manipulates the underlying - // skia::PlatformCanvas or WebCore::GLES2Canvas + // SkCanvas or WebCore::GLES2Canvas void prepareForSoftwareDraw() const; void prepareForHardwareDraw() const; - // Call to force the skia::PlatformCanvas to contain all rendering results. + // Call to force the SkCanvas to contain all rendering results. void syncSoftwareCanvas() const; void markDirtyRect(const IntRect& rect); @@ -206,7 +206,7 @@ private: struct State; // NULL indicates painting is disabled. Never delete this object. - skia::PlatformCanvas* m_canvas; + SkCanvas* m_canvas; // States stack. Enables local drawing state change with save()/restore() // calls. @@ -219,6 +219,7 @@ private: // Values are used in ImageSkia.cpp IntSize m_imageResamplingHintSrcSize; FloatSize m_imageResamplingHintDstSize; + bool m_printing; bool m_drawingToImageBuffer; bool m_useGPU; #if ENABLE(ACCELERATED_2D_CANVAS) diff --git a/Source/WebCore/platform/graphics/skia/SkiaFontWin.cpp b/Source/WebCore/platform/graphics/skia/SkiaFontWin.cpp index b0cb0c7..8ab823e 100644 --- a/Source/WebCore/platform/graphics/skia/SkiaFontWin.cpp +++ b/Source/WebCore/platform/graphics/skia/SkiaFontWin.cpp @@ -39,16 +39,11 @@ #include "SkPaint.h" #include "SkShader.h" #include "SkTemplates.h" -#include "SkTypeface.h" +#include "SkTypeface_win.h" #include <wtf/ListHashSet.h> #include <wtf/Vector.h> -#if ENABLE(SKIA_TEXT) -// FIXME: a future role of skia will have this in a proper header -extern SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT&); -#endif - namespace WebCore { struct CachedOutlineKey { @@ -235,11 +230,23 @@ bool windowsCanHandleDrawTextShadow(GraphicsContext *context) ColorSpace shadowColorSpace; bool hasShadow = context->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace); - return (hasShadow && (shadowBlur == 0) && (shadowColor.alpha() == 255) && (context->fillColor().alpha() == 255)); + return !hasShadow || (!shadowBlur && (shadowColor.alpha() == 255) && (context->fillColor().alpha() == 255)); } bool windowsCanHandleTextDrawing(GraphicsContext* context) { + if (!windowsCanHandleTextDrawingWithoutShadow(context)) + return false; + + // Check for shadow effects. + if (!windowsCanHandleDrawTextShadow(context)) + return false; + + return true; +} + +bool windowsCanHandleTextDrawingWithoutShadow(GraphicsContext* context) +{ // Check for non-translation transforms. Sometimes zooms will look better in // Skia, and sometimes better in Windows. The main problem is that zooming // in using Skia will show you the hinted outlines for the smaller size, @@ -261,8 +268,7 @@ bool windowsCanHandleTextDrawing(GraphicsContext* context) if (context->fillPattern() || context->strokePattern()) return false; - // Check for shadow effects. - if (context->platformContext()->getDrawLooper() && (!windowsCanHandleDrawTextShadow(context))) + if (!context->platformContext()->isNativeFontRenderingAllowed()) return false; return true; @@ -272,7 +278,7 @@ bool windowsCanHandleTextDrawing(GraphicsContext* context) // pattern may be NULL, in which case a solid colour is used. static bool skiaDrawText(HFONT hfont, HDC dc, - SkCanvas* canvas, + PlatformContextSkia* platformContext, const SkPoint& point, SkPaint* paint, const WORD* glyphs, @@ -280,47 +286,47 @@ static bool skiaDrawText(HFONT hfont, const GOFFSET* offsets, int numGlyphs) { -#if ENABLE(SKIA_TEXT) - SkASSERT(sizeof(WORD) == sizeof(uint16_t)); - - // Reserve space for 64 glyphs on the stack. If numGlyphs is larger, the array - // will dynamically allocate it space for numGlyph glyphs. - static const size_t kLocalGlyphMax = 64; - SkAutoSTArray<kLocalGlyphMax, SkPoint> posStorage(numGlyphs); - SkPoint* pos = posStorage.get(); - SkScalar x = point.fX; - SkScalar y = point.fY; - for (int i = 0; i < numGlyphs; i++) { - pos[i].set(x + (offsets ? offsets[i].du : 0), - y + (offsets ? offsets[i].dv : 0)); - x += SkIntToScalar(advances[i]); - } - canvas->drawPosText(glyphs, numGlyphs * sizeof(uint16_t), pos, *paint); -#else - float x = point.fX, y = point.fY; - - for (int i = 0; i < numGlyphs; i++) { - const SkPath* path = SkiaWinOutlineCache::lookupOrCreatePathForGlyph(dc, hfont, glyphs[i]); - if (!path) - return false; - - float offsetX = 0.0f, offsetY = 0.0f; - if (offsets && (offsets[i].du != 0 || offsets[i].dv != 0)) { - offsetX = offsets[i].du; - offsetY = offsets[i].dv; + SkCanvas* canvas = platformContext->canvas(); + if (!platformContext->isNativeFontRenderingAllowed()) { + SkASSERT(sizeof(WORD) == sizeof(uint16_t)); + + // Reserve space for 64 glyphs on the stack. If numGlyphs is larger, the array + // will dynamically allocate it space for numGlyph glyphs. + static const size_t kLocalGlyphMax = 64; + SkAutoSTArray<kLocalGlyphMax, SkPoint> posStorage(numGlyphs); + SkPoint* pos = posStorage.get(); + SkScalar x = point.fX; + SkScalar y = point.fY; + for (int i = 0; i < numGlyphs; i++) { + pos[i].set(x + (offsets ? offsets[i].du : 0), + y + (offsets ? offsets[i].dv : 0)); + x += SkIntToScalar(advances[i]); } + canvas->drawPosText(glyphs, numGlyphs * sizeof(uint16_t), pos, *paint); + } else { + float x = point.fX, y = point.fY; + + for (int i = 0; i < numGlyphs; i++) { + const SkPath* path = SkiaWinOutlineCache::lookupOrCreatePathForGlyph(dc, hfont, glyphs[i]); + if (!path) + return false; + + float offsetX = 0.0f, offsetY = 0.0f; + if (offsets && (offsets[i].du || offsets[i].dv)) { + offsetX = offsets[i].du; + offsetY = offsets[i].dv; + } - SkPath newPath; - newPath.addPath(*path, x + offsetX, y + offsetY); - canvas->drawPath(newPath, *paint); + SkPath newPath; + newPath.addPath(*path, x + offsetX, y + offsetY); + canvas->drawPath(newPath, *paint); - x += advances[i]; + x += advances[i]; + } } -#endif return true; } -#if ENABLE(SKIA_TEXT) static void setupPaintForFont(HFONT hfont, SkPaint* paint) { // FIXME: @@ -339,7 +345,6 @@ static void setupPaintForFont(HFONT hfont, SkPaint* paint) paint->setTypeface(face); SkSafeUnref(face); } -#endif bool paintSkiaText(GraphicsContext* context, HFONT hfont, @@ -359,14 +364,14 @@ bool paintSkiaText(GraphicsContext* context, SkPaint paint; platformContext->setupPaintForFilling(&paint); paint.setFlags(SkPaint::kAntiAlias_Flag); -#if ENABLE(SKIA_TEXT) - paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - setupPaintForFont(hfont, &paint); -#endif + if (!platformContext->isNativeFontRenderingAllowed()) { + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + setupPaintForFont(hfont, &paint); + } bool didFill = false; - if ((textMode & TextModeFill) && SkColorGetA(paint.getColor())) { - if (!skiaDrawText(hfont, dc, platformContext->canvas(), *origin, &paint, + if ((textMode & TextModeFill) && (SkColorGetA(paint.getColor()) || paint.getLooper())) { + if (!skiaDrawText(hfont, dc, platformContext, *origin, &paint, &glyphs[0], &advances[0], &offsets[0], numGlyphs)) return false; didFill = true; @@ -380,10 +385,10 @@ bool paintSkiaText(GraphicsContext* context, paint.reset(); platformContext->setupPaintForStroking(&paint, 0, 0); paint.setFlags(SkPaint::kAntiAlias_Flag); -#if ENABLE(SKIA_TEXT) - paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - setupPaintForFont(hfont, &paint); -#endif + if (!platformContext->isNativeFontRenderingAllowed()) { + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + setupPaintForFont(hfont, &paint); + } if (didFill) { // If there is a shadow and we filled above, there will already be @@ -398,7 +403,7 @@ bool paintSkiaText(GraphicsContext* context, paint.setLooper(0); } - if (!skiaDrawText(hfont, dc, platformContext->canvas(), *origin, &paint, + if (!skiaDrawText(hfont, dc, platformContext, *origin, &paint, &glyphs[0], &advances[0], &offsets[0], numGlyphs)) return false; } diff --git a/Source/WebCore/platform/graphics/skia/SkiaFontWin.h b/Source/WebCore/platform/graphics/skia/SkiaFontWin.h index 40bee62..33b4aaf 100644 --- a/Source/WebCore/platform/graphics/skia/SkiaFontWin.h +++ b/Source/WebCore/platform/graphics/skia/SkiaFontWin.h @@ -76,6 +76,10 @@ bool windowsCanHandleDrawTextShadow(GraphicsContext*); // Returns true if advanced font rendering is recommended. bool windowsCanHandleTextDrawing(GraphicsContext*); +// Returns true if advanced font rendering is recommended if shadows are +// disregarded. +bool windowsCanHandleTextDrawingWithoutShadow(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/Source/WebCore/platform/graphics/transforms/AffineTransform.h b/Source/WebCore/platform/graphics/transforms/AffineTransform.h index 14431aa..176c41e 100644 --- a/Source/WebCore/platform/graphics/transforms/AffineTransform.h +++ b/Source/WebCore/platform/graphics/transforms/AffineTransform.h @@ -32,9 +32,9 @@ #include <string.h> // for memcpy #include <wtf/FastAllocBase.h> -#if PLATFORM(CG) +#if USE(CG) #include <CoreGraphics/CGAffineTransform.h> -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) #include <cairo.h> #elif PLATFORM(OPENVG) #include "VGUtils.h" @@ -157,9 +157,9 @@ public: return result; } -#if PLATFORM(CG) +#if USE(CG) operator CGAffineTransform() const; -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) operator cairo_matrix_t() const; #elif PLATFORM(OPENVG) operator VGMatrix() const; diff --git a/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h b/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h index adda46b..ff668bb 100644 --- a/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h +++ b/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h @@ -31,12 +31,12 @@ #include <string.h> //for memcpy #include <wtf/FastAllocBase.h> -#if PLATFORM(CA) +#if USE(CA) typedef struct CATransform3D CATransform3D; #endif -#if PLATFORM(CG) +#if USE(CG) typedef struct CGAffineTransform CGAffineTransform; -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) #include <cairo.h> #elif PLATFORM(OPENVG) #include "VGUtils.h" @@ -308,14 +308,14 @@ public: return result; } -#if PLATFORM(CA) +#if USE(CA) TransformationMatrix(const CATransform3D&); operator CATransform3D() const; #endif -#if PLATFORM(CG) +#if USE(CG) TransformationMatrix(const CGAffineTransform&); operator CGAffineTransform() const; -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) operator cairo_matrix_t() const; #elif PLATFORM(OPENVG) operator VGMatrix() const; diff --git a/Source/WebCore/platform/graphics/win/DIBPixelData.cpp b/Source/WebCore/platform/graphics/win/DIBPixelData.cpp new file mode 100644 index 0000000..e45ba06 --- /dev/null +++ b/Source/WebCore/platform/graphics/win/DIBPixelData.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2011 Brent Fulgham <bfulgham@webkit.org> + * + * 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 "DIBPixelData.h" + +namespace WebCore { + +static const WORD bitmapType = 0x4d42; // BMP format +static const WORD bitmapPixelsPerMeter = 2834; // 72 dpi + +DIBPixelData::DIBPixelData(HBITMAP bitmap) +{ + initialize(bitmap); +} + +void DIBPixelData::initialize(HBITMAP bitmap) +{ + BITMAP bmpInfo; + GetObject(bitmap, sizeof(bmpInfo), &bmpInfo); + + m_bitmapBuffer = reinterpret_cast<UInt8*>(bmpInfo.bmBits); + m_bitmapBufferLength = bmpInfo.bmWidthBytes * bmpInfo.bmHeight; + m_size = IntSize(bmpInfo.bmWidth, bmpInfo.bmHeight); + m_bytesPerRow = bmpInfo.bmWidthBytes; + m_bitsPerPixel = bmpInfo.bmBitsPixel; +} + +#ifndef NDEBUG +void DIBPixelData::writeToFile(LPCWSTR filePath) +{ + HANDLE hFile = ::CreateFile(filePath, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (INVALID_HANDLE_VALUE == hFile) + return; + + BITMAPFILEHEADER header; + header.bfType = bitmapType; + header.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); + header.bfReserved1 = 0; + header.bfReserved2 = 0; + header.bfSize = sizeof(BITMAPFILEHEADER); + + BITMAPINFOHEADER info; + info.biSize = sizeof(BITMAPINFOHEADER); + info.biWidth = m_size.width(); + info.biHeight = m_size.height(); + info.biPlanes = 1; + info.biBitCount = m_bitsPerPixel; + info.biCompression = BI_RGB; + info.biSizeImage = bufferLength(); + info.biXPelsPerMeter = bitmapPixelsPerMeter; + info.biYPelsPerMeter = bitmapPixelsPerMeter; + info.biClrUsed = 0; + info.biClrImportant = 0; + + DWORD bytesWritten = 0; + ::WriteFile(hFile, &header, sizeof(header), &bytesWritten, 0); + ::WriteFile(hFile, &info, sizeof(info), &bytesWritten, 0); + ::WriteFile(hFile, buffer(), bufferLength(), &bytesWritten, 0); + + ::CloseHandle(hFile); +} +#endif + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/win/DIBPixelData.h b/Source/WebCore/platform/graphics/win/DIBPixelData.h new file mode 100644 index 0000000..40afa2b --- /dev/null +++ b/Source/WebCore/platform/graphics/win/DIBPixelData.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2011 Brent Fulgham <bfulgham@webkit.org> + * + * 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 DIBPixelData_h +#define DIBPixelData_h + +#include "IntSize.h" +#include <windows.h> + +#if !USE(CG) +// UInt8 is defined in CoreFoundation/CFBase.h +typedef unsigned char UInt8; +#endif + +namespace WebCore { + +class DIBPixelData { + public: + DIBPixelData() + : m_bitmapBuffer(0) + , m_bitmapBufferLength(0) + , m_bytesPerRow(0) + , m_bitsPerPixel(0) + { + } + DIBPixelData(HBITMAP); + + void initialize(HBITMAP); + +#ifndef NDEBUG + void writeToFile(LPCWSTR); +#endif + + UInt8* buffer() const { return m_bitmapBuffer; } + unsigned bufferLength() const { return m_bitmapBufferLength; } + const IntSize& size() const { return m_size; } + unsigned bytesPerRow() const { return m_bytesPerRow; } + unsigned short bitsPerPixel() const { return m_bitsPerPixel; } + + private: + UInt8* m_bitmapBuffer; + unsigned m_bitmapBufferLength; + IntSize m_size; + unsigned m_bytesPerRow; + unsigned short m_bitsPerPixel; +}; + +} // namespace WebCore + +#endif // DIBPixelData_h diff --git a/Source/WebCore/platform/graphics/win/FontCacheWin.cpp b/Source/WebCore/platform/graphics/win/FontCacheWin.cpp index 5382ef7..46f6f11 100644 --- a/Source/WebCore/platform/graphics/win/FontCacheWin.cpp +++ b/Source/WebCore/platform/graphics/win/FontCacheWin.cpp @@ -36,7 +36,7 @@ #include <windows.h> #include <wtf/StdLibExtras.h> #include <wtf/text/StringHash.h> -#if PLATFORM(CG) +#if USE(CG) #include <ApplicationServices/ApplicationServices.h> #include <WebKitSystemInterface/WebKitSystemInterface.h> #endif @@ -48,7 +48,7 @@ namespace WebCore void FontCache::platformInit() { -#if PLATFORM(CG) +#if USE(CG) wkSetUpFontCache(1536 * 1024 * 4); // This size matches Mac. #endif } @@ -471,7 +471,7 @@ static HFONT createGDIFont(const AtomicString& family, LONG desiredWeight, bool matchData.m_chosen.lfUnderline = false; matchData.m_chosen.lfStrikeOut = false; matchData.m_chosen.lfCharSet = DEFAULT_CHARSET; -#if PLATFORM(CG) || PLATFORM(CAIRO) +#if USE(CG) || USE(CAIRO) matchData.m_chosen.lfOutPrecision = OUT_TT_ONLY_PRECIS; #else matchData.m_chosen.lfOutPrecision = OUT_TT_PRECIS; @@ -581,9 +581,9 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD FontPlatformData* result = new FontPlatformData(hfont, fontDescription.computedPixelSize(), synthesizeBold, synthesizeItalic, useGDI); -#if PLATFORM(CG) +#if USE(CG) bool fontCreationFailed = !result->cgFont(); -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) bool fontCreationFailed = !result->scaledFont(); #endif diff --git a/Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp b/Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp index 301198d..d0b37bd 100644 --- a/Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp +++ b/Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp @@ -41,9 +41,9 @@ FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool obliq , m_orientation(Horizontal) , m_textOrientation(TextOrientationVerticalRight) , m_widthVariant(RegularWidth) -#if PLATFORM(CG) +#if USE(CG) , m_cgFont(0) -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) , m_scaledFont(0) #endif , m_isColorBitmapFont(false) diff --git a/Source/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/Source/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp index d0bd4e9..cb0c9a7 100644 --- a/Source/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp +++ b/Source/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp @@ -40,25 +40,24 @@ namespace WebCore { static CGContextRef CGContextWithHDC(HDC hdc, bool hasAlpha) { HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)); - BITMAP info; - GetObject(bitmap, sizeof(info), &info); + DIBPixelData pixelData(bitmap); // FIXME: We can get here because we asked for a bitmap that is too big // when we have a tiled layer and we're compositing. In that case // bmBitsPixel will be 0. This seems to be benign, so for now we will // exit gracefully and look at it later: // https://bugs.webkit.org/show_bug.cgi?id=52041 - // ASSERT(info.bmBitsPixel == 32); - if (info.bmBitsPixel != 32) + // ASSERT(bitmapBits.bitsPerPixel() == 32); + if (pixelData.bitsPerPixel() != 32) return 0; CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Little | (hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst); - CGContextRef context = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8, - info.bmWidthBytes, deviceRGBColorSpaceRef(), bitmapInfo); + CGContextRef context = CGBitmapContextCreate(pixelData.buffer(), pixelData.size().width(), pixelData.size().height(), 8, + pixelData.bytesPerRow(), deviceRGBColorSpaceRef(), bitmapInfo); // Flip coords - CGContextTranslateCTM(context, 0, info.bmHeight); + CGContextTranslateCTM(context, 0, pixelData.size().height()); CGContextScaleCTM(context, 1, -1); // Put the HDC In advanced mode so it will honor affine transforms. @@ -99,16 +98,14 @@ void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, boo if (dstRect.isEmpty()) return; - HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)); + OwnPtr<HBITMAP> bitmap = adoptPtr(static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP))); + + DIBPixelData pixelData(bitmap.get()); - // Need to make a CGImage out of the bitmap's pixel buffer and then draw - // it into our context. - BITMAP info; - GetObject(bitmap, sizeof(info), &info); - ASSERT(info.bmBitsPixel == 32); + ASSERT(pixelData.bitsPerPixel() == 32); - CGContextRef bitmapContext = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8, - info.bmWidthBytes, deviceRGBColorSpaceRef(), kCGBitmapByteOrder32Little | + CGContextRef bitmapContext = CGBitmapContextCreate(pixelData.buffer(), pixelData.size().width(), pixelData.size().height(), 8, + pixelData.bytesPerRow(), deviceRGBColorSpaceRef(), kCGBitmapByteOrder32Little | (supportAlphaBlend ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst)); CGImageRef image = CGBitmapContextCreateImage(bitmapContext); @@ -118,7 +115,6 @@ void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, boo CGImageRelease(image); CGContextRelease(bitmapContext); ::DeleteDC(hdc); - ::DeleteObject(bitmap); } void GraphicsContext::drawWindowsBitmap(WindowsBitmap* image, const IntPoint& point) diff --git a/Source/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/Source/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp index 7ce7ee9..9f7aece 100644 --- a/Source/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp +++ b/Source/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp @@ -78,7 +78,7 @@ void GraphicsContext::platformInit(HDC dc, bool hasAlpha) else setPaintingDisabled(true); - m_data = new GraphicsContextPlatformPrivateTopLevel(new PlatformContextCairo(cr)); + m_data = new GraphicsContextPlatformPrivateToplevel(new PlatformContextCairo(cr)); m_data->m_hdc = dc; if (platformContext()->cr()) { // Make sure the context starts in sync with our state. @@ -93,6 +93,33 @@ static void setRGBABitmapAlpha(unsigned char* bytes, size_t length, unsigned cha bytes[i + 3] = level; } +static void drawBitmapToContext(GraphicsContextPlatformPrivate* context, cairo_t* cr, const DIBPixelData& pixelData, const IntSize& translate) +{ + // Need to make a cairo_surface_t out of the bitmap's pixel buffer and then draw + // it into our context. + cairo_surface_t* surface = cairo_image_surface_create_for_data(pixelData.buffer(), + CAIRO_FORMAT_ARGB32, + pixelData.size().width(), + pixelData.size().height(), + pixelData.bytesPerRow()); + + // Flip the target surface so that when we set the srcImage as + // the surface it will draw right-side-up. + cairo_save(cr); + cairo_translate(cr, static_cast<double>(translate.width()), static_cast<double>(translate.height())); + cairo_scale(cr, 1, -1); + cairo_set_source_surface(cr, surface, 0, 0); + + if (context->layers.size()) + cairo_paint_with_alpha(cr, context->layers.last()); + else + cairo_paint(cr); + + // Delete all our junk. + cairo_surface_destroy(surface); + cairo_restore(cr); +} + void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) { bool createdBitmap = mayCreateBitmap && (!m_data->m_hdc || inTransparencyLayer()); @@ -104,46 +131,26 @@ void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, boo if (dstRect.isEmpty()) return; - HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)); + OwnPtr<HBITMAP> bitmap = adoptPtr(static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP))); - BITMAP info; - GetObject(bitmap, sizeof(info), &info); - ASSERT(info.bmBitsPixel == 32); + DIBPixelData pixelData(bitmap.get()); + ASSERT(pixelData.bitsPerPixel() == 32); // If this context does not support alpha blending, then it may have // been drawn with GDI functions which always set the alpha channel // to zero. We need to manually set the bitmap to be fully opaque. - unsigned char* bytes = reinterpret_cast<unsigned char*>(info.bmBits); + unsigned char* bytes = reinterpret_cast<unsigned char*>(pixelData.buffer()); if (!supportAlphaBlend) - setRGBABitmapAlpha(bytes, info.bmHeight * info.bmWidthBytes, 255); + setRGBABitmapAlpha(bytes, pixelData.size().height() * pixelData.bytesPerRow(), 255); - // 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(bytes, - 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_t* cr = platformContext()->cr(); - cairo_save(cr); - cairo_translate(cr, dstRect.x(), dstRect.height() + dstRect.y()); - cairo_scale(cr, 1, -1); - cairo_set_source_surface(cr, image, 0, 0); + drawBitmapToContext(m_data, platformContext()->cr(), pixelData, IntSize(dstRect.x(), dstRect.height() + dstRect.y())); - if (m_data->layers.size()) - cairo_paint_with_alpha(cr, m_data->layers.last()); - else - cairo_paint(cr); - - // Delete all our junk. - cairo_surface_destroy(image); ::DeleteDC(hdc); - ::DeleteObject(bitmap); - cairo_restore(cr); +} + +void GraphicsContext::drawWindowsBitmap(WindowsBitmap* bitmap, const IntPoint& point) +{ + drawBitmapToContext(m_data, platformContext()->cr(), bitmap->windowsDIB(), IntSize(point.x(), bitmap->size().height() + point.y())); } void GraphicsContextPlatformPrivate::syncContext(cairo_t* cr) diff --git a/Source/WebCore/platform/graphics/win/GraphicsContextWin.cpp b/Source/WebCore/platform/graphics/win/GraphicsContextWin.cpp index f2850e4..28ce55a 100644 --- a/Source/WebCore/platform/graphics/win/GraphicsContextWin.cpp +++ b/Source/WebCore/platform/graphics/win/GraphicsContextWin.cpp @@ -26,9 +26,9 @@ #include "config.h" #include "GraphicsContext.h" -#if PLATFORM(CG) +#if USE(CG) #include "GraphicsContextPlatformPrivateCG.h" -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) #include "GraphicsContextPlatformPrivateCairo.h" #endif @@ -65,21 +65,20 @@ bool GraphicsContext::shouldIncludeChildWindows() const GraphicsContext::WindowsBitmap::WindowsBitmap(HDC hdc, IntSize size) : m_hdc(0) - , m_size(size) { - BitmapInfo bitmapInfo = BitmapInfo::create(m_size); + BitmapInfo bitmapInfo = BitmapInfo::create(size); - m_bitmap = CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, reinterpret_cast<void**>(&m_bitmapBuffer), 0, 0); + void* storage = 0; + m_bitmap = CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, &storage, 0, 0); if (!m_bitmap) return; m_hdc = CreateCompatibleDC(hdc); SelectObject(m_hdc, m_bitmap); - BITMAP bmpInfo; - GetObject(m_bitmap, sizeof(bmpInfo), &bmpInfo); - m_bytesPerRow = bmpInfo.bmWidthBytes; - m_bitmapBufferLength = bmpInfo.bmWidthBytes * bmpInfo.bmHeight; + m_pixelData.initialize(m_bitmap); + + ASSERT(storage == m_pixelData.buffer()); SetGraphicsMode(m_hdc, GM_ADVANCED); } diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp index dd3cd32..588146a 100644 --- a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp +++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp @@ -30,7 +30,7 @@ #include "WebCoreInstanceHandle.h" #include <windows.h> -#if PLATFORM(CG) +#if USE(CG) #include <CoreGraphics/CGColor.h> #endif diff --git a/Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp b/Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp index 323ff73..db730ca 100644 --- a/Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp +++ b/Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp @@ -39,7 +39,7 @@ #include <winsock2.h> #include <wtf/MathExtras.h> -#if PLATFORM(CG) +#if USE(CG) #include <ApplicationServices/ApplicationServices.h> #include <WebKitSystemInterface/WebKitSystemInterface.h> #endif diff --git a/Source/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp b/Source/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp index 19683df..e501621 100644 --- a/Source/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp +++ b/Source/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp @@ -1300,7 +1300,7 @@ void GraphicsContext::drawRoundCorner(bool needsNewClip, RECT clipRect, RECT rec } -FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect, RoundingMode) { notImplemented(); return frect; diff --git a/Source/WebCore/platform/graphics/wince/ImageBufferData.h b/Source/WebCore/platform/graphics/wince/ImageBufferDataWince.h index cbd49dc..dd46d38 100644 --- a/Source/WebCore/platform/graphics/wince/ImageBufferData.h +++ b/Source/WebCore/platform/graphics/wince/ImageBufferDataWince.h @@ -17,9 +17,6 @@ * Boston, MA 02110-1301, USA. */ -#ifndef ImageBufferData_h -#define ImageBufferData_h - #include "SharedBitmap.h" namespace WebCore { @@ -33,5 +30,3 @@ public: }; } // namespace WebCore - -#endif // ImageBufferData_h diff --git a/Source/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp b/Source/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp index 830cd05..3d98aeb 100644 --- a/Source/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp +++ b/Source/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp @@ -99,12 +99,14 @@ FontPlatformData::FontPlatformData(const FontDescription& desc, const AtomicStri ) )); #endif -#if OS(DARWIN) && !defined(wxOSX_USE_CORE_TEXT) +#if OS(DARWIN) +#if !wxOSX_USE_CORE_TEXT #if wxCHECK_VERSION(2,9,0) m_atsuFontID = m_font->font()->OSXGetATSUFontID(); #else m_atsuFontID = m_font->font()->MacGetATSUFontID(); #endif +#endif m_nsFont = 0; cacheNSFont(); #endif diff --git a/Source/WebCore/platform/graphics/wx/GraphicsContextWx.cpp b/Source/WebCore/platform/graphics/wx/GraphicsContextWx.cpp index 47f3211..071df47 100644 --- a/Source/WebCore/platform/graphics/wx/GraphicsContextWx.cpp +++ b/Source/WebCore/platform/graphics/wx/GraphicsContextWx.cpp @@ -416,7 +416,7 @@ void GraphicsContext::scale(const FloatSize& scale) } -FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect, RoundingMode) { FloatRect result; diff --git a/Source/WebCore/platform/graphics/wx/ImageBufferData.h b/Source/WebCore/platform/graphics/wx/ImageBufferDataWx.h index d4a6114..9961fee 100644 --- a/Source/WebCore/platform/graphics/wx/ImageBufferData.h +++ b/Source/WebCore/platform/graphics/wx/ImageBufferDataWx.h @@ -23,10 +23,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ImageBufferData_h -#define ImageBufferData_h - - #include "OwnPtr.h" namespace WebCore { @@ -38,6 +34,4 @@ public: ImageBufferData(const IntSize&); }; -} // namespace WebCore - -#endif // ImageBufferData_h +} // namespace WebCore diff --git a/Source/WebCore/platform/gtk/GtkVersioning.c b/Source/WebCore/platform/gtk/GtkVersioning.c index c3407ea..1138d56 100644 --- a/Source/WebCore/platform/gtk/GtkVersioning.c +++ b/Source/WebCore/platform/gtk/GtkVersioning.c @@ -271,3 +271,13 @@ gboolean g_signal_accumulator_first_wins(GSignalInvocationHint *invocationHint, } #endif +#if !GTK_CHECK_VERSION(2, 22, 0) +cairo_surface_t *gdk_window_create_similar_surface(GdkWindow *window, cairo_content_t content, int width, int height) +{ + cairo_t *cairoContext = gdk_cairo_create(window); + cairo_surface_t *cairoSurface = cairo_get_target(cairoContext); + cairo_surface_t *newSurface = cairo_surface_create_similar(cairoSurface, content, width, height); + cairo_destroy(cairoContext); + return newSurface; +} +#endif // GTK_CHECK_VERSION(2, 22, 0) diff --git a/Source/WebCore/platform/gtk/GtkVersioning.h b/Source/WebCore/platform/gtk/GtkVersioning.h index 70e1bbe..b44fc38 100644 --- a/Source/WebCore/platform/gtk/GtkVersioning.h +++ b/Source/WebCore/platform/gtk/GtkVersioning.h @@ -46,6 +46,10 @@ GdkPixbuf* gdk_pixbuf_get_from_surface(cairo_surface_t* surface, int srcX, int s #define gdk_window_get_visual gdk_drawable_get_visual #endif // GTK_CHECK_VERSION(2, 23, 0) +#if !GTK_CHECK_VERSION(2, 22, 0) +cairo_surface_t* gdk_window_create_similar_surface(GdkWindow* window, cairo_content_t content, int width, int height); +#endif // GTK_CHECK_VERSION(2, 22, 0) + #if !GTK_CHECK_VERSION(2, 21, 2) #define gdk_visual_get_depth(visual) (visual)->depth #define gdk_visual_get_bits_per_rgb(visual) (visual)->bits_per_rgb diff --git a/Source/WebCore/platform/gtk/LocalizedStringsGtk.cpp b/Source/WebCore/platform/gtk/LocalizedStringsGtk.cpp index 02f6c47..13c46fc 100644 --- a/Source/WebCore/platform/gtk/LocalizedStringsGtk.cpp +++ b/Source/WebCore/platform/gtk/LocalizedStringsGtk.cpp @@ -642,4 +642,9 @@ String validationMessageStepMismatchText(const String&, const String&) return String::fromUTF8(_("step mismatch")); } +String localizedString(const char* key) +{ + return String::fromUTF8(key, strlen(key)); +} + } diff --git a/Source/WebCore/platform/gtk/KeyEventGtk.cpp b/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp index d010b37..d010b37 100644 --- a/Source/WebCore/platform/gtk/KeyEventGtk.cpp +++ b/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp diff --git a/Source/WebCore/platform/gtk/MouseEventGtk.cpp b/Source/WebCore/platform/gtk/PlatformMouseEventGtk.cpp index 69f938f..69f938f 100644 --- a/Source/WebCore/platform/gtk/MouseEventGtk.cpp +++ b/Source/WebCore/platform/gtk/PlatformMouseEventGtk.cpp diff --git a/Source/WebCore/platform/gtk/WheelEventGtk.cpp b/Source/WebCore/platform/gtk/PlatformWheelEventGtk.cpp index fc6206f..fc6206f 100644 --- a/Source/WebCore/platform/gtk/WheelEventGtk.cpp +++ b/Source/WebCore/platform/gtk/PlatformWheelEventGtk.cpp diff --git a/Source/WebCore/platform/gtk/RenderThemeGtk.h b/Source/WebCore/platform/gtk/RenderThemeGtk.h index 191a34b..09eb1df 100644 --- a/Source/WebCore/platform/gtk/RenderThemeGtk.h +++ b/Source/WebCore/platform/gtk/RenderThemeGtk.h @@ -147,6 +147,7 @@ protected: void initMediaColors(); void initMediaButtons(); void adjustMediaSliderThumbSize(RenderObject*) const; + virtual bool hasOwnDisabledStateHandlingFor(ControlPart) const { return true; } virtual bool paintMediaFullscreenButton(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintMediaPlayButton(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintMediaMuteButton(RenderObject*, const PaintInfo&, const IntRect&); diff --git a/Source/WebCore/platform/gtk/RenderThemeGtk3.cpp b/Source/WebCore/platform/gtk/RenderThemeGtk3.cpp index 527de1a..6e2c94c 100644 --- a/Source/WebCore/platform/gtk/RenderThemeGtk3.cpp +++ b/Source/WebCore/platform/gtk/RenderThemeGtk3.cpp @@ -34,6 +34,7 @@ #include "MediaControlElements.h" #include "Page.h" #include "PaintInfo.h" +#include "PlatformContextCairo.h" #include "RenderObject.h" #include "TextDirection.h" #include "UserAgentStyleSheets.h" @@ -216,16 +217,16 @@ static void paintToggle(const RenderThemeGtk* theme, GType widgetType, RenderObj gtk_style_context_set_state(context, static_cast<GtkStateFlags>(flags)); if (widgetType == GTK_TYPE_CHECK_BUTTON) - gtk_render_check(context, paintInfo.context->platformContext(), rect.x(), rect.y(), rect.width(), rect.height()); + gtk_render_check(context, paintInfo.context->platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height()); else - gtk_render_option(context, paintInfo.context->platformContext(), rect.x(), rect.y(), rect.width(), rect.height()); + gtk_render_option(context, paintInfo.context->platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height()); if (theme->isFocused(renderObject)) { IntRect indicatorRect(rect); gint indicatorSpacing; gtk_style_context_get_style(context, "indicator-spacing", &indicatorSpacing, NULL); indicatorRect.inflate(indicatorSpacing); - gtk_render_focus(context, paintInfo.context->platformContext(), indicatorRect.x(), indicatorRect.y(), + gtk_render_focus(context, paintInfo.context->platformContext()->cr(), indicatorRect.x(), indicatorRect.y(), indicatorRect.width(), indicatorRect.height()); } @@ -284,8 +285,8 @@ static void renderButton(RenderTheme* theme, GtkStyleContext* context, RenderObj gtk_style_context_add_class(context, GTK_STYLE_CLASS_DEFAULT); } - gtk_render_background(context, paintInfo.context->platformContext(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height()); - gtk_render_frame(context, paintInfo.context->platformContext(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height()); + gtk_render_background(context, paintInfo.context->platformContext()->cr(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height()); + gtk_render_frame(context, paintInfo.context->platformContext()->cr(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height()); if (theme->isFocused(renderObject)) { gint focusWidth, focusPad; @@ -317,7 +318,7 @@ static void renderButton(RenderTheme* theme, GtkStyleContext* context, RenderObj buttonRect.move(childDisplacementX, childDisplacementY); } - gtk_render_focus(context, paintInfo.context->platformContext(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height()); + gtk_render_focus(context, paintInfo.context->platformContext()->cr(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height()); } } bool RenderThemeGtk::paintButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) @@ -423,7 +424,7 @@ int RenderThemeGtk::popupInternalPaddingBottom(RenderStyle* style) const bool RenderThemeGtk::paintMenuList(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) { - cairo_t* cairoContext = paintInfo.context->platformContext(); + cairo_t* cairoContext = paintInfo.context->platformContext()->cr(); GtkTextDirection direction = static_cast<GtkTextDirection>(gtkTextDirection(renderObject->style()->direction())); // Paint the button. @@ -568,8 +569,8 @@ bool RenderThemeGtk::paintTextField(RenderObject* renderObject, const PaintInfo& flags |= GTK_STATE_FLAG_FOCUSED; gtk_style_context_set_state(context, static_cast<GtkStateFlags>(flags)); - gtk_render_background(context, paintInfo.context->platformContext(), rect.x(), rect.y(), rect.width(), rect.height()); - gtk_render_frame(context, paintInfo.context->platformContext(), rect.x(), rect.y(), rect.width(), rect.height()); + gtk_render_background(context, paintInfo.context->platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height()); + gtk_render_frame(context, paintInfo.context->platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height()); if (isFocused(renderObject) && isEnabled(renderObject)) { gboolean interiorFocus; @@ -582,7 +583,7 @@ bool RenderThemeGtk::paintTextField(RenderObject* renderObject, const PaintInfo& if (!interiorFocus) { IntRect focusRect(rect); focusRect.inflate(focusWidth + focusPad); - gtk_render_focus(context, paintInfo.context->platformContext(), + gtk_render_focus(context, paintInfo.context->platformContext()->cr(), focusRect.x(), focusRect.y(), focusRect.width(), focusRect.height()); } } @@ -607,9 +608,9 @@ bool RenderThemeGtk::paintSliderTrack(RenderObject* renderObject, const PaintInf if (!isEnabled(renderObject) || isReadOnlyControl(renderObject)) gtk_style_context_set_state(context, GTK_STATE_FLAG_INSENSITIVE); - gtk_render_background(context, paintInfo.context->platformContext(), + gtk_render_background(context, paintInfo.context->platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height()); - gtk_render_frame(context, paintInfo.context->platformContext(), + gtk_render_frame(context, paintInfo.context->platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height()); if (isFocused(renderObject)) { @@ -619,7 +620,7 @@ bool RenderThemeGtk::paintSliderTrack(RenderObject* renderObject, const PaintInf "focus-padding", &focusPad, NULL); IntRect focusRect(rect); focusRect.inflate(focusWidth + focusPad); - gtk_render_focus(context, paintInfo.context->platformContext(), + gtk_render_focus(context, paintInfo.context->platformContext()->cr(), focusRect.x(), focusRect.y(), focusRect.width(), focusRect.height()); } @@ -654,7 +655,7 @@ bool RenderThemeGtk::paintSliderThumb(RenderObject* renderObject, const PaintInf flags |= GTK_STATE_FLAG_ACTIVE; gtk_style_context_set_state(context, static_cast<GtkStateFlags>(flags)); - gtk_render_slider(context, paintInfo.context->platformContext(), sliderRect.x(), sliderRect.y(), sliderRect.width(), sliderRect.height(), + gtk_render_slider(context, paintInfo.context->platformContext()->cr(), sliderRect.x(), sliderRect.y(), sliderRect.width(), sliderRect.height(), part == SliderThumbHorizontalPart ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL); gtk_style_context_restore(context); @@ -698,8 +699,8 @@ bool RenderThemeGtk::paintProgressBar(RenderObject* renderObject, const PaintInf gtk_style_context_add_class(context, GTK_STYLE_CLASS_TROUGH); - gtk_render_background(context, paintInfo.context->platformContext(), rect.x(), rect.y(), rect.width(), rect.height()); - gtk_render_frame(context, paintInfo.context->platformContext(), rect.x(), rect.y(), rect.width(), rect.height()); + gtk_render_background(context, paintInfo.context->platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height()); + gtk_render_frame(context, paintInfo.context->platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height()); gtk_style_context_restore(context); @@ -715,7 +716,7 @@ bool RenderThemeGtk::paintProgressBar(RenderObject* renderObject, const PaintInf progressRect = RenderThemeGtk::calculateProgressRect(renderObject, progressRect); if (!progressRect.isEmpty()) - gtk_render_activity(context, paintInfo.context->platformContext(), progressRect.x(), progressRect.y(), progressRect.width(), progressRect.height()); + gtk_render_activity(context, paintInfo.context->platformContext()->cr(), progressRect.x(), progressRect.y(), progressRect.width(), progressRect.height()); gtk_style_context_restore(context); return false; @@ -777,8 +778,8 @@ static void paintSpinArrowButton(RenderTheme* theme, GtkStyleContext* context, R buttonRect.setHeight(rect.height() / 2); gtk_style_context_set_junction_sides(context, static_cast<GtkJunctionSides>(junction)); - gtk_render_background(context, paintInfo.context->platformContext(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height()); - gtk_render_frame(context, paintInfo.context->platformContext(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height()); + gtk_render_background(context, paintInfo.context->platformContext()->cr(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height()); + gtk_render_frame(context, paintInfo.context->platformContext()->cr(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height()); // Paint arrow centered inside button. // This code is based on gtkspinbutton.c code. @@ -804,7 +805,7 @@ static void paintSpinArrowButton(RenderTheme* theme, GtkStyleContext* context, R gint height = (width + 1) / 2; arrowRect.move((arrowRect.width() - width) / 2, (arrowRect.height() - height) / 2); - gtk_render_arrow(context, paintInfo.context->platformContext(), angle, arrowRect.x(), arrowRect.y(), width); + gtk_render_arrow(context, paintInfo.context->platformContext()->cr(), angle, arrowRect.x(), arrowRect.y(), width); gtk_style_context_restore(context); } diff --git a/Source/WebCore/platform/gtk/ScrollbarThemeGtk3.cpp b/Source/WebCore/platform/gtk/ScrollbarThemeGtk3.cpp index b0b5146..f854037 100644 --- a/Source/WebCore/platform/gtk/ScrollbarThemeGtk3.cpp +++ b/Source/WebCore/platform/gtk/ScrollbarThemeGtk3.cpp @@ -28,6 +28,7 @@ #ifndef GTK_API_VERSION_2 +#include "PlatformContextCairo.h" #include "PlatformMouseEvent.h" #include "RenderThemeGtk.h" #include "ScrollView.h" @@ -77,9 +78,9 @@ void ScrollbarThemeGtk::paintTrackBackground(GraphicsContext* context, Scrollbar gtk_style_context_add_class(m_context, GTK_STYLE_CLASS_SCROLLBAR); gtk_style_context_add_class(m_context, GTK_STYLE_CLASS_TROUGH); - gtk_render_background(m_context, context->platformContext(), + gtk_render_background(m_context, context->platformContext()->cr(), fullScrollbarRect.x(), fullScrollbarRect.y(), fullScrollbarRect.width(), fullScrollbarRect.height()); - gtk_render_frame(m_context, context->platformContext(), + gtk_render_frame(m_context, context->platformContext()->cr(), fullScrollbarRect.x(), fullScrollbarRect.y(), fullScrollbarRect.width(), fullScrollbarRect.height()); gtk_style_context_restore(m_context); @@ -91,7 +92,7 @@ void ScrollbarThemeGtk::paintScrollbarBackground(GraphicsContext* context, Scrol gtk_style_context_add_class(m_context, GTK_STYLE_CLASS_SCROLLBAR); gtk_style_context_add_class(m_context, "scrolled-window"); - gtk_render_frame(m_context, context->platformContext(), scrollbar->x(), scrollbar->y(), scrollbar->width(), scrollbar->height()); + gtk_render_frame(m_context, context->platformContext()->cr(), scrollbar->x(), scrollbar->y(), scrollbar->width(), scrollbar->height()); gtk_style_context_restore(m_context); } @@ -110,7 +111,7 @@ void ScrollbarThemeGtk::paintThumb(GraphicsContext* context, Scrollbar* scrollba flags |= GTK_STATE_FLAG_PRELIGHT; gtk_style_context_set_state(m_context, static_cast<GtkStateFlags>(flags)); - gtk_render_slider(m_context, context->platformContext(), rect.x(), rect.y(), rect.width(), rect.height(), + gtk_render_slider(m_context, context->platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height(), scrollbar->orientation() == VerticalScrollbar ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL); gtk_style_context_restore(m_context); @@ -136,8 +137,8 @@ void ScrollbarThemeGtk::paintButton(GraphicsContext* context, Scrollbar* scrollb gtk_style_context_set_state(m_context, static_cast<GtkStateFlags>(flags)); gtk_style_context_add_class(m_context, GTK_STYLE_CLASS_BUTTON); - gtk_render_background(m_context, context->platformContext(), rect.x(), rect.y(), rect.width(), rect.height()); - gtk_render_frame(m_context, context->platformContext(), rect.x(), rect.y(), rect.width(), rect.height()); + gtk_render_background(m_context, context->platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height()); + gtk_render_frame(m_context, context->platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height()); gfloat arrowScaling; gtk_style_context_get_style(m_context, "arrow-scaling", &arrowScaling, NULL); @@ -162,7 +163,7 @@ void ScrollbarThemeGtk::paintButton(GraphicsContext* context, Scrollbar* scrollb angle = (part == ForwardButtonEndPart || part == ForwardButtonStartPart) ? G_PI / 2 : 3 * (G_PI / 2); } - gtk_render_arrow(m_context, context->platformContext(), angle, arrowPoint.x(), arrowPoint.y(), arrowSize); + gtk_render_arrow(m_context, context->platformContext()->cr(), angle, arrowPoint.x(), arrowPoint.y(), arrowSize); gtk_style_context_restore(m_context); } diff --git a/Source/WebCore/platform/image-decoders/ImageDecoder.cpp b/Source/WebCore/platform/image-decoders/ImageDecoder.cpp index e59d461..24a9f90 100644 --- a/Source/WebCore/platform/image-decoders/ImageDecoder.cpp +++ b/Source/WebCore/platform/image-decoders/ImageDecoder.cpp @@ -172,7 +172,7 @@ void ImageFrame::zeroFillPixelData() m_hasAlpha = true; } -#if !PLATFORM(CG) +#if !USE(CG) void ImageFrame::copyReferenceToBitmapData(const ImageFrame& other) { diff --git a/Source/WebCore/platform/image-decoders/ImageDecoder.h b/Source/WebCore/platform/image-decoders/ImageDecoder.h index 801daf3..f45d708 100644 --- a/Source/WebCore/platform/image-decoders/ImageDecoder.h +++ b/Source/WebCore/platform/image-decoders/ImageDecoder.h @@ -147,7 +147,7 @@ namespace WebCore { #endif private: -#if PLATFORM(CG) +#if USE(CG) typedef RetainPtr<CFMutableDataRef> NativeBackingStore; #else typedef Vector<PixelData> NativeBackingStore; diff --git a/Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.cpp b/Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.cpp index 060c62a..eacfd29 100644 --- a/Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.cpp +++ b/Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.cpp @@ -38,6 +38,8 @@ namespace WebCore { WEBPImageDecoder::WEBPImageDecoder(ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption) : ImageDecoder(alphaOption, gammaAndColorProfileOption) + , m_decoder(0) + , m_lastVisibleRow(0) { } @@ -79,12 +81,13 @@ bool WEBPImageDecoder::decode(bool onlySize) if (failed()) return false; + const size_t dataSize = m_data->size(); - const uint8_t* dataBytes = - reinterpret_cast<const uint8_t*>(m_data->data()); - int width, height; if (dataSize < sizeOfHeader) return true; + + int width, height; + const uint8_t* dataBytes = reinterpret_cast<const uint8_t*>(m_data->data()); if (!WebPGetInfo(dataBytes, dataSize, &width, &height)) return setFailed(); if (!ImageDecoder::isSizeAvailable() && !setSize(width, height)) @@ -92,9 +95,8 @@ bool WEBPImageDecoder::decode(bool onlySize) if (onlySize) return true; - // FIXME: Add support for progressive decoding. - if (!isAllDataReceived()) - return true; + bool allDataReceived = isAllDataReceived(); + int stride = width * bytesPerPixel; ASSERT(!m_frameBufferCache.isEmpty()); ImageFrame& buffer = m_frameBufferCache[0]; if (buffer.status() == ImageFrame::FrameEmpty) { @@ -102,22 +104,41 @@ bool WEBPImageDecoder::decode(bool onlySize) ASSERT(height == size().height()); if (!buffer.setSize(width, height)) return setFailed(); + buffer.setStatus(allDataReceived ? ImageFrame::FrameComplete : ImageFrame::FramePartial); + // FIXME: We currently hard code false below because libwebp doesn't support alpha yet. + buffer.setHasAlpha(false); + buffer.setOriginalFrameRect(IntRect(IntPoint(), size())); + m_rgbOutput.resize(height * stride); + } + int newLastVisibleRow = 0; // Last completed row. + if (allDataReceived) { + if (!WebPDecodeRGBInto(dataBytes, dataSize, m_rgbOutput.data(), m_rgbOutput.size(), stride)) + return setFailed(); + newLastVisibleRow = height; + } else { + if (!m_decoder) { + m_decoder = WebPINewRGB(MODE_RGB, m_rgbOutput.data(), m_rgbOutput.size(), stride); + if (!m_decoder) + return setFailed(); + } + const VP8StatusCode status = WebPIUpdate(m_decoder, dataBytes, dataSize); + if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) + return setFailed(); + if (!WebPIDecGetRGB(m_decoder, &newLastVisibleRow, 0, 0, 0)) + return setFailed(); + ASSERT(newLastVisibleRow >= 0); + ASSERT(newLastVisibleRow <= height); } - const int stride = width * bytesPerPixel; - Vector<uint8_t> rgb; - rgb.resize(height * stride); - if (!WebPDecodeBGRInto(dataBytes, dataSize, rgb.data(), rgb.size(), stride)) - return setFailed(); // FIXME: remove this data copy. - for (int y = 0; y < height; ++y) { - const uint8_t* const src = &rgb[y * stride]; + for (int y = m_lastVisibleRow; y < newLastVisibleRow; ++y) { + const uint8_t* const src = &m_rgbOutput[y * stride]; for (int x = 0; x < width; ++x) - buffer.setRGBA(x, y, src[bytesPerPixel * x + 2], src[bytesPerPixel * x + 1], src[bytesPerPixel * x + 0], 0xff); + buffer.setRGBA(x, y, src[bytesPerPixel * x + 0], src[bytesPerPixel * x + 1], src[bytesPerPixel * x + 2], 0xff); } - buffer.setStatus(ImageFrame::FrameComplete); - buffer.setHasAlpha(false); - buffer.setOriginalFrameRect(IntRect(IntPoint(), size())); - return true; + m_lastVisibleRow = newLastVisibleRow; + if (m_lastVisibleRow == height) + buffer.setStatus(ImageFrame::FrameComplete); + return m_lastVisibleRow == height; } } diff --git a/Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.h b/Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.h index c32e047..53da91f 100644 --- a/Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.h +++ b/Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.h @@ -33,6 +33,9 @@ #if USE(WEBP) +// Forward declaration of libwebp's structure. Must be outside the WebCore scope. +typedef struct WebPIDecoder WebPIDecoder; + namespace WebCore { class WEBPImageDecoder : public ImageDecoder { @@ -46,6 +49,10 @@ public: private: // Returns false in case of decoding failure. bool decode(bool onlySize); + + WebPIDecoder* m_decoder; // This is only used when we want to decode() but not all data is available yet. + int m_lastVisibleRow; + Vector<uint8_t> m_rgbOutput; }; } // namespace WebCore diff --git a/Source/WebCore/platform/leveldb/LevelDBComparator.h b/Source/WebCore/platform/leveldb/LevelDBComparator.h new file mode 100644 index 0000000..08ac261 --- /dev/null +++ b/Source/WebCore/platform/leveldb/LevelDBComparator.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 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 LevelDBComparator_h +#define LevelDBComparator_h + +#if ENABLE(LEVELDB) + +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class LevelDBSlice; + +class LevelDBComparator { +public: + virtual ~LevelDBComparator() {} + + virtual int compare(const LevelDBSlice&, const LevelDBSlice&) const = 0; + virtual const char* name() const = 0; +}; + +} // namespace WebCore + +#endif // ENABLE(LEVELDB) +#endif // LevelDBComparator_h diff --git a/Source/WebCore/platform/leveldb/LevelDBDatabase.cpp b/Source/WebCore/platform/leveldb/LevelDBDatabase.cpp new file mode 100644 index 0000000..4587631 --- /dev/null +++ b/Source/WebCore/platform/leveldb/LevelDBDatabase.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "LevelDBDatabase.h" + +#if ENABLE(LEVELDB) + +#include "LevelDBComparator.h" +#include "LevelDBIterator.h" +#include "LevelDBSlice.h" +#include <leveldb/comparator.h> +#include <leveldb/db.h> +#include <leveldb/slice.h> +#include <string> +#include <wtf/PassOwnPtr.h> +#include <wtf/text/CString.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +static leveldb::Slice makeSlice(const Vector<char>& value) +{ + return leveldb::Slice(value.data(), value.size()); +} + +static leveldb::Slice makeSlice(const LevelDBSlice& s) +{ + return leveldb::Slice(s.begin(), s.end() - s.begin()); +} + +static LevelDBSlice makeLevelDBSlice(const leveldb::Slice& s) +{ + return LevelDBSlice(s.data(), s.data() + s.size()); +} + +static Vector<char> makeVector(const std::string& s) +{ + Vector<char> res; + res.append(s.c_str(), s.length()); + return res; +} + +namespace { +class ComparatorAdapter : public leveldb::Comparator { +public: + ComparatorAdapter(const LevelDBComparator* comparator) + : m_comparator(comparator) + { + } + + virtual int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const + { + return m_comparator->compare(makeLevelDBSlice(a), makeLevelDBSlice(b)); + } + + virtual const char* Name() const { return m_comparator->name(); } + + // FIXME: Support the methods below in the future. + virtual void FindShortestSeparator(std::string* start, const leveldb::Slice& limit) const { } + virtual void FindShortSuccessor(std::string* key) const { } + +private: + const LevelDBComparator* m_comparator; +}; +} + +LevelDBDatabase::LevelDBDatabase() + : m_db(0) +{ +} + +LevelDBDatabase::~LevelDBDatabase() +{ +} + +LevelDBDatabase* LevelDBDatabase::open(const String& fileName, const LevelDBComparator* comparator) +{ + OwnPtr<ComparatorAdapter> comparatorAdapter(new ComparatorAdapter(comparator)); + + LevelDBDatabase* result = new LevelDBDatabase(); + + leveldb::Options options; + options.comparator = comparatorAdapter.get(); + options.create_if_missing = true; + leveldb::DB* db; + leveldb::Status s = leveldb::DB::Open(options, fileName.utf8().data(), &db); + + if (!s.ok()) { + delete result; + return 0; + } + + result->m_db = WTF::adoptPtr(db); + result->m_comparatorAdapter = comparatorAdapter.release(); + + return result; +} + + +bool LevelDBDatabase::put(const LevelDBSlice& key, const Vector<char>& value) +{ + leveldb::WriteOptions writeOptions; + writeOptions.sync = false; + + return m_db->Put(writeOptions, makeSlice(key), makeSlice(value)).ok(); +} + +bool LevelDBDatabase::remove(const LevelDBSlice& key) +{ + leveldb::WriteOptions writeOptions; + writeOptions.sync = false; + + return m_db->Delete(writeOptions, makeSlice(key)).ok(); +} + +bool LevelDBDatabase::get(const LevelDBSlice& key, Vector<char>& value) +{ + std::string result; + if (!m_db->Get(leveldb::ReadOptions(), makeSlice(key), &result).ok()) + return false; + + value = makeVector(result); + return true; +} + +LevelDBIterator* LevelDBDatabase::newIterator() +{ + leveldb::Iterator* i = m_db->NewIterator(leveldb::ReadOptions()); + if (!i) // FIXME: Double check if we actually need to check this. + return 0; + return new LevelDBIterator(i); +} + +} // namespace WebCore + +#endif // ENABLE(LEVELDB) diff --git a/Source/WebCore/platform/leveldb/LevelDBDatabase.h b/Source/WebCore/platform/leveldb/LevelDBDatabase.h new file mode 100644 index 0000000..471f335 --- /dev/null +++ b/Source/WebCore/platform/leveldb/LevelDBDatabase.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 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 LevelDBDatabase_h +#define LevelDBDatabase_h + +#if ENABLE(LEVELDB) + +#include "PlatformString.h" +#include <OwnPtr.h> +#include <Vector.h> + +namespace leveldb { +class Comparator; +class DB; +} + +namespace WebCore { + +class LevelDBComparator; +class LevelDBIterator; +class LevelDBSlice; + +class LevelDBDatabase { +public: + static LevelDBDatabase* open(const String& fileName, const LevelDBComparator*); + ~LevelDBDatabase(); + + bool put(const LevelDBSlice& key, const Vector<char>& value); + bool remove(const LevelDBSlice& key); + bool get(const LevelDBSlice& key, Vector<char>& value); + LevelDBIterator* newIterator(); + +private: + LevelDBDatabase(); + + OwnPtr<leveldb::DB> m_db; + OwnPtr<leveldb::Comparator> m_comparatorAdapter; +}; + +} // namespace WebCore + +#endif // ENABLE(LEVELDB) +#endif // LevelDBDatabase_h diff --git a/Source/WebCore/platform/mac/RuntimeApplicationChecks.mm b/Source/WebCore/platform/leveldb/LevelDBIterator.cpp index 7fe8378..de0f286 100644 --- a/Source/WebCore/platform/mac/RuntimeApplicationChecks.mm +++ b/Source/WebCore/platform/leveldb/LevelDBIterator.cpp @@ -1,15 +1,15 @@ /* - * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2011 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * 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. + * 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 @@ -23,46 +23,72 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#import "config.h" -#import "RuntimeApplicationChecks.h" +#include "config.h" +#include "LevelDBIterator.h" +#if ENABLE(LEVELDB) + +#include <leveldb/iterator.h> +#include <leveldb/slice.h> +#include <wtf/text/CString.h> +#include <wtf/text/WTFString.h> namespace WebCore { -bool applicationIsAppleMail() +LevelDBIterator::~LevelDBIterator() +{ +} + +LevelDBIterator::LevelDBIterator(leveldb::Iterator* it) + : m_iterator(it) +{ +} + +static leveldb::Slice makeSlice(const Vector<char>& value) +{ + return leveldb::Slice(value.data(), value.size()); +} + +static LevelDBSlice makeLevelDBSlice(leveldb::Slice s) { - static const bool isAppleMail = [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.mail"]; - return isAppleMail; + return LevelDBSlice(s.data(), s.data() + s.size()); } -bool applicationIsSafari() +bool LevelDBIterator::isValid() const { - static const bool isSafari = [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Safari"]; - return isSafari; + return m_iterator->Valid(); } -bool applicationIsMicrosoftMessenger() +void LevelDBIterator::seekToLast() { - static bool isMicrosoftMessenger = [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.microsoft.Messenger"]; - return isMicrosoftMessenger; + m_iterator->SeekToLast(); } -bool applicationIsAdobeInstaller() +void LevelDBIterator::seek(const Vector<char>& target) { - static bool isAdobeInstaller = [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.adobe.Installers.Setup"]; - return isAdobeInstaller; + m_iterator->Seek(makeSlice(target)); } - -bool applicationIsAOLInstantMessenger() + +void LevelDBIterator::next() +{ + m_iterator->Next(); +} + +void LevelDBIterator::prev() { - static bool isAOLInstantMessenger = [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.aol.aim.desktop"]; - return isAOLInstantMessenger; + m_iterator->Prev(); } -bool applicationIsMicrosoftMyDay() +LevelDBSlice LevelDBIterator::key() const { - static bool isMicrosoftMyDay = [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.microsoft.myday"]; - return isMicrosoftMyDay; + return makeLevelDBSlice(m_iterator->key()); +} + +LevelDBSlice LevelDBIterator::value() const +{ + return makeLevelDBSlice(m_iterator->value()); } } // namespace WebCore + +#endif // ENABLE(LEVELDB) diff --git a/Source/WebCore/platform/leveldb/LevelDBIterator.h b/Source/WebCore/platform/leveldb/LevelDBIterator.h new file mode 100644 index 0000000..ff9cbca --- /dev/null +++ b/Source/WebCore/platform/leveldb/LevelDBIterator.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 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 LevelDBIterator_h +#define LevelDBIterator_h + +#if ENABLE(LEVELDB) + +#include "LevelDBSlice.h" +#include "PlatformString.h" +#include <OwnPtr.h> +#include <Vector.h> + +namespace leveldb { +class Iterator; +} + +namespace WebCore { + +class LevelDBIterator { +public: + ~LevelDBIterator(); + + bool isValid() const; + void seekToLast(); + void seek(const Vector<char>& target); + void next(); + void prev(); + LevelDBSlice key() const; + LevelDBSlice value() const; + +private: + LevelDBIterator(leveldb::Iterator*); + friend class LevelDBDatabase; + + OwnPtr<leveldb::Iterator> m_iterator; +}; + + +} // namespace WebCore + +#endif // ENABLE(LEVELDB) +#endif // LevelDBIterator_h diff --git a/Source/WebCore/platform/leveldb/LevelDBSlice.h b/Source/WebCore/platform/leveldb/LevelDBSlice.h new file mode 100644 index 0000000..15c576c --- /dev/null +++ b/Source/WebCore/platform/leveldb/LevelDBSlice.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 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 LevelDBSlice_h +#define LevelDBSlice_h + +#if ENABLE(LEVELDB) + +#include "PlatformString.h" +#include <Vector.h> + +namespace WebCore { + +class LevelDBSlice { +public: + LevelDBSlice(const char* begin, const char* end) + : m_begin(begin) + , m_end(end) + { + ASSERT(m_end >= m_begin); + } + + LevelDBSlice(const Vector<char>& v) + : m_begin(v.data()) + , m_end(m_begin + v.size()) + { + ASSERT(m_end >= m_begin); + } + + ~LevelDBSlice() + { + } + + const char* begin() const { return m_begin; } + const char* end() const { return m_end; } + +private: + const char* m_begin; + const char* m_end; +}; + +} // namespace WebCore + +#endif // ENABLE(LEVELDB) +#endif // LevelDBSlice_h diff --git a/Source/WebCore/platform/mac/ClipboardMac.mm b/Source/WebCore/platform/mac/ClipboardMac.mm index a41982a..a5005eb 100644 --- a/Source/WebCore/platform/mac/ClipboardMac.mm +++ b/Source/WebCore/platform/mac/ClipboardMac.mm @@ -49,7 +49,7 @@ namespace WebCore { PassRefPtr<Clipboard> Clipboard::create(ClipboardAccessPolicy policy, DragData* dragData, Frame* frame) { - return ClipboardMac::create(DragAndDrop, [dragData->platformData() draggingPasteboard], policy, frame); + return ClipboardMac::create(DragAndDrop, dragData->pasteboard(), policy, frame); } ClipboardMac::ClipboardMac(ClipboardType clipboardType, NSPasteboard *pasteboard, ClipboardAccessPolicy policy, Frame *frame) diff --git a/Source/WebCore/platform/mac/DragDataMac.mm b/Source/WebCore/platform/mac/DragDataMac.mm index 64376b1..41d23db 100644 --- a/Source/WebCore/platform/mac/DragDataMac.mm +++ b/Source/WebCore/platform/mac/DragDataMac.mm @@ -104,7 +104,7 @@ String DragData::asPlainText(Frame *frame) const Color DragData::asColor() const { - NSColor *color = [NSColor colorFromPasteboard:[m_platformDragData draggingPasteboard]]; + NSColor *color = [NSColor colorFromPasteboard:m_pasteboard.get()]; return makeRGBA((int)([color redComponent] * 255.0 + 0.5), (int)([color greenComponent] * 255.0 + 0.5), (int)([color blueComponent] * 255.0 + 0.5), (int)([color alphaComponent] * 255.0 + 0.5)); } @@ -141,7 +141,7 @@ String DragData::asURL(Frame* frame, FilenameConversionPolicy filenamePolicy, St (void)filenamePolicy; if (title) { - if (NSString *URLTitleString = [[m_platformDragData draggingPasteboard] stringForType:WebURLNamePboardType]) + if (NSString *URLTitleString = [m_pasteboard.get() stringForType:WebURLNamePboardType]) *title = URLTitleString; } Pasteboard pasteboard(m_pasteboard.get()); diff --git a/Source/WebCore/platform/mac/HTMLConverter.h b/Source/WebCore/platform/mac/HTMLConverter.h index 645c1d7..3250769 100644 --- a/Source/WebCore/platform/mac/HTMLConverter.h +++ b/Source/WebCore/platform/mac/HTMLConverter.h @@ -23,12 +23,12 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#import "DOM.h" -#import "DOMDocument.h" -#import "DOMRange.h" +@class DOMDocument; +@class DOMRange; namespace WebCore { -class DocumentLoader; + class DocumentLoader; + class Range; } @interface WebHTMLConverter : NSObject { @@ -79,10 +79,13 @@ class DocumentLoader; } _flags; } +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) - (id)init; - (id)initWithDOMRange:(DOMRange *)domRange; - (NSAttributedString *)attributedString; +#endif ++ (NSAttributedString *)editingAttributedStringFromRange:(WebCore::Range*)range; @end diff --git a/Source/WebCore/platform/mac/HTMLConverter.mm b/Source/WebCore/platform/mac/HTMLConverter.mm index a4864c2..c0b0ba2 100644 --- a/Source/WebCore/platform/mac/HTMLConverter.mm +++ b/Source/WebCore/platform/mac/HTMLConverter.mm @@ -27,26 +27,35 @@ #import "HTMLConverter.h" #import "ArchiveResource.h" +#import "ColorMac.h" #import "Document.h" #import "DocumentLoader.h" #import "DOMDocumentInternal.h" #import "DOMElementInternal.h" #import "DOMHTMLTableCellElement.h" #import "DOMPrivate.h" +#import "DOMRangeInternal.h" #import "Element.h" #import "Frame.h" #import "HTMLNames.h" #import "HTMLParserIdioms.h" +#import "LoaderNSURLExtras.h" +#import "RenderImage.h" +#import "TextIterator.h" #import <wtf/ASCIICType.h> using namespace WebCore; using namespace HTMLNames; +static NSFileWrapper *fileWrapperForURL(DocumentLoader *, NSURL *); +static NSFileWrapper *fileWrapperForElement(Element*); + #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + // Additional control Unicode characters const unichar WebNextLineCharacter = 0x0085; -@interface NSTextList (TextListPrivate) +@interface NSTextList (WebCoreNSTextListDetails) + (NSDictionary *)_standardMarkerAttributesForAttributes:(NSDictionary *)attrs; @end @@ -55,14 +64,12 @@ const unichar WebNextLineCharacter = 0x0085; - (BOOL)ignoresOrientation; @end -@interface NSURL (WebDataURL) -+ (NSURL *)_web_uniqueWebDataURL; -+ (NSURL *)_web_uniqueWebDataURLWithRelativeString:(NSString *)string; +@interface NSURL (WebCoreNSURLDetails) +// FIXME: What is the reason to use this Foundation method, and not +[NSURL URLWithString:relativeToURL:]? + (NSURL *)_web_URLWithString:(NSString *)string relativeToURL:(NSURL *)baseURL; -- (NSString *)_web_suggestedFilenameWithMIMEType:(NSString *)MIMEType; @end -@interface WebHTMLConverter(WebHTMLConverterPrivate) +@interface WebHTMLConverter(WebHTMLConverterInternal) - (NSString *)_stringForNode:(DOMNode *)node property:(NSString *)key; - (NSColor *)_colorForNode:(DOMNode *)node property:(NSString *)key; @@ -89,8 +96,12 @@ static NSFont *WebDefaultFont() return defaultFont; } +#endif + @implementation WebHTMLConverter +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + static NSFont *_fontForNameAndSize(NSString *fontName, CGFloat size, NSMutableDictionary *cache) { NSFontManager *fontManager = [NSFontManager sharedFontManager]; @@ -769,39 +780,6 @@ static inline NSShadow *_shadowForShadowStyle(NSString *shadowStyle) [string release]; _flags.isSoft = YES; } - -static NSFileWrapper *fileWrapperForURL(DocumentLoader *dataSource, NSURL *URL) -{ - if ([URL isFileURL]) { - NSString *path = [[URL path] stringByResolvingSymlinksInPath]; - return [[[NSFileWrapper alloc] initWithPath:path] autorelease]; - } - - RefPtr<ArchiveResource> resource = dataSource->subresource(URL); - if (resource) { - NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:[resource->data()->createNSData() autorelease]] autorelease]; - NSString *filename = resource->response().suggestedFilename(); - if (!filename || ![filename length]) { - NSURL *URL = resource->url(); - filename = [URL _web_suggestedFilenameWithMIMEType:resource->mimeType()]; - } - [wrapper setPreferredFilename:filename]; - return wrapper; - } - - NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL]; - - NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request]; - [request release]; - - if (cachedResponse) { - NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:[cachedResponse data]] autorelease]; - [wrapper setPreferredFilename:[[cachedResponse response] suggestedFilename]]; - return wrapper; - } - - return nil; -} - (BOOL)_addAttachmentForElement:(DOMElement *)element URL:(NSURL *)url needsParagraph:(BOOL)needsParagraph usePlaceholder:(BOOL)flag { @@ -823,7 +801,7 @@ static NSFileWrapper *fileWrapperForURL(DocumentLoader *dataSource, NSURL *URL) if (flag && resource && [@"text/html" isEqual:resource->mimeType()]) notFound = YES; if (resource && !notFound) { fileWrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:[resource->data()->createNSData() autorelease]] autorelease]; - [fileWrapper setPreferredFilename:[url _web_suggestedFilenameWithMIMEType:resource->mimeType()]]; + [fileWrapper setPreferredFilename:suggestedFilenameWithMIMEType(url, resource->mimeType())]; } } if (!fileWrapper && !notFound) { @@ -1672,11 +1650,119 @@ static NSInteger _colCompare(id block1, id block2, void *) return self; } +// This function supports more HTML features than the editing variant below, such as tables. - (NSAttributedString *)attributedString { [self _loadFromDOMRange]; return (0 == _errorCode) ? [[_attrStr retain] autorelease] : nil; } +#endif // !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + +// This function uses TextIterator, which makes offsets in its result compatible with HTML editing. ++ (NSAttributedString *)editingAttributedStringFromRange:(Range*)range +{ + NSMutableAttributedString *string = [[NSMutableAttributedString alloc] init]; + NSUInteger stringLength = 0; + RetainPtr<NSMutableDictionary> attrs(AdoptNS, [[NSMutableDictionary alloc] init]); + + for (TextIterator it(range); !it.atEnd(); it.advance()) { + RefPtr<Range> currentTextRange = it.range(); + ExceptionCode ec = 0; + Node* startContainer = currentTextRange->startContainer(ec); + Node* endContainer = currentTextRange->endContainer(ec); + int startOffset = currentTextRange->startOffset(ec); + int endOffset = currentTextRange->endOffset(ec); + + if (startContainer == endContainer && (startOffset == endOffset - 1)) { + Node* node = startContainer->childNode(startOffset); + if (node && node->hasTagName(imgTag)) { + NSFileWrapper *fileWrapper = fileWrapperForElement(static_cast<Element*>(node)); + NSTextAttachment *attachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper]; + [string appendAttributedString:[NSAttributedString attributedStringWithAttachment:attachment]]; + [attachment release]; + } + } + + int currentTextLength = it.length(); + if (!currentTextLength) + continue; + + RenderObject* renderer = startContainer->renderer(); + ASSERT(renderer); + if (!renderer) + continue; + RenderStyle* style = renderer->style(); + NSFont *font = style->font().primaryFont()->getNSFont(); + [attrs.get() setObject:font forKey:NSFontAttributeName]; + if (style->visitedDependentColor(CSSPropertyColor).alpha()) + [attrs.get() setObject:nsColor(style->visitedDependentColor(CSSPropertyColor)) forKey:NSForegroundColorAttributeName]; + else + [attrs.get() removeObjectForKey:NSForegroundColorAttributeName]; + if (style->visitedDependentColor(CSSPropertyBackgroundColor).alpha()) + [attrs.get() setObject:nsColor(style->visitedDependentColor(CSSPropertyBackgroundColor)) forKey:NSBackgroundColorAttributeName]; + else + [attrs.get() removeObjectForKey:NSBackgroundColorAttributeName]; + + RetainPtr<NSString> substring(AdoptNS, [[NSString alloc] initWithCharactersNoCopy:const_cast<UChar*>(it.characters()) length:currentTextLength freeWhenDone:NO]); + [string replaceCharactersInRange:NSMakeRange(stringLength, 0) withString:substring.get()]; + [string setAttributes:attrs.get() range:NSMakeRange(stringLength, currentTextLength)]; + stringLength += currentTextLength; + } + + return [string autorelease]; +} + @end -#endif + +static NSFileWrapper *fileWrapperForURL(DocumentLoader *dataSource, NSURL *URL) +{ + if ([URL isFileURL]) { + NSString *path = [[URL path] stringByResolvingSymlinksInPath]; + return [[[NSFileWrapper alloc] initWithPath:path] autorelease]; + } + + RefPtr<ArchiveResource> resource = dataSource->subresource(URL); + if (resource) { + NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:[resource->data()->createNSData() autorelease]] autorelease]; + NSString *filename = resource->response().suggestedFilename(); + if (!filename || ![filename length]) + filename = suggestedFilenameWithMIMEType(resource->url(), resource->mimeType()); + [wrapper setPreferredFilename:filename]; + return wrapper; + } + + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL]; + + NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request]; + [request release]; + + if (cachedResponse) { + NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:[cachedResponse data]] autorelease]; + [wrapper setPreferredFilename:[[cachedResponse response] suggestedFilename]]; + return wrapper; + } + + return nil; +} + +static NSFileWrapper *fileWrapperForElement(Element* element) +{ + NSFileWrapper *wrapper = nil; + + const AtomicString& attr = element->getAttribute(srcAttr); + if (!attr.isEmpty()) { + NSURL *URL = element->document()->completeURL(attr); + wrapper = fileWrapperForURL(element->document()->loader(), URL); + } + if (!wrapper) { + RenderImage* renderer = toRenderImage(element->renderer()); + if (renderer->cachedImage() && !renderer->cachedImage()->errorOccurred()) { + wrapper = [[NSFileWrapper alloc] initRegularFileWithContents:(NSData *)(renderer->cachedImage()->image()->getTIFFRepresentation())]; + [wrapper setPreferredFilename:@"image.tiff"]; + [wrapper autorelease]; + } + } + + return wrapper; +} diff --git a/Source/WebCore/platform/mac/PasteboardMac.mm b/Source/WebCore/platform/mac/PasteboardMac.mm index da06606..69782ab 100644 --- a/Source/WebCore/platform/mac/PasteboardMac.mm +++ b/Source/WebCore/platform/mac/PasteboardMac.mm @@ -38,9 +38,7 @@ #import "FrameLoaderClient.h" #import "HitTestResult.h" #import "HTMLAnchorElement.h" -#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) #import "HTMLConverter.h" -#endif #import "htmlediting.h" #import "HTMLNames.h" #import "Image.h" @@ -52,6 +50,7 @@ #import "RenderImage.h" #import "Text.h" #import "WebCoreNSStringExtras.h" +#import "WebNSAttributedStringExtras.h" #import "markup.h" #import <wtf/StdLibExtras.h> #import <wtf/RetainPtr.h> @@ -129,19 +128,6 @@ void Pasteboard::clear() [m_pasteboard.get() declareTypes:[NSArray array] owner:nil]; } -static NSAttributedString *stripAttachmentCharacters(NSAttributedString *string) -{ - const unichar attachmentCharacter = NSAttachmentCharacter; - DEFINE_STATIC_LOCAL(RetainPtr<NSString>, attachmentCharacterString, ([NSString stringWithCharacters:&attachmentCharacter length:1])); - NSMutableAttributedString *result = [[string mutableCopy] autorelease]; - NSRange attachmentRange = [[result string] rangeOfString:attachmentCharacterString.get()]; - while (attachmentRange.location != NSNotFound) { - [result replaceCharactersInRange:attachmentRange withString:@""]; - attachmentRange = [[result string] rangeOfString:attachmentCharacterString.get()]; - } - return result; -} - void Pasteboard::writeSelection(NSPasteboard* pasteboard, NSArray* pasteboardTypes, Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame) { if (!WebArchivePboardType) @@ -207,7 +193,7 @@ void Pasteboard::writeSelection(NSPasteboard* pasteboard, NSArray* pasteboardTyp } if ([types containsObject:NSRTFPboardType]) { if ([attributedString containsAttachments]) - attributedString = stripAttachmentCharacters(attributedString); + attributedString = attributedStringByStrippingAttachmentCharacters(attributedString); NSData *RTFData = [attributedString RTFFromRange:NSMakeRange(0, [attributedString length]) documentAttributes:nil]; [pasteboard setData:RTFData forType:NSRTFPboardType]; } diff --git a/Source/WebCore/platform/mac/ScrollAnimatorMac.h b/Source/WebCore/platform/mac/ScrollAnimatorMac.h index f7b6332..382052e 100644 --- a/Source/WebCore/platform/mac/ScrollAnimatorMac.h +++ b/Source/WebCore/platform/mac/ScrollAnimatorMac.h @@ -106,6 +106,8 @@ private: virtual void willEndLiveResize(); virtual void contentAreaDidShow() const; virtual void contentAreaDidHide() const; + void didBeginScrollGesture() const; + void didEndScrollGesture() const; virtual void didAddVerticalScrollbar(Scrollbar*); virtual void willRemoveVerticalScrollbar(Scrollbar*); diff --git a/Source/WebCore/platform/mac/ScrollAnimatorMac.mm b/Source/WebCore/platform/mac/ScrollAnimatorMac.mm index 5725880..321ef0f 100644 --- a/Source/WebCore/platform/mac/ScrollAnimatorMac.mm +++ b/Source/WebCore/platform/mac/ScrollAnimatorMac.mm @@ -100,6 +100,11 @@ static NSSize abs(NSSize size) _animator->immediateScrollToPoint(newPosition); } +- (NSPoint)_pixelAlignProposedScrollPosition:(NSPoint)newOrigin +{ + return newOrigin; +} + - (NSSize)convertSizeToBase:(NSSize)size { return abs(size); @@ -322,9 +327,9 @@ static NSSize abs(NSSize size) // Invalidate the scrollbars so that they paint the animation if (WebCore::Scrollbar* verticalScrollbar = _animator->scrollableArea()->verticalScrollbar()) - _animator->scrollableArea()->invalidateScrollbarRect(verticalScrollbar, WebCore::IntRect(0, 0, verticalScrollbar->width(), verticalScrollbar->height())); + verticalScrollbar->invalidateRect(WebCore::IntRect(0, 0, verticalScrollbar->width(), verticalScrollbar->height())); if (WebCore::Scrollbar* horizontalScrollbar = _animator->scrollableArea()->horizontalScrollbar()) - _animator->scrollableArea()->invalidateScrollbarRect(horizontalScrollbar, WebCore::IntRect(0, 0, horizontalScrollbar->width(), horizontalScrollbar->height())); + horizontalScrollbar->invalidateRect(WebCore::IntRect(0, 0, horizontalScrollbar->width(), horizontalScrollbar->height())); } - (void)scrollAnimatorDestroyed @@ -575,6 +580,9 @@ void ScrollAnimatorMac::immediateScrollToPoint(const FloatPoint& newPosition) { FloatPoint adjustedPosition = adjustScrollPositionIfNecessary(newPosition); + if (adjustedPosition.x() == m_currentPosX && adjustedPosition.y() == m_currentPosY) + return; + m_currentPosX = adjustedPosition.x(); m_currentPosY = adjustedPosition.y(); notityPositionChanged(); @@ -582,13 +590,23 @@ void ScrollAnimatorMac::immediateScrollToPoint(const FloatPoint& newPosition) void ScrollAnimatorMac::immediateScrollByDeltaX(float deltaX) { - m_currentPosX = adjustScrollXPositionIfNecessary(m_currentPosX + deltaX); + float newPosX = adjustScrollXPositionIfNecessary(m_currentPosX + deltaX); + + if (newPosX == m_currentPosX) + return; + + m_currentPosX = newPosX; notityPositionChanged(); } void ScrollAnimatorMac::immediateScrollByDeltaY(float deltaY) { - m_currentPosY = adjustScrollYPositionIfNecessary(m_currentPosY + deltaY); + float newPosY = adjustScrollYPositionIfNecessary(m_currentPosY + deltaY); + + if (newPosY == m_currentPosY) + return; + + m_currentPosY = newPosY; notityPositionChanged(); } @@ -663,6 +681,20 @@ void ScrollAnimatorMac::contentAreaDidHide() const #endif } +void ScrollAnimatorMac::didBeginScrollGesture() const +{ +#if USE(WK_SCROLLBAR_PAINTER) + wkDidBeginScrollGesture(m_scrollbarPainterController.get()); +#endif +} + +void ScrollAnimatorMac::didEndScrollGesture() const +{ +#if USE(WK_SCROLLBAR_PAINTER) + wkDidEndScrollGesture(m_scrollbarPainterController.get()); +#endif +} + void ScrollAnimatorMac::didAddVerticalScrollbar(Scrollbar* scrollbar) { #if USE(WK_SCROLLBAR_PAINTER) @@ -771,6 +803,22 @@ void ScrollAnimatorMac::handleWheelEvent(PlatformWheelEvent& wheelEvent) return; } + // FIXME: This is somewhat roundabout hack to allow forwarding wheel events + // up to the parent scrollable area. It takes advantage of the fact that + // the base class implemenatation of handleWheelEvent will not accept the + // wheel event if there is nowhere to scroll. + if (fabsf(wheelEvent.deltaY()) >= fabsf(wheelEvent.deltaX())) { + if (!allowsVerticalStretching()) { + ScrollAnimator::handleWheelEvent(wheelEvent); + return; + } + } else { + if (!allowsHorizontalStretching()) { + ScrollAnimator::handleWheelEvent(wheelEvent); + return; + } + } + wheelEvent.accept(); bool isMometumScrollEvent = (wheelEvent.momentumPhase() != PlatformWheelEventPhaseNone); @@ -819,21 +867,37 @@ bool ScrollAnimatorMac::pinnedInDirection(float deltaX, float deltaY) bool ScrollAnimatorMac::allowsVerticalStretching() const { - Scrollbar* hScroller = m_scrollableArea->horizontalScrollbar(); - Scrollbar* vScroller = m_scrollableArea->verticalScrollbar(); - if (((vScroller && vScroller->enabled()) || (!hScroller || !hScroller->enabled()))) + switch (m_scrollableArea->verticalScrollElasticity()) { + case ScrollElasticityAutomatic: { + Scrollbar* hScroller = m_scrollableArea->horizontalScrollbar(); + Scrollbar* vScroller = m_scrollableArea->verticalScrollbar(); + return (((vScroller && vScroller->enabled()) || (!hScroller || !hScroller->enabled()))); + } + case ScrollElasticityNone: + return false; + case ScrollElasticityAllowed: return true; + } + ASSERT_NOT_REACHED(); return false; } bool ScrollAnimatorMac::allowsHorizontalStretching() const { - Scrollbar* hScroller = m_scrollableArea->horizontalScrollbar(); - Scrollbar* vScroller = m_scrollableArea->verticalScrollbar(); - if (((hScroller && hScroller->enabled()) || (!vScroller || !vScroller->enabled()))) + switch (m_scrollableArea->horizontalScrollElasticity()) { + case ScrollElasticityAutomatic: { + Scrollbar* hScroller = m_scrollableArea->horizontalScrollbar(); + Scrollbar* vScroller = m_scrollableArea->verticalScrollbar(); + return (((hScroller && hScroller->enabled()) || (!vScroller || !vScroller->enabled()))); + } + case ScrollElasticityNone: + return false; + case ScrollElasticityAllowed: return true; + } + ASSERT_NOT_REACHED(); return false; } @@ -858,7 +922,7 @@ void ScrollAnimatorMac::smoothScrollWithEvent(PlatformWheelEvent& wheelEvent) deltaX = 0; else deltaY = 0; - + bool isVerticallyStretched = false; bool isHorizontallyStretched = false; bool shouldStretch = false; @@ -993,6 +1057,8 @@ void ScrollAnimatorMac::smoothScrollWithEvent(PlatformWheelEvent& wheelEvent) void ScrollAnimatorMac::beginScrollGesture() { + didBeginScrollGesture(); + m_haveScrolledSincePageLoad = true; m_inScrollGesture = true; m_momentumScrollInProgress = false; @@ -1012,6 +1078,8 @@ void ScrollAnimatorMac::beginScrollGesture() void ScrollAnimatorMac::endScrollGesture() { + didEndScrollGesture(); + snapRubberBand(); } diff --git a/Source/WebCore/platform/mac/WebCoreSystemInterface.h b/Source/WebCore/platform/mac/WebCoreSystemInterface.h index 308a551..3c9850b 100644 --- a/Source/WebCore/platform/mac/WebCoreSystemInterface.h +++ b/Source/WebCore/platform/mac/WebCoreSystemInterface.h @@ -29,7 +29,7 @@ #include <ApplicationServices/ApplicationServices.h> #include <objc/objc.h> -#if PLATFORM(MAC) && PLATFORM(CA) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) +#if PLATFORM(MAC) && USE(CA) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) #include <IOSurface/IOSurface.h> #endif @@ -155,11 +155,12 @@ extern void (*wkSignalCFReadStreamError)(CFReadStreamRef stream, CFStreamError * extern void (*wkSignalCFReadStreamHasBytes)(CFReadStreamRef stream); extern unsigned (*wkInitializeMaximumHTTPConnectionCountPerHost)(unsigned preferredConnectionCount); extern int (*wkGetHTTPPipeliningPriority)(NSURLRequest *); +extern void (*wkSetHTTPPipeliningMaximumPriority)(int maximumPriority); extern void (*wkSetHTTPPipeliningPriority)(NSMutableURLRequest *, int priority); +extern void (*wkSetHTTPPipeliningMinimumFastLanePriority)(int priority); extern void (*wkSetCONNECTProxyForStream)(CFReadStreamRef, CFStringRef proxyHost, CFNumberRef proxyPort); extern void (*wkSetCONNECTProxyAuthorizationForStream)(CFReadStreamRef, CFStringRef proxyAuthorizationString); extern CFHTTPMessageRef (*wkCopyCONNECTProxyResponse)(CFReadStreamRef, CFURLRef responseURL); -extern BOOL (*wkIsLatchingWheelEvent)(NSEvent *); #ifndef BUILDING_ON_TIGER extern void (*wkGetGlyphsForCharacters)(CGFontRef, const UniChar[], CGGlyph[], size_t); @@ -187,6 +188,15 @@ extern BOOL (*wkUseSharedMediaUI)(); extern void* wkGetHyphenationLocationBeforeIndex; #else extern CFIndex (*wkGetHyphenationLocationBeforeIndex)(CFStringRef string, CFIndex index); + +typedef enum { + wkEventPhaseNone = 0, + wkEventPhaseBegan = 1, + wkEventPhaseChanged = 2, + wkEventPhaseEnded = 3, +} wkEventPhase; + +extern int (*wkGetNSEventMomentumPhase)(NSEvent *); #endif extern CTLineRef (*wkCreateCTLineWithUniCharProvider)(const UniChar* (*provide)(CFIndex stringIndex, CFIndex* charCount, CFDictionaryRef* attributes, void*), void (*dispose)(const UniChar* chars, void*), void*); @@ -229,6 +239,8 @@ extern void (*wkContentAreaResized)(WKScrollbarPainterControllerRef); extern void (*wkWillEndLiveResize)(WKScrollbarPainterControllerRef); extern void (*wkContentAreaDidShow)(WKScrollbarPainterControllerRef); extern void (*wkContentAreaDidHide)(WKScrollbarPainterControllerRef); +extern void (*wkDidBeginScrollGesture)(WKScrollbarPainterControllerRef); +extern void (*wkDidEndScrollGesture)(WKScrollbarPainterControllerRef); extern bool (*wkScrollbarPainterUsesOverlayScrollers)(void); #endif diff --git a/Source/WebCore/platform/mac/WebCoreSystemInterface.mm b/Source/WebCore/platform/mac/WebCoreSystemInterface.mm index ab059bd..6a78ff6 100644 --- a/Source/WebCore/platform/mac/WebCoreSystemInterface.mm +++ b/Source/WebCore/platform/mac/WebCoreSystemInterface.mm @@ -91,11 +91,12 @@ void (*wkSetNSURLRequestShouldContentSniff)(NSMutableURLRequest *, BOOL); id (*wkCreateNSURLConnectionDelegateProxy)(void); unsigned (*wkInitializeMaximumHTTPConnectionCountPerHost)(unsigned preferredConnectionCount); int (*wkGetHTTPPipeliningPriority)(NSURLRequest *); +void (*wkSetHTTPPipeliningMaximumPriority)(int priority); void (*wkSetHTTPPipeliningPriority)(NSMutableURLRequest *, int priority); +void (*wkSetHTTPPipeliningMinimumFastLanePriority)(int priority); void (*wkSetCONNECTProxyForStream)(CFReadStreamRef, CFStringRef proxyHost, CFNumberRef proxyPort); void (*wkSetCONNECTProxyAuthorizationForStream)(CFReadStreamRef, CFStringRef proxyAuthorizationString); CFHTTPMessageRef (*wkCopyCONNECTProxyResponse)(CFReadStreamRef, CFURLRef responseURL); -BOOL (*wkIsLatchingWheelEvent)(NSEvent *); #ifndef BUILDING_ON_TIGER void (*wkGetGlyphsForCharacters)(CGFontRef, const UniChar[], CGGlyph[], size_t); @@ -120,6 +121,7 @@ BOOL (*wkSupportsMultipartXMixedReplace)(NSMutableURLRequest *); void* wkGetHyphenationLocationBeforeIndex; #else CFIndex (*wkGetHyphenationLocationBeforeIndex)(CFStringRef string, CFIndex index); +int (*wkGetNSEventMomentumPhase)(NSEvent *); #endif CTLineRef (*wkCreateCTLineWithUniCharProvider)(const UniChar* (*provide)(CFIndex stringIndex, CFIndex* charCount, CFDictionaryRef* attributes, void*), void (*dispose)(const UniChar* chars, void*), void*); @@ -159,6 +161,8 @@ void (*wkContentAreaResized)(WKScrollbarPainterControllerRef); void (*wkWillEndLiveResize)(WKScrollbarPainterControllerRef); void (*wkContentAreaDidShow)(WKScrollbarPainterControllerRef); void (*wkContentAreaDidHide)(WKScrollbarPainterControllerRef); +void (*wkDidBeginScrollGesture)(WKScrollbarPainterControllerRef); +void (*wkDidEndScrollGesture)(WKScrollbarPainterControllerRef); bool (*wkScrollbarPainterUsesOverlayScrollers)(void); #endif diff --git a/Source/WebCore/platform/mac/WebNSAttributedStringExtras.h b/Source/WebCore/platform/mac/WebNSAttributedStringExtras.h new file mode 100644 index 0000000..ce4cfe4 --- /dev/null +++ b/Source/WebCore/platform/mac/WebNSAttributedStringExtras.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2005, 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +namespace WebCore { + +NSAttributedString *attributedStringByStrippingAttachmentCharacters(NSAttributedString *); + +} diff --git a/Source/WebCore/platform/mac/WebNSAttributedStringExtras.mm b/Source/WebCore/platform/mac/WebNSAttributedStringExtras.mm new file mode 100644 index 0000000..f64e24d --- /dev/null +++ b/Source/WebCore/platform/mac/WebNSAttributedStringExtras.mm @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2005, 2007, 2008, 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "WebNSAttributedStringExtras.h" + +namespace WebCore { + +NSAttributedString *attributedStringByStrippingAttachmentCharacters(NSAttributedString *attributedString) +{ + NSRange attachmentRange; + NSString *originalString = [attributedString string]; + static NSString *attachmentCharString = nil; + + if (!attachmentCharString) { + unichar chars[2]; + if (!attachmentCharString) { + chars[0] = NSAttachmentCharacter; + chars[1] = 0; + attachmentCharString = [[NSString alloc] initWithCharacters:chars length:1]; + } + } + + attachmentRange = [originalString rangeOfString:attachmentCharString]; + if (attachmentRange.location != NSNotFound && attachmentRange.length > 0) { + NSMutableAttributedString *newAttributedString = [[attributedString mutableCopyWithZone:NULL] autorelease]; + + while (attachmentRange.location != NSNotFound && attachmentRange.length > 0) { + [newAttributedString replaceCharactersInRange:attachmentRange withString:@""]; + attachmentRange = [[newAttributedString string] rangeOfString:attachmentCharString]; + } + return newAttributedString; + } + + return attributedString; +} + +} diff --git a/Source/WebCore/platform/mac/WheelEventMac.mm b/Source/WebCore/platform/mac/WheelEventMac.mm index 4e9a8b7..2494e69 100644 --- a/Source/WebCore/platform/mac/WheelEventMac.mm +++ b/Source/WebCore/platform/mac/WheelEventMac.mm @@ -35,8 +35,9 @@ namespace WebCore { static PlatformWheelEventPhase momentumPhaseForEvent(NSEvent *event) { + uint32_t phase = PlatformWheelEventPhaseNone; + #if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) - uint32_t phase = PlatformWheelEventPhaseNone; if ([event momentumPhase] & NSEventPhaseBegan) phase |= PlatformWheelEventPhaseBegan; if ([event momentumPhase] & NSEventPhaseStationary) @@ -47,11 +48,24 @@ static PlatformWheelEventPhase momentumPhaseForEvent(NSEvent *event) phase |= PlatformWheelEventPhaseEnded; if ([event momentumPhase] & NSEventPhaseCancelled) phase |= PlatformWheelEventPhaseCancelled; - return static_cast<PlatformWheelEventPhase>(phase); #else - UNUSED_PARAM(event); - return PlatformWheelEventPhaseNone; + switch (wkGetNSEventMomentumPhase(event)) { + case wkEventPhaseNone: + phase = PlatformWheelEventPhaseNone; + break; + case wkEventPhaseBegan: + phase = PlatformWheelEventPhaseBegan; + break; + case wkEventPhaseChanged: + phase = PlatformWheelEventPhaseChanged; + break; + case wkEventPhaseEnded: + phase = PlatformWheelEventPhaseEnded; + break; + } #endif + + return static_cast<PlatformWheelEventPhase>(phase); } static PlatformWheelEventPhase phaseForEvent(NSEvent *event) diff --git a/Source/WebCore/platform/network/BlobResourceHandle.cpp b/Source/WebCore/platform/network/BlobResourceHandle.cpp index 24c9088..d4cf452 100644 --- a/Source/WebCore/platform/network/BlobResourceHandle.cpp +++ b/Source/WebCore/platform/network/BlobResourceHandle.cpp @@ -79,7 +79,7 @@ public: BlobResourceSynchronousLoader(ResourceError&, ResourceResponse&, Vector<char>&); virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&); - virtual void didReceiveData(ResourceHandle*, const char*, int, int /*lengthReceived*/); + virtual void didReceiveData(ResourceHandle*, const char*, int, int /*encodedDataLength*/); virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/); virtual void didFail(ResourceHandle*, const ResourceError&); diff --git a/Source/WebCore/platform/network/MIMESniffing.cpp b/Source/WebCore/platform/network/MIMESniffing.cpp new file mode 100644 index 0000000..f9868c1 --- /dev/null +++ b/Source/WebCore/platform/network/MIMESniffing.cpp @@ -0,0 +1,495 @@ +/* + Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" +#include "MIMESniffing.h" + +#include <cstring> +#include <stdint.h> + +// MIME type sniffing implementation based on http://tools.ietf.org/html/draft-abarth-mime-sniff-06 + +namespace { + +static inline bool isTextInList(const char* text, size_t size, const char** data) +{ + for (size_t i = 0; i < size; ++i) { + if (!strcmp(text, data[i])) + return true; + } + return false; + +} + +// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-6 +const char* textTypes[] = { + "text/plain", + "text/plain; charset=ISO-8859-1", + "text/plain; charset=iso-8859-1", + "text/plain; charset=UTF-8" +}; +const size_t textTypesSize = sizeof(textTypes) / sizeof(textTypes[0]); + +static inline bool isTextOrBinaryType(const char* type) +{ + return isTextInList(type, textTypesSize, textTypes); +} + +// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-6 +const char* unknownTypes[] = { + "", + "unknown/unknown", + "application/unknown", + "*/*" +}; +const size_t unknownTypesSize = sizeof(unknownTypes) / sizeof(unknownTypes[0]); + +static inline bool isUnknownType(const char* type) +{ + return isTextInList(type, unknownTypesSize, unknownTypes); +} + +const char* xmlTypes[] = { + "text/xml", + "application/xml" +}; +const size_t xmlTypesSize = sizeof(xmlTypes) / sizeof(xmlTypes[0]); + +const char xmlSuffix[] = "+xml"; + +static inline bool isXMLType(const char* type) +{ + const size_t xmlSuffixSize = sizeof(xmlSuffix) - 1; + size_t typeSize = strlen(type); + if (typeSize >= xmlSuffixSize && !memcmp(type + typeSize - xmlSuffixSize, xmlSuffix, xmlSuffixSize)) + return true; + + return isTextInList(type, xmlTypesSize, xmlTypes); +} + +// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-8 +const char binaryFlags[256] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static inline bool isBinaryChar(unsigned char data) +{ + return binaryFlags[data]; +} + +static inline bool isBinaryData(const char* data, size_t size) +{ + for (size_t i = 0; i < size; ++i) { + if (isBinaryChar(data[i])) + return true; + } + return false; +} + +// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-11 +const char whiteSpaceChars[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static inline bool isWhiteSpace(unsigned char data) +{ + return whiteSpaceChars[data]; +} + +static inline void skipWhiteSpace(const char* data, size_t& pos, size_t dataSize) +{ + while (pos < dataSize && isWhiteSpace(data[pos])) + ++pos; +} + +enum { + SkipWhiteSpace = 1, + TrailingSpaceOrBracket = 2 +}; + +struct MagicNumbers { + const char* pattern; + const char* mask; + const char* mimeType; + size_t size; + int flags; +}; + +#define MAGIC_NUMBERS_MASKED(pattern, mask, mimeType, flags) {(pattern), (mask), (mimeType), sizeof(pattern) - 1, (flags)} +#define MAGIC_NUMBERS_SIMPLE(pattern, mimeType) {(pattern), 0, (mimeType), sizeof(pattern) - 1, 0} + +// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-12 +const MagicNumbers securityConstrainedTypes[] = { + MAGIC_NUMBERS_MASKED("<!DOCTYPE HTML", "\xFF\xFF\xDF\xDF\xDF\xDF\xDF\xDF\xDF\xFF\xDF\xDF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), + MAGIC_NUMBERS_MASKED("<HTML", "\xFF\xDF\xDF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), + MAGIC_NUMBERS_MASKED("<HEAD", "\xFF\xDF\xDF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), + MAGIC_NUMBERS_MASKED("<SCRIPT", "\xFF\xDF\xDF\xDF\xDF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), + MAGIC_NUMBERS_MASKED("<IFRAME", "\xFF\xDF\xDF\xDF\xDF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), + MAGIC_NUMBERS_MASKED("<H1", "\xFF\xDF\xFF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), + MAGIC_NUMBERS_MASKED("<DIV", "\xFF\xDF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), + MAGIC_NUMBERS_MASKED("<FONT", "\xFF\xDF\xDF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), + MAGIC_NUMBERS_MASKED("<TABLE", "\xFF\xDF\xDF\xDF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), + MAGIC_NUMBERS_MASKED("<A", "\xFF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), + MAGIC_NUMBERS_MASKED("<STYLE", "\xFF\xDF\xDF\xDF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), + MAGIC_NUMBERS_MASKED("<TITLE", "\xFF\xDF\xDF\xDF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), + MAGIC_NUMBERS_MASKED("<B", "\xFF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), + MAGIC_NUMBERS_MASKED("<BODY", "\xFF\xDF\xDF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), + MAGIC_NUMBERS_MASKED("<BR", "\xFF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), + MAGIC_NUMBERS_MASKED("<P", "\xFF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), + MAGIC_NUMBERS_MASKED("<!--", 0, "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), + MAGIC_NUMBERS_MASKED("<?xml", 0, "text/xml", SkipWhiteSpace), + MAGIC_NUMBERS_SIMPLE("%PDF-", "application/pdf") +}; +const size_t securityConstrainedTypesSize = sizeof(securityConstrainedTypes) / sizeof(securityConstrainedTypes[0]); + +// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-8 +const MagicNumbers bomTypes[] = { + MAGIC_NUMBERS_SIMPLE("\xFE\xFF", "text/plain"), // UTF-16BE BOM + MAGIC_NUMBERS_SIMPLE("\xFF\xFE", "text/plain"), // UTF-16LE BOM + MAGIC_NUMBERS_SIMPLE("\xEF\xBB\xBF", "text/plain") // UTF-8 BOM +}; +const size_t bomTypesSize = sizeof(bomTypes) / sizeof(bomTypes[0]); + +// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-13 +const MagicNumbers safeTypes[] = { + MAGIC_NUMBERS_SIMPLE("%!PS-Adobe-", "application/postscript"), + MAGIC_NUMBERS_SIMPLE("\x4F\x67\x67\x53\x00", "application/ogg"), // An Ogg Vorbis audio or video signature. + MAGIC_NUMBERS_MASKED("RIFF\x00\x00\x00\x00WAVE", "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF", "audio/x-wave", 0), // "RIFF" followed by four bytes, followed by "WAVE". + MAGIC_NUMBERS_SIMPLE("\x1A\x45\xDF\xA3", "video/webm"), // The WebM signature. + MAGIC_NUMBERS_SIMPLE("Rar!\x1A\x07\x00", "application/x-rar-compressed"), // A RAR archive. + MAGIC_NUMBERS_SIMPLE("\x50\x4B\x03\x04", "application/zip"), // A ZIP archive. + MAGIC_NUMBERS_SIMPLE("\x1F\x8B\x08", "application/x-gzip") // A GZIP archive. +}; +const size_t safeTypesSize = sizeof(safeTypes) / sizeof(safeTypes[0]); + +// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-16 +const MagicNumbers imageTypes[] = { + MAGIC_NUMBERS_MASKED("RIFF\x00\x00\x00\x00WEBPVP", "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF", "image/webp", 0), // "RIFF" followed by four bytes, followed by "WEBPVP". + MAGIC_NUMBERS_SIMPLE("GIF87a", "image/gif"), + MAGIC_NUMBERS_SIMPLE("GIF89a", "image/gif"), + MAGIC_NUMBERS_SIMPLE("\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", "image/png"), + MAGIC_NUMBERS_SIMPLE("\xFF\xD8\xFF", "image/jpeg"), + MAGIC_NUMBERS_SIMPLE("BM", "image/bmp"), + MAGIC_NUMBERS_SIMPLE("\x00\x00\x01\x00", "image/vnd.microsoft.icon") // A Windows Icon signature. +}; +const size_t imageTypesSize = sizeof(imageTypes) / sizeof(imageTypes[0]); + +static inline size_t dataSizeNeededForImageSniffing() +{ + size_t result = 0; + for (int i = 0; i < imageTypesSize; ++i) { + if (imageTypes[i].size > result) + result = imageTypes[i].size; + } + return result; +} + +static inline bool maskedCompare(const MagicNumbers& info, const char* data, size_t dataSize) +{ + if (dataSize < info.size) + return false; + + const uint32_t* pattern32 = reinterpret_cast<const uint32_t*>(info.pattern); + const uint32_t* mask32 = reinterpret_cast<const uint32_t*>(info.mask); + const uint32_t* data32 = reinterpret_cast<const uint32_t*>(data); + + size_t count = info.size >> 2; + + for (size_t i = 0; i < count; ++i) { + if ((*data32++ & *mask32++) != *pattern32++) + return false; + } + + const char* p = reinterpret_cast<const char*>(pattern32); + const char* m = reinterpret_cast<const char*>(mask32); + const char* d = reinterpret_cast<const char*>(data32); + + count = info.size & 3; + + for (size_t i = 0; i < count; ++i) { + if ((*d++ & *m++) != *p++) + return false; + } + + return true; +} + +// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-11 +static inline bool checkSpaceOrBracket(const char* data) +{ + return isWhiteSpace(*data) || *data == 0x3E; +} + +static inline bool compare(const MagicNumbers& info, const char* data, size_t dataSize) +{ + if (info.flags & SkipWhiteSpace) { + size_t pos = 0; + skipWhiteSpace(data, pos, dataSize); + data += pos; + dataSize -= pos; + } + + bool result; + if (info.mask) + result = maskedCompare(info, data, info.size); + else + result = dataSize >= info.size && !memcmp(data, info.pattern, info.size); + + return result && (!(info.flags & TrailingSpaceOrBracket) || checkSpaceOrBracket(data + info.size)); +} + +static inline const char* findMIMEType(const char* data, size_t dataSize, const MagicNumbers* types, size_t typesCount) +{ + for (size_t i = 0; i < typesCount; ++i) { + if (compare(types[i], data, dataSize)) + return types[i].mimeType; + } + return 0; +} + +static inline const char* findSimpleMIMEType(const char* data, size_t dataSize, const MagicNumbers* types, size_t typesCount) +{ + for (size_t i = 0; i < typesCount; ++i) { + ASSERT(!types[i].mask); + ASSERT(!types[i].flags); + + if (dataSize >= types[i].size && !memcmp(data, types[i].pattern, types[i].size)) + return types[i].mimeType; + } + return 0; +} + +bool isTypeInList(const char* type, const MagicNumbers* types, size_t typesCount) +{ + for (size_t i = 0; i < typesCount; ++i) { + if (!strcmp(type, types[i].mimeType)) + return true; + } + return false; +} + +// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-8 +static const char* internalTextOrBinaryTypeSniffingProcedure(const char* data, size_t dataSize) +{ + const char* mimeType = 0; + + mimeType = findSimpleMIMEType(data, dataSize, bomTypes, bomTypesSize); + if (mimeType) + return mimeType; + + if (!isBinaryData(data, dataSize)) + return "text/plain"; + + mimeType = findMIMEType(data, dataSize, safeTypes, safeTypesSize); + if (mimeType) + return mimeType; + + mimeType = findMIMEType(data, dataSize, imageTypes, imageTypesSize); + if (mimeType) + return mimeType; + + return "application/octet-stream"; +} + +static const char* textOrBinaryTypeSniffingProcedure(const char* data, size_t dataSize) +{ + const char* result = internalTextOrBinaryTypeSniffingProcedure(data, dataSize); + ASSERT(!isTypeInList(result, securityConstrainedTypes, securityConstrainedTypesSize)); + return result; +} + +// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-10 +static const char* unknownTypeSniffingProcedure(const char* data, size_t dataSize) +{ + const char* mimeType = 0; + + mimeType = findMIMEType(data, dataSize, securityConstrainedTypes, securityConstrainedTypesSize); + if (mimeType) + return mimeType; + + mimeType = findSimpleMIMEType(data, dataSize, bomTypes, bomTypesSize); + if (mimeType) + return mimeType; + + mimeType = findMIMEType(data, dataSize, safeTypes, safeTypesSize); + if (mimeType) + return mimeType; + + mimeType = findMIMEType(data, dataSize, imageTypes, imageTypesSize); + if (mimeType) + return mimeType; + + if (!isBinaryData(data, dataSize)) + return "text/plain"; + + return "application/octet-stream"; +} + +// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-16 +static const char* imageTypeSniffingProcedure(const char* data, size_t dataSize) +{ + return findMIMEType(data, dataSize, imageTypes, imageTypesSize); +} + +static inline bool checkText(const char* data, size_t& pos, size_t dataSize, const char* text, size_t textSize) +{ + if (dataSize - pos < textSize || memcmp(data + pos, text, textSize)) + return false; + + pos += textSize; + return true; +} + +const char rssUrl[] = "http://purl.org/rss/1.0"; +const char rdfUrl[] = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; + +static inline const char* checkRDF(const char* data, size_t pos, size_t dataSize) +{ + bool isRDF = false; + bool isRSS = false; + + while (pos <= dataSize) { + if (checkText(data, pos, dataSize, rssUrl, sizeof(rssUrl) - 1)) { + isRSS = true; + continue; + } + + if (checkText(data, pos, dataSize, rdfUrl, sizeof(rdfUrl) - 1)) { + isRDF = true; + continue; + } + + ++pos; + + if (isRSS && isRDF) + return "application/rdf+xml"; + } + + return 0; +} + +static inline bool skipTag(const char*& data, size_t& pos, size_t dataSize, const char* tag, size_t tagSize, const char* tagEnd, size_t tagEndSize) +{ + if (!checkText(data, pos, dataSize, tag, tagSize)) + return false; + + while (pos < dataSize && !checkText(data, pos, dataSize, tagEnd, tagEndSize)) + ++pos; + + return true; +} + +// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-17 +static const char* feedTypeSniffingProcedure(const char* data, size_t dataSize) +{ + size_t pos = 0; + + if (dataSize >= 3 && !memcmp(data, "\xEF\xBB\xBF", 3)) + pos += 3; + + while (pos < dataSize) { + skipWhiteSpace(data, pos, dataSize); + + if (!skipTag(data, pos, dataSize, "<!--", 4, "-->", 3) && !skipTag(data, pos, dataSize, "<!", 2, "!>", 2) && !skipTag(data, pos, dataSize, "<?", 2, "?>", 2)) + break; + } + + if (checkText(data, pos, dataSize, "<rss", 4)) + return "application/rss+xml"; + + if (checkText(data, pos, dataSize, "<feed", 5)) + return "application/atom+xml"; + + if (checkText(data, pos, dataSize, "<rdf:RDF", 8)) + return checkRDF(data, pos, dataSize); + + return 0; +} + +} + +// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-6 +MIMESniffer::MIMESniffer(const char* advertisedMIMEType, bool isSupportedImageType) + : m_dataSize(0) + , m_function(0) +{ + if (!advertisedMIMEType) { + m_dataSize = 512; + m_function = &unknownTypeSniffingProcedure; + return; + } + + if (isTextOrBinaryType(advertisedMIMEType)) { + m_dataSize = 512; + m_function = &textOrBinaryTypeSniffingProcedure; + return; + } + + if (isUnknownType(advertisedMIMEType)) { + m_dataSize = 512; + m_function = &unknownTypeSniffingProcedure; + return; + } + + if (isXMLType(advertisedMIMEType)) + return; + + if (isSupportedImageType) { + static const size_t dataSize = dataSizeNeededForImageSniffing(); + m_dataSize = dataSize; + m_function = &imageTypeSniffingProcedure; + return; + } + + if (!strcmp(advertisedMIMEType, "text/html")) { + m_dataSize = 512; + m_function = &feedTypeSniffingProcedure; + return; + } +} diff --git a/Source/WebCore/platform/network/MIMESniffing.h b/Source/WebCore/platform/network/MIMESniffing.h new file mode 100644 index 0000000..cd1c52b --- /dev/null +++ b/Source/WebCore/platform/network/MIMESniffing.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef MIMESniffing_h +#define MIMESniffing_h + +#include <stddef.h> + +// MIME type sniffing implementation based on http://tools.ietf.org/html/draft-abarth-mime-sniff-06 + +class MIMESniffer { +public: + MIMESniffer(const char* advertisedMIMEType, bool isSupportedImageType); + + size_t dataSize() const { return m_dataSize; } + const char* sniff(const char* data, size_t size) const { return m_function ? m_function(data, size) : 0; } + bool isValid() const { return m_dataSize > 0; } + +private: + typedef const char* (*SniffFunction)(const char*, size_t); + size_t m_dataSize; + SniffFunction m_function; +}; + +#endif // MIMESniffing_h diff --git a/Source/WebCore/platform/network/NetworkingContext.h b/Source/WebCore/platform/network/NetworkingContext.h index e8a3776..134394e 100644 --- a/Source/WebCore/platform/network/NetworkingContext.h +++ b/Source/WebCore/platform/network/NetworkingContext.h @@ -58,6 +58,7 @@ public: #if PLATFORM(QT) virtual QObject* originatingObject() const = 0; virtual QNetworkAccessManager* networkAccessManager() const = 0; + virtual bool mimeSniffingEnabled() const = 0; #endif #if PLATFORM(WIN) diff --git a/Source/WebCore/platform/network/ProtectionSpaceHash.h b/Source/WebCore/platform/network/ProtectionSpaceHash.h index 40eb9b6..edd95db 100644 --- a/Source/WebCore/platform/network/ProtectionSpaceHash.h +++ b/Source/WebCore/platform/network/ProtectionSpaceHash.h @@ -57,12 +57,7 @@ struct ProtectionSpaceHash { namespace WTF { - // WebCore::ProtectionSpaceHash is the default hash for ProtectionSpace - template<> struct HashTraits<WebCore::ProtectionSpace> : GenericHashTraits<WebCore::ProtectionSpace> { - static const bool emptyValueIsZero = true; - static void constructDeletedValue(WebCore::ProtectionSpace& slot) { new (&slot) WebCore::ProtectionSpace(HashTableDeletedValue); } - static bool isDeletedValue(const WebCore::ProtectionSpace& slot) { return slot.isHashTableDeletedValue(); } - }; + template<> struct HashTraits<WebCore::ProtectionSpace> : SimpleClassHashTraits<WebCore::ProtectionSpace> { }; template<typename T> struct DefaultHash; template<> struct DefaultHash<WebCore::ProtectionSpace> { diff --git a/Source/WebCore/platform/network/ResourceHandleClient.h b/Source/WebCore/platform/network/ResourceHandleClient.h index e92b376..8b064c5 100644 --- a/Source/WebCore/platform/network/ResourceHandleClient.h +++ b/Source/WebCore/platform/network/ResourceHandleClient.h @@ -71,7 +71,7 @@ namespace WebCore { virtual void didSendData(ResourceHandle*, unsigned long long /*bytesSent*/, unsigned long long /*totalBytesToBeSent*/) { } virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&) { } - virtual void didReceiveData(ResourceHandle*, const char*, int, int /*lengthReceived*/) { } + virtual void didReceiveData(ResourceHandle*, const char*, int, int /*encodedDataLength*/) { } virtual void didReceiveCachedMetadata(ResourceHandle*, const char*, int) { } virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/) { } virtual void didFail(ResourceHandle*, const ResourceError&) { } diff --git a/Source/WebCore/platform/network/ResourceHandleInternal.h b/Source/WebCore/platform/network/ResourceHandleInternal.h index b622801..bd24d22 100644 --- a/Source/WebCore/platform/network/ResourceHandleInternal.h +++ b/Source/WebCore/platform/network/ResourceHandleInternal.h @@ -116,7 +116,6 @@ namespace WebCore { , m_buffer(0) , m_bodySize(0) , m_bodyDataSent(0) - , m_idleHandler(0) , m_gotChunkHandler(0) #endif #if PLATFORM(QT) @@ -195,7 +194,6 @@ namespace WebCore { char* m_buffer; unsigned long m_bodySize; unsigned long m_bodyDataSent; - guint m_idleHandler; RefPtr<NetworkingContext> m_context; gulong m_gotChunkHandler; #endif diff --git a/Source/WebCore/platform/network/ResourceLoadInfo.h b/Source/WebCore/platform/network/ResourceLoadInfo.h index a1b958c..94c5f24 100644 --- a/Source/WebCore/platform/network/ResourceLoadInfo.h +++ b/Source/WebCore/platform/network/ResourceLoadInfo.h @@ -33,12 +33,16 @@ namespace WebCore { struct ResourceLoadInfo : RefCounted<ResourceLoadInfo> { ResourceLoadInfo() - : httpStatusCode(0) { } + : httpStatusCode(0) + , encodedDataLength(-1) { } int httpStatusCode; String httpStatusText; + long long encodedDataLength; HTTPHeaderMap requestHeaders; HTTPHeaderMap responseHeaders; + String requestHeadersText; + String responseHeadersText; }; } diff --git a/Source/WebCore/platform/network/ResourceLoadPriority.h b/Source/WebCore/platform/network/ResourceLoadPriority.h index 1c9d5d2..45238d7 100644 --- a/Source/WebCore/platform/network/ResourceLoadPriority.h +++ b/Source/WebCore/platform/network/ResourceLoadPriority.h @@ -28,15 +28,15 @@ namespace WebCore { -enum ResourceLoadPriority { - ResourceLoadPriorityVeryLow, - ResourceLoadPriorityLow, - ResourceLoadPriorityMedium, - ResourceLoadPriorityHigh, - ResourceLoadPriorityLowest = ResourceLoadPriorityVeryLow, - ResourceLoadPriorityHighest = ResourceLoadPriorityHigh, +enum ResourceLoadPriority { // The unresolved priority is here for the convenience of the clients. It should not be passed to the ResourceLoadScheduler. - ResourceLoadPriorityUnresolved, + ResourceLoadPriorityUnresolved = -1, + ResourceLoadPriorityVeryLow = 0, + ResourceLoadPriorityLow, + ResourceLoadPriorityMedium, + ResourceLoadPriorityHigh, + ResourceLoadPriorityLowest = ResourceLoadPriorityVeryLow, + ResourceLoadPriorityHighest = ResourceLoadPriorityHigh, }; } diff --git a/Source/WebCore/platform/network/ResourceRequestBase.h b/Source/WebCore/platform/network/ResourceRequestBase.h index 31a1e69..53e1160 100644 --- a/Source/WebCore/platform/network/ResourceRequestBase.h +++ b/Source/WebCore/platform/network/ResourceRequestBase.h @@ -65,6 +65,7 @@ namespace WebCore { TargetIsWorker, TargetIsSharedWorker, TargetIsPrefetch, + TargetIsFavicon, }; static PassOwnPtr<ResourceRequest> adopt(PassOwnPtr<CrossThreadResourceRequestData>); @@ -240,14 +241,6 @@ namespace WebCore { unsigned initializeMaximumHTTPConnectionCountPerHost(); -#if USE(CF) - bool isHTTPPipeliningEnabled(); - bool shouldForceHTTPPipeliningPriorityHigh(); -#else - inline bool isHTTPPipeliningEnabled() { return false; } - inline bool shouldForceHTTPPipeliningPriorityHigh() { return false; } -#endif - } // namespace WebCore #endif // ResourceRequestBase_h diff --git a/Source/WebCore/platform/network/ResourceResponseBase.cpp b/Source/WebCore/platform/network/ResourceResponseBase.cpp index 55eac76..5fcc328 100644 --- a/Source/WebCore/platform/network/ResourceResponseBase.cpp +++ b/Source/WebCore/platform/network/ResourceResponseBase.cpp @@ -108,7 +108,7 @@ PassOwnPtr<ResourceResponse> ResourceResponseBase::adopt(PassOwnPtr<CrossThreadR response->setHTTPStatusCode(data->m_httpStatusCode); response->setHTTPStatusText(data->m_httpStatusText); - response->lazyInit(); + response->lazyInit(AllFields); response->m_httpHeaderFields.adopt(data->m_httpHeaders.release()); response->setLastModifiedDate(data->m_lastModifiedDate); response->setResourceLoadTiming(data->m_resourceLoadTiming.release()); @@ -135,7 +135,7 @@ PassOwnPtr<CrossThreadResourceResponseData> ResourceResponseBase::copyData() con bool ResourceResponseBase::isHTTP() const { - lazyInit(); + lazyInit(CommonFieldsOnly); String protocol = m_url.protocol(); @@ -144,126 +144,140 @@ bool ResourceResponseBase::isHTTP() const const KURL& ResourceResponseBase::url() const { - lazyInit(); - + lazyInit(CommonFieldsOnly); + return m_url; } void ResourceResponseBase::setURL(const KURL& url) { - lazyInit(); + lazyInit(CommonFieldsOnly); m_isNull = false; - + m_url = url; } const String& ResourceResponseBase::mimeType() const { - lazyInit(); + lazyInit(CommonFieldsOnly); return m_mimeType; } void ResourceResponseBase::setMimeType(const String& mimeType) { - lazyInit(); + lazyInit(CommonFieldsOnly); m_isNull = false; - + m_mimeType = mimeType; } long long ResourceResponseBase::expectedContentLength() const { - lazyInit(); + lazyInit(CommonFieldsOnly); return m_expectedContentLength; } void ResourceResponseBase::setExpectedContentLength(long long expectedContentLength) { - lazyInit(); + lazyInit(CommonFieldsOnly); m_isNull = false; - + m_expectedContentLength = expectedContentLength; } const String& ResourceResponseBase::textEncodingName() const { - lazyInit(); + lazyInit(CommonFieldsOnly); return m_textEncodingName; } void ResourceResponseBase::setTextEncodingName(const String& encodingName) { - lazyInit(); + lazyInit(CommonFieldsOnly); m_isNull = false; - + m_textEncodingName = encodingName; } // FIXME should compute this on the fly const String& ResourceResponseBase::suggestedFilename() const { - lazyInit(); + lazyInit(CommonFieldsOnly); return m_suggestedFilename; } void ResourceResponseBase::setSuggestedFilename(const String& suggestedName) { - lazyInit(); + lazyInit(CommonFieldsOnly); m_isNull = false; - + m_suggestedFilename = suggestedName; } int ResourceResponseBase::httpStatusCode() const { - lazyInit(); + lazyInit(CommonFieldsOnly); return m_httpStatusCode; } void ResourceResponseBase::setHTTPStatusCode(int statusCode) { - lazyInit(); + lazyInit(CommonFieldsOnly); m_httpStatusCode = statusCode; } const String& ResourceResponseBase::httpStatusText() const { - lazyInit(); + lazyInit(AllFields); return m_httpStatusText; } void ResourceResponseBase::setHTTPStatusText(const String& statusText) { - lazyInit(); + lazyInit(AllFields); m_httpStatusText = statusText; } String ResourceResponseBase::httpHeaderField(const AtomicString& name) const { - lazyInit(); + lazyInit(CommonFieldsOnly); + + // If we already have the header, just return it instead of consuming memory by grabing all headers. + String value = m_httpHeaderFields.get(name); + if (!value.isEmpty()) + return value; + + lazyInit(AllFields); return m_httpHeaderFields.get(name); } String ResourceResponseBase::httpHeaderField(const char* name) const { - lazyInit(); + lazyInit(CommonFieldsOnly); + + // If we already have the header, just return it instead of consuming memory by grabing all headers. + String value = m_httpHeaderFields.get(name); + if (!value.isEmpty()) + return value; + + lazyInit(AllFields); return m_httpHeaderFields.get(name); } void ResourceResponseBase::setHTTPHeaderField(const AtomicString& name, const String& value) { - lazyInit(); - + lazyInit(AllFields); + DEFINE_STATIC_LOCAL(const AtomicString, ageHeader, ("age")); DEFINE_STATIC_LOCAL(const AtomicString, cacheControlHeader, ("cache-control")); DEFINE_STATIC_LOCAL(const AtomicString, dateHeader, ("date")); @@ -286,7 +300,7 @@ void ResourceResponseBase::setHTTPHeaderField(const AtomicString& name, const St const HTTPHeaderMap& ResourceResponseBase::httpHeaderFields() const { - lazyInit(); + lazyInit(AllFields); return m_httpHeaderFields; } @@ -295,7 +309,7 @@ void ResourceResponseBase::parseCacheControlDirectives() const { ASSERT(!m_haveParsedCacheControlHeader); - lazyInit(); + lazyInit(CommonFieldsOnly); m_haveParsedCacheControlHeader = true; @@ -332,13 +346,14 @@ void ResourceResponseBase::parseCacheControlDirectives() const } } } - + 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); } } @@ -364,6 +379,15 @@ bool ResourceResponseBase::cacheControlContainsMustRevalidate() const return m_cacheControlContainsMustRevalidate; } +bool ResourceResponseBase::hasCacheValidatorFields() const +{ + lazyInit(CommonFieldsOnly); + + DEFINE_STATIC_LOCAL(const AtomicString, lastModifiedHeader, ("last-modified")); + DEFINE_STATIC_LOCAL(const AtomicString, eTagHeader, ("etag")); + return !m_httpHeaderFields.get(lastModifiedHeader).isEmpty() || !m_httpHeaderFields.get(eTagHeader).isEmpty(); +} + double ResourceResponseBase::cacheControlMaxAge() const { if (!m_haveParsedCacheControlHeader) @@ -388,7 +412,7 @@ static double parseDateValueInHeader(const HTTPHeaderMap& headers, const AtomicS double ResourceResponseBase::date() const { - lazyInit(); + lazyInit(CommonFieldsOnly); if (!m_haveParsedDateHeader) { DEFINE_STATIC_LOCAL(const AtomicString, headerName, ("date")); @@ -400,8 +424,8 @@ double ResourceResponseBase::date() const double ResourceResponseBase::age() const { - lazyInit(); - + lazyInit(CommonFieldsOnly); + if (!m_haveParsedAgeHeader) { DEFINE_STATIC_LOCAL(const AtomicString, headerName, ("age")); String headerValue = m_httpHeaderFields.get(headerName); @@ -416,7 +440,7 @@ double ResourceResponseBase::age() const double ResourceResponseBase::expires() const { - lazyInit(); + lazyInit(CommonFieldsOnly); if (!m_haveParsedExpiresHeader) { DEFINE_STATIC_LOCAL(const AtomicString, headerName, ("expires")); @@ -428,8 +452,8 @@ double ResourceResponseBase::expires() const double ResourceResponseBase::lastModified() const { - lazyInit(); - + lazyInit(CommonFieldsOnly); + if (!m_haveParsedLastModifiedHeader) { DEFINE_STATIC_LOCAL(const AtomicString, headerName, ("last-modified")); m_lastModified = parseDateValueInHeader(m_httpHeaderFields, headerName); @@ -440,7 +464,7 @@ double ResourceResponseBase::lastModified() const bool ResourceResponseBase::isAttachment() const { - lazyInit(); + lazyInit(AllFields); DEFINE_STATIC_LOCAL(const AtomicString, headerName, ("content-disposition")); String value = m_httpHeaderFields.get(headerName); @@ -454,21 +478,21 @@ bool ResourceResponseBase::isAttachment() const void ResourceResponseBase::setLastModifiedDate(time_t lastModifiedDate) { - lazyInit(); + lazyInit(AllFields); m_lastModifiedDate = lastModifiedDate; } time_t ResourceResponseBase::lastModifiedDate() const { - lazyInit(); + lazyInit(AllFields); return m_lastModifiedDate; } bool ResourceResponseBase::wasCached() const { - lazyInit(); + lazyInit(AllFields); return m_wasCached; } @@ -480,65 +504,65 @@ void ResourceResponseBase::setWasCached(bool value) bool ResourceResponseBase::connectionReused() const { - lazyInit(); + lazyInit(AllFields); return m_connectionReused; } void ResourceResponseBase::setConnectionReused(bool connectionReused) { - lazyInit(); + lazyInit(AllFields); m_connectionReused = connectionReused; } unsigned ResourceResponseBase::connectionID() const { - lazyInit(); + lazyInit(AllFields); return m_connectionID; } void ResourceResponseBase::setConnectionID(unsigned connectionID) { - lazyInit(); + lazyInit(AllFields); m_connectionID = connectionID; } ResourceLoadTiming* ResourceResponseBase::resourceLoadTiming() const { - lazyInit(); + lazyInit(AllFields); return m_resourceLoadTiming.get(); } void ResourceResponseBase::setResourceLoadTiming(PassRefPtr<ResourceLoadTiming> resourceLoadTiming) { - lazyInit(); + lazyInit(AllFields); m_resourceLoadTiming = resourceLoadTiming; } PassRefPtr<ResourceLoadInfo> ResourceResponseBase::resourceLoadInfo() const { - lazyInit(); + lazyInit(AllFields); return m_resourceLoadInfo.get(); } void ResourceResponseBase::setResourceLoadInfo(PassRefPtr<ResourceLoadInfo> loadInfo) { - lazyInit(); + lazyInit(AllFields); m_resourceLoadInfo = loadInfo; } -void ResourceResponseBase::lazyInit() const +void ResourceResponseBase::lazyInit(InitLevel initLevel) const { - const_cast<ResourceResponse*>(static_cast<const ResourceResponse*>(this))->platformLazyInit(); + const_cast<ResourceResponse*>(static_cast<const ResourceResponse*>(this))->platformLazyInit(initLevel); } - + bool ResourceResponseBase::compare(const ResourceResponse& a, const ResourceResponse& b) { if (a.isNull() != b.isNull()) diff --git a/Source/WebCore/platform/network/ResourceResponseBase.h b/Source/WebCore/platform/network/ResourceResponseBase.h index e0774c2..250411c 100644 --- a/Source/WebCore/platform/network/ResourceResponseBase.h +++ b/Source/WebCore/platform/network/ResourceResponseBase.h @@ -35,6 +35,10 @@ #include <wtf/PassOwnPtr.h> #include <wtf/RefPtr.h> +#if OS(SOLARIS) +#include <sys/time.h> // For time_t structure. +#endif + namespace WebCore { class ResourceResponse; @@ -93,6 +97,7 @@ public: bool cacheControlContainsNoCache() const; bool cacheControlContainsNoStore() const; bool cacheControlContainsMustRevalidate() const; + bool hasCacheValidatorFields() const; double cacheControlMaxAge() const; double date() const; double age() const; @@ -124,13 +129,19 @@ public: static bool compare(const ResourceResponse&, const ResourceResponse&); protected: + enum InitLevel { + Uninitialized, + CommonFieldsOnly, + AllFields + }; + ResourceResponseBase(); ResourceResponseBase(const KURL& url, const String& mimeType, long long expectedLength, const String& textEncodingName, const String& filename); - void lazyInit() const; + void lazyInit(InitLevel) const; // The ResourceResponse subclass may "shadow" this method to lazily initialize platform specific fields - void platformLazyInit() { } + void platformLazyInit(InitLevel) { } // The ResourceResponse subclass may "shadow" this method to compare platform specific fields static bool platformCompare(const ResourceResponse&, const ResourceResponse&) { return true; } diff --git a/Source/WebCore/platform/network/android/ResourceHandleAndroid.cpp b/Source/WebCore/platform/network/android/ResourceHandleAndroid.cpp index 8837cf8..13a26f0 100644 --- a/Source/WebCore/platform/network/android/ResourceHandleAndroid.cpp +++ b/Source/WebCore/platform/network/android/ResourceHandleAndroid.cpp @@ -131,7 +131,7 @@ public: *m_response = response; } - virtual void didReceiveData(ResourceHandle*, const char* data, int len, int lengthReceived) + virtual void didReceiveData(ResourceHandle*, const char* data, int len, int encodedDataLength) { m_data->append(data, len); } diff --git a/Source/WebCore/platform/network/cf/ResourceHandleCFNet.cpp b/Source/WebCore/platform/network/cf/ResourceHandleCFNet.cpp index f840b04..83cd793 100644 --- a/Source/WebCore/platform/network/cf/ResourceHandleCFNet.cpp +++ b/Source/WebCore/platform/network/cf/ResourceHandleCFNet.cpp @@ -93,7 +93,7 @@ private: virtual bool shouldUseCredentialStorage(ResourceHandle*); virtual void didReceiveAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge&); virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&); - virtual void didReceiveData(ResourceHandle*, const char*, int, int /*lengthReceived*/); + virtual void didReceiveData(ResourceHandle*, const char*, int, int /*encodedDataLength*/); virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/); virtual void didFail(ResourceHandle*, const ResourceError&); @@ -757,7 +757,7 @@ void WebCoreSynchronousLoaderClient::didReceiveResponse(ResourceHandle*, const R m_response = response; } -void WebCoreSynchronousLoaderClient::didReceiveData(ResourceHandle*, const char* data, int length, int /*lengthReceived*/) +void WebCoreSynchronousLoaderClient::didReceiveData(ResourceHandle*, const char* data, int length, int /*encodedDataLength*/) { if (!m_data) m_data.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, 0)); diff --git a/Source/WebCore/platform/network/cf/ResourceRequest.h b/Source/WebCore/platform/network/cf/ResourceRequest.h index 2da5026..5a14342 100644 --- a/Source/WebCore/platform/network/cf/ResourceRequest.h +++ b/Source/WebCore/platform/network/cf/ResourceRequest.h @@ -88,6 +88,9 @@ namespace WebCore { void setStorageSession(CFURLStorageSessionRef); #endif + static bool httpPipeliningEnabled(); + static void setHTTPPipeliningEnabled(bool); + private: friend class ResourceRequestBase; @@ -102,6 +105,8 @@ namespace WebCore { #else RetainPtr<NSURLRequest> m_nsRequest; #endif + + static bool s_httpPipeliningEnabled; }; struct CrossThreadResourceRequestData : public CrossThreadResourceRequestDataBase { diff --git a/Source/WebCore/platform/network/cf/ResourceRequestCFNet.cpp b/Source/WebCore/platform/network/cf/ResourceRequestCFNet.cpp index fdccc11..d0ef1f9 100644 --- a/Source/WebCore/platform/network/cf/ResourceRequestCFNet.cpp +++ b/Source/WebCore/platform/network/cf/ResourceRequestCFNet.cpp @@ -29,6 +29,7 @@ #include "ResourceRequest.h" #if PLATFORM(MAC) +#include "ResourceLoadPriority.h" #include "WebCoreSystemInterface.h" #endif @@ -40,6 +41,8 @@ namespace WebCore { +bool ResourceRequest::s_httpPipeliningEnabled = false; + #if USE(CFNETWORK) typedef void (*CFURLRequestSetContentDispositionEncodingFallbackArrayFunction)(CFMutableURLRequestRef, CFArrayRef); @@ -208,6 +211,16 @@ void ResourceRequest::setStorageSession(CFURLStorageSessionRef storageSession) #endif // USE(CFNETWORK) +bool ResourceRequest::httpPipeliningEnabled() +{ + return s_httpPipeliningEnabled; +} + +void ResourceRequest::setHTTPPipeliningEnabled(bool flag) +{ + s_httpPipeliningEnabled = flag; +} + unsigned initializeMaximumHTTPConnectionCountPerHost() { static const unsigned preferredConnectionCount = 6; @@ -217,7 +230,9 @@ unsigned initializeMaximumHTTPConnectionCountPerHost() unsigned maximumHTTPConnectionCountPerHost = wkInitializeMaximumHTTPConnectionCountPerHost(preferredConnectionCount); #if PLATFORM(MAC) - if (isHTTPPipeliningEnabled()) { + if (ResourceRequest::httpPipeliningEnabled()) { + wkSetHTTPPipeliningMaximumPriority(ResourceLoadPriorityHighest); + wkSetHTTPPipeliningMinimumFastLanePriority(ResourceLoadPriorityMedium); // When pipelining do not rate-limit requests sent from WebCore since CFNetwork handles that. return unlimitedConnectionCount; } @@ -226,23 +241,4 @@ unsigned initializeMaximumHTTPConnectionCountPerHost() return maximumHTTPConnectionCountPerHost; } -static inline bool readBooleanPreference(CFStringRef key) -{ - Boolean keyExistsAndHasValidFormat; - Boolean result = CFPreferencesGetAppBooleanValue(key, kCFPreferencesCurrentApplication, &keyExistsAndHasValidFormat); - return keyExistsAndHasValidFormat ? result : false; -} - -bool isHTTPPipeliningEnabled() -{ - static bool isEnabled = readBooleanPreference(CFSTR("WebKitEnableHTTPPipelining")); - return isEnabled; -} - -bool shouldForceHTTPPipeliningPriorityHigh() -{ - static bool shouldForcePriorityHigh = readBooleanPreference(CFSTR("WebKitForceHTTPPipeliningPriorityHigh")); - return shouldForcePriorityHigh; -} - } // namespace WebCore diff --git a/Source/WebCore/platform/network/cf/ResourceRequestCFNet.h b/Source/WebCore/platform/network/cf/ResourceRequestCFNet.h index 271dcd2..987508f 100644 --- a/Source/WebCore/platform/network/cf/ResourceRequestCFNet.h +++ b/Source/WebCore/platform/network/cf/ResourceRequestCFNet.h @@ -41,34 +41,37 @@ void getResourceRequest(ResourceRequest&, CFURLRequestRef); CFURLRequestRef cfURLRequest(const ResourceRequest&); #endif -inline ResourceLoadPriority mapHTTPPipeliningPriorityToResourceLoadPriority(int priority) +inline ResourceLoadPriority toResourceLoadPriority(int priority) { switch (priority) { + case -1: + return ResourceLoadPriorityUnresolved; case 0: - return ResourceLoadPriorityLow; + return ResourceLoadPriorityVeryLow; case 1: - return ResourceLoadPriorityMedium; + return ResourceLoadPriorityLow; case 2: - return ResourceLoadPriorityHigh; + return ResourceLoadPriorityMedium; case 3: - return ResourceLoadPriorityUnresolved; + return ResourceLoadPriorityHigh; default: ASSERT_NOT_REACHED(); return ResourceLoadPriorityLowest; } } -inline int mapResourceLoadPriorityToHTTPPipeliningPriority(ResourceLoadPriority priority) +inline int toHTTPPipeliningPriority(ResourceLoadPriority priority) { switch (priority) { + case ResourceLoadPriorityUnresolved: + return -1; case ResourceLoadPriorityVeryLow: - case ResourceLoadPriorityLow: return 0; - case ResourceLoadPriorityMedium: + case ResourceLoadPriorityLow: return 1; - case ResourceLoadPriorityHigh: + case ResourceLoadPriorityMedium: return 2; - case ResourceLoadPriorityUnresolved: + case ResourceLoadPriorityHigh: return 3; } diff --git a/Source/WebCore/platform/network/cf/ResourceResponse.h b/Source/WebCore/platform/network/cf/ResourceResponse.h index 0551ede..675d431 100644 --- a/Source/WebCore/platform/network/cf/ResourceResponse.h +++ b/Source/WebCore/platform/network/cf/ResourceResponse.h @@ -44,21 +44,21 @@ namespace WebCore { class ResourceResponse : public ResourceResponseBase { public: ResourceResponse() - : m_isUpToDate(true) + : m_initLevel(AllFields) { } #if USE(CFNETWORK) ResourceResponse(CFURLResponseRef cfResponse) : m_cfResponse(cfResponse) - , m_isUpToDate(false) + , m_initLevel(Uninitialized) { m_isNull = !cfResponse; } #else ResourceResponse(NSURLResponse* nsResponse) : m_nsResponse(nsResponse) - , m_isUpToDate(false) + , m_initLevel(Uninitialized) { m_isNull = !nsResponse; } @@ -66,15 +66,15 @@ public: ResourceResponse(const KURL& url, const String& mimeType, long long expectedLength, const String& textEncodingName, const String& filename) : ResourceResponseBase(url, mimeType, expectedLength, textEncodingName, filename) - , m_isUpToDate(true) + , m_initLevel(AllFields) { } unsigned memoryUsage() const { // FIXME: Find some programmatic lighweight way to calculate ResourceResponse and associated classes. - // This is a rough estimate of resource overhead based on stats collected from the stress test. - return 3072; + // This is a rough estimate of resource overhead based on stats collected from memory usage tests. + return 3800; /* 1280 * 2 + // average size of ResourceResponse. Doubled to account for the WebCore copy and the CF copy. // Mostly due to the size of the hash maps, the Header Map strings and the URL. 256 * 2 // Overhead from ResourceRequest, doubled to account for WebCore copy and CF copy. @@ -91,7 +91,7 @@ public: private: friend class ResourceResponseBase; - void platformLazyInit(); + void platformLazyInit(InitLevel); PassOwnPtr<CrossThreadResourceResponseData> doPlatformCopyData(PassOwnPtr<CrossThreadResourceResponseData> data) const { return data; } void doPlatformAdopt(PassOwnPtr<CrossThreadResourceResponseData>) { } @@ -102,7 +102,7 @@ private: #else mutable RetainPtr<NSURLResponse> m_nsResponse; #endif - bool m_isUpToDate; + InitLevel m_initLevel; }; struct CrossThreadResourceResponseData : public CrossThreadResourceResponseDataBase { diff --git a/Source/WebCore/platform/network/cf/ResourceResponseCFNet.cpp b/Source/WebCore/platform/network/cf/ResourceResponseCFNet.cpp index d4a0b31..06cc706 100644 --- a/Source/WebCore/platform/network/cf/ResourceResponseCFNet.cpp +++ b/Source/WebCore/platform/network/cf/ResourceResponseCFNet.cpp @@ -42,6 +42,11 @@ using namespace std; namespace WebCore { +static CFStringRef const commonHeaderFields[] = { + CFSTR("Age"), CFSTR("Cache-Control"), CFSTR("Date"), CFSTR("Etag"), CFSTR("Expires"), CFSTR("Last-Modified"), CFSTR("Pragma") +}; +static const int numCommonHeaderFields = sizeof(commonHeaderFields) / sizeof(CFStringRef); + CFURLResponseRef ResourceResponse::cfURLResponse() const { if (!m_cfResponse && !m_isNull) { @@ -70,52 +75,66 @@ static time_t toTimeT(CFAbsoluteTime time) return min(max(minTimeAsDouble, time + kCFAbsoluteTimeIntervalSince1970), maxTimeAsDouble); } -void ResourceResponse::platformLazyInit() +void ResourceResponse::platformLazyInit(InitLevel initLevel) { - if (m_isUpToDate) + if (m_initLevel > initLevel) return; - m_isUpToDate = true; if (m_isNull) { ASSERT(!m_cfResponse.get()); return; } - // FIXME: We may need to do MIME type sniffing here (unless that is done in CFURLResponseGetMIMEType). - - m_url = CFURLResponseGetURL(m_cfResponse.get()); - m_mimeType = CFURLResponseGetMIMEType(m_cfResponse.get()); - m_expectedContentLength = CFURLResponseGetExpectedContentLength(m_cfResponse.get()); - m_textEncodingName = CFURLResponseGetTextEncodingName(m_cfResponse.get()); - - // Workaround for <rdar://problem/8757088>, can be removed once that is fixed. - unsigned textEncodingNameLength = m_textEncodingName.length(); - if (textEncodingNameLength >= 2 && m_textEncodingName[0U] == '"' && m_textEncodingName[textEncodingNameLength - 1] == '"') - m_textEncodingName = m_textEncodingName.substring(1, textEncodingNameLength - 2); - - m_lastModifiedDate = toTimeT(CFURLResponseGetLastModifiedDate(m_cfResponse.get())); - - RetainPtr<CFStringRef> suggestedFilename(AdoptCF, CFURLResponseCopySuggestedFilename(m_cfResponse.get())); - m_suggestedFilename = suggestedFilename.get(); - - CFHTTPMessageRef httpResponse = CFURLResponseGetHTTPResponse(m_cfResponse.get()); - if (httpResponse) { - m_httpStatusCode = CFHTTPMessageGetResponseStatusCode(httpResponse); + if (m_initLevel < CommonFieldsOnly && initLevel >= CommonFieldsOnly) { + m_url = CFURLResponseGetURL(m_cfResponse.get()); + m_mimeType = CFURLResponseGetMIMEType(m_cfResponse.get()); + m_expectedContentLength = CFURLResponseGetExpectedContentLength(m_cfResponse.get()); + m_textEncodingName = CFURLResponseGetTextEncodingName(m_cfResponse.get()); + + // Workaround for <rdar://problem/8757088>, can be removed once that is fixed. + unsigned textEncodingNameLength = m_textEncodingName.length(); + if (textEncodingNameLength >= 2 && m_textEncodingName[0U] == '"' && m_textEncodingName[textEncodingNameLength - 1] == '"') + m_textEncodingName = m_textEncodingName.substring(1, textEncodingNameLength - 2); + + m_lastModifiedDate = toTimeT(CFURLResponseGetLastModifiedDate(m_cfResponse.get())); + + RetainPtr<CFStringRef> suggestedFilename(AdoptCF, CFURLResponseCopySuggestedFilename(m_cfResponse.get())); + m_suggestedFilename = suggestedFilename.get(); + + CFHTTPMessageRef httpResponse = CFURLResponseGetHTTPResponse(m_cfResponse.get()); + if (httpResponse) { + m_httpStatusCode = CFHTTPMessageGetResponseStatusCode(httpResponse); + + RetainPtr<CFDictionaryRef> headers(AdoptCF, CFHTTPMessageCopyAllHeaderFields(httpResponse)); + + for (int i = 0; i < numCommonHeaderFields; i++) { + CFStringRef value; + if (CFDictionaryGetValueIfPresent(headers.get(), commonHeaderFields[i], (const void **)&value)) + m_httpHeaderFields.set(commonHeaderFields[i], value); + } + } else + m_httpStatusCode = 0; + } - RetainPtr<CFStringRef> statusLine(AdoptCF, CFHTTPMessageCopyResponseStatusLine(httpResponse)); - m_httpStatusText = extractReasonPhraseFromHTTPStatusLine(statusLine.get()); + if (m_initLevel < AllFields && initLevel >= AllFields) { + CFHTTPMessageRef httpResponse = CFURLResponseGetHTTPResponse(m_cfResponse.get()); + if (httpResponse) { + RetainPtr<CFStringRef> statusLine(AdoptCF, CFHTTPMessageCopyResponseStatusLine(httpResponse)); + m_httpStatusText = extractReasonPhraseFromHTTPStatusLine(statusLine.get()); + + RetainPtr<CFDictionaryRef> headers(AdoptCF, CFHTTPMessageCopyAllHeaderFields(httpResponse)); + CFIndex headerCount = CFDictionaryGetCount(headers.get()); + Vector<const void*, 128> keys(headerCount); + Vector<const void*, 128> values(headerCount); + CFDictionaryGetKeysAndValues(headers.get(), keys.data(), values.data()); + for (int i = 0; i < headerCount; ++i) + m_httpHeaderFields.set((CFStringRef)keys[i], (CFStringRef)values[i]); + } + } - RetainPtr<CFDictionaryRef> headers(AdoptCF, CFHTTPMessageCopyAllHeaderFields(httpResponse)); - CFIndex headerCount = CFDictionaryGetCount(headers.get()); - Vector<const void*, 128> keys(headerCount); - Vector<const void*, 128> values(headerCount); - CFDictionaryGetKeysAndValues(headers.get(), keys.data(), values.data()); - for (int i = 0; i < headerCount; ++i) - m_httpHeaderFields.set((CFStringRef)keys[i], (CFStringRef)values[i]); - } else - m_httpStatusCode = 0; + m_initLevel = initLevel; } - + bool ResourceResponse::platformCompare(const ResourceResponse& a, const ResourceResponse& b) { return CFEqual(a.cfURLResponse(), b.cfURLResponse()); diff --git a/Source/WebCore/platform/network/curl/ResourceHandleCurl.cpp b/Source/WebCore/platform/network/curl/ResourceHandleCurl.cpp index 1d276aa..d982186 100644 --- a/Source/WebCore/platform/network/curl/ResourceHandleCurl.cpp +++ b/Source/WebCore/platform/network/curl/ResourceHandleCurl.cpp @@ -46,7 +46,7 @@ public: WebCoreSynchronousLoader(); virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&); - virtual void didReceiveData(ResourceHandle*, const char*, int, int lengthReceived); + virtual void didReceiveData(ResourceHandle*, const char*, int, int encodedDataLength); virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/); virtual void didFail(ResourceHandle*, const ResourceError&); diff --git a/Source/WebCore/platform/network/mac/ResourceHandleMac.mm b/Source/WebCore/platform/network/mac/ResourceHandleMac.mm index b2a89f0..c0a49d7 100644 --- a/Source/WebCore/platform/network/mac/ResourceHandleMac.mm +++ b/Source/WebCore/platform/network/mac/ResourceHandleMac.mm @@ -117,7 +117,7 @@ private: virtual bool shouldUseCredentialStorage(ResourceHandle*); virtual void didReceiveAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge&); virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&); - virtual void didReceiveData(ResourceHandle*, const char*, int, int /*lengthReceived*/); + virtual void didReceiveData(ResourceHandle*, const char*, int, int /*encodedDataLength*/); virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/); virtual void didFail(ResourceHandle*, const ResourceError&); #if USE(PROTECTION_SPACE_AUTH_CALLBACK) @@ -1127,7 +1127,7 @@ void WebCoreSynchronousLoaderClient::didReceiveResponse(ResourceHandle*, const R m_response = [response.nsURLResponse() copy]; } -void WebCoreSynchronousLoaderClient::didReceiveData(ResourceHandle*, const char* data, int length, int /*lengthReceived*/) +void WebCoreSynchronousLoaderClient::didReceiveData(ResourceHandle*, const char* data, int length, int /*encodedDataLength*/) { if (!m_data) m_data = [[NSMutableData alloc] init]; diff --git a/Source/WebCore/platform/network/mac/ResourceRequestMac.mm b/Source/WebCore/platform/network/mac/ResourceRequestMac.mm index 8446782..d99e1b7 100644 --- a/Source/WebCore/platform/network/mac/ResourceRequestMac.mm +++ b/Source/WebCore/platform/network/mac/ResourceRequestMac.mm @@ -70,8 +70,8 @@ void ResourceRequest::doUpdateResourceRequest() m_allowCookies = [m_nsRequest.get() HTTPShouldHandleCookies]; #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) - if (isHTTPPipeliningEnabled() && !shouldForceHTTPPipeliningPriorityHigh()) - m_priority = mapHTTPPipeliningPriorityToResourceLoadPriority(wkGetHTTPPipeliningPriority(m_nsRequest.get())); + if (ResourceRequest::httpPipeliningEnabled()) + m_priority = toResourceLoadPriority(wkGetHTTPPipeliningPriority(m_nsRequest.get())); #endif NSDictionary *headers = [m_nsRequest.get() allHTTPHeaderFields]; @@ -120,10 +120,8 @@ void ResourceRequest::doUpdatePlatformRequest() #endif #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) - if (isHTTPPipeliningEnabled()) { - int priority = mapResourceLoadPriorityToHTTPPipeliningPriority(m_priority); - wkSetHTTPPipeliningPriority(nsRequest, shouldForceHTTPPipeliningPriorityHigh() ? 2 : priority); - } + if (ResourceRequest::httpPipeliningEnabled()) + wkSetHTTPPipeliningPriority(nsRequest, toHTTPPipeliningPriority(m_priority)); #endif [nsRequest setCachePolicy:(NSURLRequestCachePolicy)cachePolicy()]; diff --git a/Source/WebCore/platform/network/mac/ResourceResponseMac.mm b/Source/WebCore/platform/network/mac/ResourceResponseMac.mm index 58c3641..704592a 100644 --- a/Source/WebCore/platform/network/mac/ResourceResponseMac.mm +++ b/Source/WebCore/platform/network/mac/ResourceResponseMac.mm @@ -34,6 +34,7 @@ #import <Foundation/Foundation.h> #import <wtf/StdLibExtras.h> #import <limits> +#include <wtf/text/CString.h> @interface NSURLResponse (FoundationSecretsWebCoreKnowsAbout) - (NSTimeInterval)_calculatedExpiration; @@ -45,6 +46,11 @@ typedef int NSInteger; namespace WebCore { +static NSString* const commonHeaderFields[] = { + @"Age", @"Cache-Control", @"Date", @"Etag", @"Expires", @"Last-Modified", @"Pragma" +}; +static const int numCommonHeaderFields = sizeof(commonHeaderFields) / sizeof(AtomicString*); + NSURLResponse *ResourceResponse::nsURLResponse() const { if (!m_nsResponse && !m_isNull) { @@ -61,48 +67,72 @@ NSURLResponse *ResourceResponse::nsURLResponse() const return m_nsResponse.get(); } -void ResourceResponse::platformLazyInit() +void ResourceResponse::platformLazyInit(InitLevel initLevel) { - if (m_isUpToDate) + if (m_initLevel >= initLevel) return; - m_isUpToDate = true; if (m_isNull) { ASSERT(!m_nsResponse); return; } - - m_url = [m_nsResponse.get() URL]; - m_mimeType = [m_nsResponse.get() MIMEType]; - m_expectedContentLength = [m_nsResponse.get() expectedContentLength]; - m_textEncodingName = [m_nsResponse.get() textEncodingName]; - // Workaround for <rdar://problem/8757088>, can be removed once that is fixed. - unsigned textEncodingNameLength = m_textEncodingName.length(); - if (textEncodingNameLength >= 2 && m_textEncodingName[0U] == '"' && m_textEncodingName[textEncodingNameLength - 1] == '"') - m_textEncodingName = m_textEncodingName.substring(1, textEncodingNameLength - 2); + if (m_initLevel < CommonFieldsOnly && initLevel >= CommonFieldsOnly) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - m_suggestedFilename = [m_nsResponse.get() suggestedFilename]; - - if ([m_nsResponse.get() isKindOfClass:[NSHTTPURLResponse class]]) { - NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)m_nsResponse.get(); + m_httpHeaderFields.clear(); + m_url = [m_nsResponse.get() URL]; + m_mimeType = [m_nsResponse.get() MIMEType]; + m_expectedContentLength = [m_nsResponse.get() expectedContentLength]; + m_textEncodingName = [m_nsResponse.get() textEncodingName]; + + // Workaround for <rdar://problem/8757088>, can be removed once that is fixed. + unsigned textEncodingNameLength = m_textEncodingName.length(); + if (textEncodingNameLength >= 2 && m_textEncodingName[0U] == '"' && m_textEncodingName[textEncodingNameLength - 1] == '"') + m_textEncodingName = m_textEncodingName.substring(1, textEncodingNameLength - 2); + + m_suggestedFilename = [m_nsResponse.get() suggestedFilename]; + + if ([m_nsResponse.get() isKindOfClass:[NSHTTPURLResponse class]]) { + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)m_nsResponse.get(); + + m_httpStatusCode = [httpResponse statusCode]; + + NSDictionary *headers = [httpResponse allHeaderFields]; + + for (int i = 0; i < numCommonHeaderFields; i++) { + if (NSString* headerValue = [headers objectForKey:commonHeaderFields[i]]) + m_httpHeaderFields.set([commonHeaderFields[i] UTF8String], headerValue); + } + } else + m_httpStatusCode = 0; - m_httpStatusCode = [httpResponse statusCode]; + [pool drain]; + } + + if (m_initLevel < AllFields && initLevel >= AllFields && [m_nsResponse.get() isKindOfClass:[NSHTTPURLResponse class]]) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)m_nsResponse.get(); RetainPtr<NSString> httpStatusLine(AdoptNS, wkCopyNSURLResponseStatusLine(m_nsResponse.get())); if (httpStatusLine) m_httpStatusText = extractReasonPhraseFromHTTPStatusLine(httpStatusLine.get()); else m_httpStatusText = "OK"; - + NSDictionary *headers = [httpResponse allHeaderFields]; NSEnumerator *e = [headers keyEnumerator]; while (NSString *name = [e nextObject]) m_httpHeaderFields.set(name, [headers objectForKey:name]); - } else - m_httpStatusCode = 0; + + [pool drain]; + } + + m_initLevel = initLevel; } + bool ResourceResponse::platformCompare(const ResourceResponse& a, const ResourceResponse& b) { return a.nsURLResponse() == b.nsURLResponse(); diff --git a/Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp b/Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp index 6e63145..b27c8f4 100644 --- a/Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp +++ b/Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp @@ -149,13 +149,72 @@ bool FormDataIODevice::isSequential() const return true; } -QNetworkReplyWrapper::QNetworkReplyWrapper(QNetworkReply* reply, QObject* parent) +QNetworkReplyHandlerCallQueue::QNetworkReplyHandlerCallQueue(QNetworkReplyHandler* handler, bool deferSignals) + : m_replyHandler(handler) + , m_locks(0) + , m_deferSignals(deferSignals) + , m_flushing(false) +{ + Q_ASSERT(handler); +} + +void QNetworkReplyHandlerCallQueue::push(EnqueuedCall method) +{ + m_enqueuedCalls.append(method); + flush(); +} + +void QNetworkReplyHandlerCallQueue::lock() +{ + ++m_locks; +} + +void QNetworkReplyHandlerCallQueue::unlock() +{ + if (!m_locks) + return; + + --m_locks; + flush(); +} + +void QNetworkReplyHandlerCallQueue::setDeferSignals(bool defer) +{ + m_deferSignals = defer; + flush(); +} + +void QNetworkReplyHandlerCallQueue::flush() +{ + if (m_flushing) + return; + + m_flushing = true; + + while (!m_deferSignals && !m_locks && !m_enqueuedCalls.isEmpty()) + (m_replyHandler->*(m_enqueuedCalls.takeFirst()))(); + + m_flushing = false; +} + +class QueueLocker { +public: + QueueLocker(QNetworkReplyHandlerCallQueue* queue) : m_queue(queue) { m_queue->lock(); } + ~QueueLocker() { m_queue->unlock(); } +private: + QNetworkReplyHandlerCallQueue* m_queue; +}; + +QNetworkReplyWrapper::QNetworkReplyWrapper(QNetworkReplyHandlerCallQueue* queue, QNetworkReply* reply, bool sniffMIMETypes, QObject* parent) : QObject(parent) , m_reply(reply) + , m_queue(queue) + , m_responseContainsData(false) + , m_sniffer(0) + , m_sniffMIMETypes(sniffMIMETypes) { Q_ASSERT(m_reply); - connect(m_reply, SIGNAL(metaDataChanged()), this, SLOT(receiveMetaData())); connect(m_reply, SIGNAL(readyRead()), this, SLOT(receiveMetaData())); connect(m_reply, SIGNAL(finished()), this, SLOT(receiveMetaData())); } @@ -164,6 +223,7 @@ QNetworkReplyWrapper::~QNetworkReplyWrapper() { if (m_reply) m_reply->deleteLater(); + m_queue->clear(); } QNetworkReply* QNetworkReplyWrapper::release() @@ -174,6 +234,8 @@ QNetworkReply* QNetworkReplyWrapper::release() resetConnections(); QNetworkReply* reply = m_reply; m_reply = 0; + m_sniffer = 0; + reply->setParent(0); return reply; } @@ -190,43 +252,80 @@ void QNetworkReplyWrapper::receiveMetaData() // This slot is only used to receive the first signal from the QNetworkReply object. resetConnections(); + + WTF::String contentType = m_reply->header(QNetworkRequest::ContentTypeHeader).toString(); + m_encoding = extractCharsetFromMediaType(contentType); + m_advertisedMIMEType = extractMIMETypeFromMediaType(contentType); + m_redirectionTargetUrl = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); if (m_redirectionTargetUrl.isValid()) { - emit metaDataChanged(); - emit finished(); + QueueLocker lock(m_queue); + m_queue->push(&QNetworkReplyHandler::sendResponseIfNeeded); + m_queue->push(&QNetworkReplyHandler::finish); return; } - WTF::String contentType = m_reply->header(QNetworkRequest::ContentTypeHeader).toString(); - m_encoding = extractCharsetFromMediaType(contentType); - m_advertisedMimeType = extractMIMETypeFromMediaType(contentType); + if (!m_sniffMIMETypes) { + emitMetaDataChanged(); + return; + } + + bool isSupportedImageType = MIMETypeRegistry::isSupportedImageMIMEType(m_advertisedMIMEType); - bool hasData = m_reply->bytesAvailable(); - bool isFinished = m_reply->isFinished(); + Q_ASSERT(!m_sniffer); - if (!isFinished) { - // If not finished, connect to the slots that will be used from this point on. - connect(m_reply, SIGNAL(readyRead()), this, SIGNAL(readyRead())); - connect(m_reply, SIGNAL(finished()), this, SLOT(didReceiveFinished())); + m_sniffer = new QtMIMETypeSniffer(m_reply, m_advertisedMIMEType, isSupportedImageType); + + if (m_sniffer->isFinished()) { + receiveSniffedMIMEType(); + return; } - emit metaDataChanged(); + connect(m_sniffer.get(), SIGNAL(finished()), this, SLOT(receiveSniffedMIMEType())); +} + +void QNetworkReplyWrapper::receiveSniffedMIMEType() +{ + Q_ASSERT(m_sniffer); + + m_sniffedMIMEType = m_sniffer->mimeType(); + m_sniffer = 0; + + emitMetaDataChanged(); +} - if (hasData) - emit readyRead(); +void QNetworkReplyWrapper::emitMetaDataChanged() +{ + QueueLocker lock(m_queue); + m_queue->push(&QNetworkReplyHandler::sendResponseIfNeeded); - if (isFinished) { - emit finished(); + if (m_reply->bytesAvailable()) { + m_responseContainsData = true; + m_queue->push(&QNetworkReplyHandler::forwardData); + } + + if (m_reply->isFinished()) { + m_queue->push(&QNetworkReplyHandler::finish); return; } + // If not finished, connect to the slots that will be used from this point on. + connect(m_reply, SIGNAL(readyRead()), this, SLOT(didReceiveReadyRead())); + connect(m_reply, SIGNAL(finished()), this, SLOT(didReceiveFinished())); +} + +void QNetworkReplyWrapper::didReceiveReadyRead() +{ + if (m_reply->bytesAvailable()) + m_responseContainsData = true; + m_queue->push(&QNetworkReplyHandler::forwardData); } void QNetworkReplyWrapper::didReceiveFinished() { // Disconnecting will make sure that nothing will happen after emitting the finished signal. resetConnections(); - emit finished(); + m_queue->push(&QNetworkReplyHandler::finish); } String QNetworkReplyHandler::httpMethod() const @@ -255,11 +354,9 @@ QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadType load , m_replyWrapper(0) , m_resourceHandle(handle) , m_loadType(loadType) - , m_deferred(deferred) , m_redirectionTries(gMaxRedirections) + , m_queue(this, deferred) { - resetState(); - const ResourceRequest &r = m_resourceHandle->firstRequest(); if (r.httpMethod() == "GET") @@ -281,52 +378,7 @@ QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadType load m_request = r.toNetworkRequest(originatingObject); - if (!m_deferred) - start(); -} - -void QNetworkReplyHandler::resetState() -{ - m_redirected = false; - m_responseSent = false; - m_responseContainsData = false; - m_hasStarted = false; - m_callFinishOnResume = false; - m_callSendResponseIfNeededOnResume = false; - m_callForwardDataOnResume = false; - - if (m_replyWrapper) { - m_replyWrapper->deleteLater(); - m_replyWrapper = 0; - } -} - -void QNetworkReplyHandler::setLoadingDeferred(bool deferred) -{ - m_deferred = deferred; - - if (!deferred) - resumeDeferredLoad(); -} - -void QNetworkReplyHandler::resumeDeferredLoad() -{ - if (!m_hasStarted) { - ASSERT(!m_callSendResponseIfNeededOnResume); - ASSERT(!m_callForwardDataOnResume); - ASSERT(!m_callFinishOnResume); - start(); - return; - } - - if (m_callSendResponseIfNeededOnResume) - sendResponseIfNeeded(); - - if (m_callForwardDataOnResume) - forwardData(); - - if (m_callFinishOnResume) - finish(); + m_queue.push(&QNetworkReplyHandler::start); } void QNetworkReplyHandler::abort() @@ -345,7 +397,6 @@ QNetworkReply* QNetworkReplyHandler::release() return 0; QNetworkReply* reply = m_replyWrapper->release(); - m_replyWrapper->deleteLater(); m_replyWrapper = 0; return reply; } @@ -365,35 +416,21 @@ static bool shouldIgnoreHttpError(QNetworkReply* reply, bool receivedData) void QNetworkReplyHandler::finish() { - ASSERT(m_hasStarted); - - m_callFinishOnResume = m_deferred; - if (m_deferred) - return; - - if (!m_replyWrapper || !m_replyWrapper->reply()) - return; - - - sendResponseIfNeeded(); - - if (wasAborted()) - return; + ASSERT(m_replyWrapper && m_replyWrapper->reply() && !wasAborted()); ResourceHandleClient* client = m_resourceHandle->client(); if (!client) { - m_replyWrapper->deleteLater(); m_replyWrapper = 0; return; } - if (m_redirected) { - resetState(); - start(); + if (m_replyWrapper->wasRedirected()) { + m_replyWrapper = 0; + m_queue.push(&QNetworkReplyHandler::start); return; } - if (!m_replyWrapper->reply()->error() || shouldIgnoreHttpError(m_replyWrapper->reply(), m_responseContainsData)) + if (!m_replyWrapper->reply()->error() || shouldIgnoreHttpError(m_replyWrapper->reply(), m_replyWrapper->responseContainsData())) client->didFinishLoading(m_resourceHandle, 0); else { QUrl url = m_replyWrapper->reply()->url(); @@ -408,40 +445,21 @@ void QNetworkReplyHandler::finish() } } - if (m_replyWrapper) { - m_replyWrapper->deleteLater(); - m_replyWrapper = 0; - } + m_replyWrapper = 0; } void QNetworkReplyHandler::sendResponseIfNeeded() { - ASSERT(m_hasStarted); + ASSERT(m_replyWrapper && m_replyWrapper->reply() && !wasAborted()); - m_callSendResponseIfNeededOnResume = m_deferred; - if (m_deferred) + if (m_replyWrapper->reply()->error() && m_replyWrapper->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).isNull()) return; - if (!m_replyWrapper || !m_replyWrapper->reply()) - return; - - if (m_replyWrapper->reply()->error() && !shouldIgnoreHttpError(m_replyWrapper->reply(), m_responseContainsData)) - return; - - if (wasAborted()) - return; - - if (m_responseSent) - return; - m_responseSent = true; - ResourceHandleClient* client = m_resourceHandle->client(); if (!client) return; - WTF::String contentType = m_replyWrapper->reply()->header(QNetworkRequest::ContentTypeHeader).toString(); - WTF::String encoding = extractCharsetFromMediaType(contentType); - WTF::String mimeType = extractMIMETypeFromMediaType(contentType); + WTF::String mimeType = m_replyWrapper->mimeType(); if (mimeType.isEmpty()) { // let's try to guess from the extension @@ -451,7 +469,7 @@ void QNetworkReplyHandler::sendResponseIfNeeded() KURL url(m_replyWrapper->reply()->url()); ResourceResponse response(url, mimeType.lower(), m_replyWrapper->reply()->header(QNetworkRequest::ContentLengthHeader).toLongLong(), - encoding, String()); + m_replyWrapper->encoding(), String()); if (url.isLocalFile()) { client->didReceiveResponse(m_resourceHandle, response); @@ -501,9 +519,9 @@ void QNetworkReplyHandler::redirect(ResourceResponse& response, const QUrl& redi newUrl.toString(), QCoreApplication::translate("QWebPage", "Redirection limit reached")); client->didFail(m_resourceHandle, error); + m_replyWrapper = 0; return; } - m_redirected = true; // Status Code 301 (Moved Permanently), 302 (Moved Temporarily), 303 (See Other): // - If original request is POST convert to GET and redirect automatically @@ -533,26 +551,7 @@ void QNetworkReplyHandler::redirect(ResourceResponse& response, const QUrl& redi void QNetworkReplyHandler::forwardData() { - ASSERT(m_hasStarted); - - m_callForwardDataOnResume = m_deferred; - if (m_deferred) - return; - - if (!m_replyWrapper || !m_replyWrapper->reply()) - return; - - if (m_replyWrapper->reply()->bytesAvailable()) - m_responseContainsData = true; - - sendResponseIfNeeded(); - - // don't emit the "Document has moved here" type of HTML - if (m_redirected) - return; - - if (wasAborted()) - return; + ASSERT(m_replyWrapper && m_replyWrapper->reply() && !wasAborted() && !m_replyWrapper->wasRedirected()); QByteArray data = m_replyWrapper->reply()->read(m_replyWrapper->reply()->bytesAvailable()); @@ -579,17 +578,11 @@ void QNetworkReplyHandler::uploadProgress(qint64 bytesSent, qint64 bytesTotal) client->didSendData(m_resourceHandle, bytesSent, bytesTotal); } -QNetworkReply* QNetworkReplyHandler::sendNetworkRequest() +QNetworkReply* QNetworkReplyHandler::sendNetworkRequest(QNetworkAccessManager* manager, const ResourceRequest& request) { if (m_loadType == SynchronousLoad) m_request.setAttribute(gSynchronousNetworkRequestAttribute, true); - ResourceHandleInternal* d = m_resourceHandle->getInternal(); - - QNetworkAccessManager* manager = 0; - if (d->m_context) - manager = d->m_context->networkAccessManager(); - if (!manager) return 0; @@ -606,7 +599,7 @@ QNetworkReply* QNetworkReplyHandler::sendNetworkRequest() case QNetworkAccessManager::GetOperation: return manager->get(m_request); case QNetworkAccessManager::PostOperation: { - FormDataIODevice* postDevice = new FormDataIODevice(d->m_firstRequest.httpBody()); + FormDataIODevice* postDevice = new FormDataIODevice(request.httpBody()); // We may be uploading files so prevent QNR from buffering data m_request.setHeader(QNetworkRequest::ContentLengthHeader, postDevice->getFormDataSize()); m_request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, QVariant(true)); @@ -617,7 +610,7 @@ QNetworkReply* QNetworkReplyHandler::sendNetworkRequest() case QNetworkAccessManager::HeadOperation: return manager->head(m_request); case QNetworkAccessManager::PutOperation: { - FormDataIODevice* putDevice = new FormDataIODevice(d->m_firstRequest.httpBody()); + FormDataIODevice* putDevice = new FormDataIODevice(request.httpBody()); // We may be uploading files so prevent QNR from buffering data m_request.setHeader(QNetworkRequest::ContentLengthHeader, putDevice->getFormDataSize()); m_request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, QVariant(true)); @@ -639,24 +632,22 @@ QNetworkReply* QNetworkReplyHandler::sendNetworkRequest() void QNetworkReplyHandler::start() { - ASSERT(!m_hasStarted); - m_hasStarted = true; + ResourceHandleInternal* d = m_resourceHandle->getInternal(); + if (!d || !d->m_context) + return; - QNetworkReply* reply = sendNetworkRequest(); + QNetworkReply* reply = sendNetworkRequest(d->m_context->networkAccessManager(), d->m_firstRequest); if (!reply) return; - m_replyWrapper = new QNetworkReplyWrapper(reply, this); + m_replyWrapper = new QNetworkReplyWrapper(&m_queue, reply, m_resourceHandle->shouldContentSniff() && d->m_context->mimeSniffingEnabled(), this); if (m_loadType == SynchronousLoad && m_replyWrapper->reply()->isFinished()) { + m_replyWrapper->synchronousLoad(); // If supported, a synchronous request will be finished at this point, no need to hook up the signals. return; } - connect(m_replyWrapper, SIGNAL(finished()), this, SLOT(finish())); - connect(m_replyWrapper, SIGNAL(metaDataChanged()), this, SLOT(sendResponseIfNeeded())); - connect(m_replyWrapper, SIGNAL(readyRead()), this, SLOT(forwardData())); - if (m_resourceHandle->firstRequest().reportUploadProgress()) connect(m_replyWrapper->reply(), SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(uploadProgress(qint64, qint64))); } diff --git a/Source/WebCore/platform/network/qt/QNetworkReplyHandler.h b/Source/WebCore/platform/network/qt/QNetworkReplyHandler.h index 61694d6..ec4e65a 100644 --- a/Source/WebCore/platform/network/qt/QNetworkReplyHandler.h +++ b/Source/WebCore/platform/network/qt/QNetworkReplyHandler.h @@ -25,6 +25,7 @@ #include <QNetworkAccessManager> #include "FormData.h" +#include "QtMIMETypeSniffer.h" QT_BEGIN_NAMESPACE class QFile; @@ -34,39 +35,73 @@ QT_END_NAMESPACE namespace WebCore { class ResourceHandle; +class ResourceRequest; class ResourceResponse; +class QNetworkReplyHandler; + +class QNetworkReplyHandlerCallQueue { +public: + QNetworkReplyHandlerCallQueue(QNetworkReplyHandler*, bool deferSignals); + bool deferSignals() const { return m_deferSignals; } + void setDeferSignals(bool); + + typedef void (QNetworkReplyHandler::*EnqueuedCall)(); + void push(EnqueuedCall method); + void clear() { m_enqueuedCalls.clear(); } + + void lock(); + void unlock(); +private: + QNetworkReplyHandler* m_replyHandler; + int m_locks; + bool m_deferSignals; + bool m_flushing; + QList<EnqueuedCall> m_enqueuedCalls; + + void flush(); +}; class QNetworkReplyWrapper : public QObject { Q_OBJECT public: - QNetworkReplyWrapper(QNetworkReply*, QObject* parent = 0); + QNetworkReplyWrapper(QNetworkReplyHandlerCallQueue*, QNetworkReply*, bool sniffMIMETypes, QObject* parent = 0); ~QNetworkReplyWrapper(); QNetworkReply* reply() const { return m_reply; } QNetworkReply* release(); + void synchronousLoad() { receiveMetaData(); } + QUrl redirectionTargetUrl() const { return m_redirectionTargetUrl; } QString encoding() const { return m_encoding; } - QString advertisedMimeType() const { return m_advertisedMimeType; } + QString advertisedMIMEType() const { return m_advertisedMIMEType; } + QString mimeType() const { return m_sniffedMIMEType.isEmpty() ? m_advertisedMIMEType : m_sniffedMIMEType; } -Q_SIGNALS: - void finished(); - void metaDataChanged(); - void readyRead(); - void uploadProgress(qint64 bytesSent, qint64 bytesTotal); + bool responseContainsData() const { return m_responseContainsData; } + bool wasRedirected() const { return m_redirectionTargetUrl.isValid(); } private Q_SLOTS: void receiveMetaData(); void didReceiveFinished(); + void didReceiveReadyRead(); + void receiveSniffedMIMEType(); private: void resetConnections(); + void emitMetaDataChanged(); QNetworkReply* m_reply; QUrl m_redirectionTargetUrl; QString m_encoding; - QString m_advertisedMimeType; + QNetworkReplyHandlerCallQueue* m_queue; + bool m_responseContainsData; + + QString m_advertisedMIMEType; + + QString m_sniffedMIMEType; + OwnPtr<QtMIMETypeSniffer> m_sniffer; + bool m_sniffMIMETypes; }; class QNetworkReplyHandler : public QObject @@ -79,7 +114,7 @@ public: }; QNetworkReplyHandler(ResourceHandle*, LoadType, bool deferred = false); - void setLoadingDeferred(bool); + void setLoadingDeferred(bool deferred) { m_queue.setDeferSignals(deferred); } QNetworkReply* reply() const { return m_replyWrapper ? m_replyWrapper->reply() : 0; } @@ -87,38 +122,30 @@ public: QNetworkReply* release(); -public slots: void finish(); - void sendResponseIfNeeded(); void forwardData(); + void sendResponseIfNeeded(); + +private slots: void uploadProgress(qint64 bytesSent, qint64 bytesTotal); private: void start(); - void resetState(); String httpMethod() const; - void resumeDeferredLoad(); void redirect(ResourceResponse&, const QUrl&); bool wasAborted() const { return !m_resourceHandle; } - QNetworkReply* sendNetworkRequest(); + QNetworkReply* sendNetworkRequest(QNetworkAccessManager*, const ResourceRequest&); - QNetworkReplyWrapper* m_replyWrapper; + OwnPtr<QNetworkReplyWrapper> m_replyWrapper; ResourceHandle* m_resourceHandle; - bool m_redirected; - bool m_responseSent; - bool m_responseContainsData; LoadType m_loadType; QNetworkAccessManager::Operation m_method; QNetworkRequest m_request; - bool m_deferred; - // defer state holding - bool m_hasStarted; - bool m_callFinishOnResume; - bool m_callSendResponseIfNeededOnResume; - bool m_callForwardDataOnResume; int m_redirectionTries; + + QNetworkReplyHandlerCallQueue m_queue; }; // Self destructing QIODevice for FormData diff --git a/Source/WebCore/platform/network/qt/QtMIMETypeSniffer.cpp b/Source/WebCore/platform/network/qt/QtMIMETypeSniffer.cpp new file mode 100644 index 0000000..e719b80 --- /dev/null +++ b/Source/WebCore/platform/network/qt/QtMIMETypeSniffer.cpp @@ -0,0 +1,63 @@ +/* + Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" +#include "QtMIMETypeSniffer.h" + +#include "MIMESniffing.h" +#include <QCoreApplication> +#include <QNetworkReply> + +QtMIMETypeSniffer::QtMIMETypeSniffer(QNetworkReply* reply, const QString& advertisedMimeType, bool isSupportedImageType) + : QObject(0) + , m_reply(reply) + , m_mimeType(advertisedMimeType) + , m_sniffer(advertisedMimeType.toLatin1().constData(), isSupportedImageType) + , m_isFinished(false) +{ + m_isFinished = !m_sniffer.isValid() || sniff(); + if (m_isFinished) + return; + + connect(m_reply, SIGNAL(readyRead()), this, SLOT(trySniffing())); + connect(m_reply, SIGNAL(finished()), this, SLOT(trySniffing())); +} + +bool QtMIMETypeSniffer::sniff() +{ + if (!m_reply->isFinished() && m_reply->bytesAvailable() < m_sniffer.dataSize()) + return false; + + QByteArray data = m_reply->peek(m_sniffer.dataSize()); + const char* sniffedMimeType = m_sniffer.sniff(data.constData(), data.size()); + if (sniffedMimeType) + m_mimeType = QString::fromLatin1(sniffedMimeType); + return true; +} + +void QtMIMETypeSniffer::trySniffing() +{ + if (!sniff()) + return; + + m_reply->disconnect(this); + QCoreApplication::removePostedEvents(this, QEvent::MetaCall); + m_isFinished = true; + emit finished(); +} diff --git a/Source/WebCore/platform/network/qt/QtMIMETypeSniffer.h b/Source/WebCore/platform/network/qt/QtMIMETypeSniffer.h new file mode 100644 index 0000000..5424906 --- /dev/null +++ b/Source/WebCore/platform/network/qt/QtMIMETypeSniffer.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef QtMIMETypeSniffer_h +#define QtMIMETypeSniffer_h + +#include "MIMESniffing.h" +#include <QObject> + +class QNetworkReply; + +class QtMIMETypeSniffer : public QObject { + Q_OBJECT +public: + QtMIMETypeSniffer(QNetworkReply*, const QString& advertisedMimeType, bool isSupportedImageType); + QString mimeType() const { return m_mimeType; } + bool isFinished() const { return m_isFinished; } + +signals: + void finished(); + +private slots: + void trySniffing(); + +private: + bool sniff(); + + QNetworkReply* m_reply; + QString m_mimeType; + MIMESniffer m_sniffer; + bool m_isFinished; +}; + +#endif // QtMIMETypeSniffer_h diff --git a/Source/WebCore/platform/network/qt/ResourceHandleQt.cpp b/Source/WebCore/platform/network/qt/ResourceHandleQt.cpp index a6da432..642d0a6 100644 --- a/Source/WebCore/platform/network/qt/ResourceHandleQt.cpp +++ b/Source/WebCore/platform/network/qt/ResourceHandleQt.cpp @@ -53,62 +53,22 @@ namespace WebCore { class WebCoreSynchronousLoader : public ResourceHandleClient { public: - WebCoreSynchronousLoader(); - - void waitForCompletion(); - - virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&); - virtual void didReceiveData(ResourceHandle*, const char*, int, int lengthReceived); - virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/); - virtual void didFail(ResourceHandle*, const ResourceError&); - - ResourceResponse resourceResponse() const { return m_response; } - ResourceError resourceError() const { return m_error; } - Vector<char> data() const { return m_data; } - - void setReplyFinished(bool finished) { m_replyFinished = finished; } - + WebCoreSynchronousLoader(ResourceError& error, ResourceResponse& response, Vector<char>& data) + : m_error(error) + , m_response(response) + , m_data(data) + {} + + virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse& response) { m_response = response; } + virtual void didReceiveData(ResourceHandle*, const char* data, int length, int) { m_data.append(data, length); } + virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/) {} + virtual void didFail(ResourceHandle*, const ResourceError& error) { m_error = error; } private: - ResourceResponse m_response; - ResourceError m_error; - Vector<char> m_data; - QEventLoop m_eventLoop; - bool m_replyFinished; + ResourceError& m_error; + ResourceResponse& m_response; + Vector<char>& m_data; }; -WebCoreSynchronousLoader::WebCoreSynchronousLoader() - : m_replyFinished(false) -{ -} - -void WebCoreSynchronousLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse& response) -{ - m_response = response; -} - -void WebCoreSynchronousLoader::didReceiveData(ResourceHandle*, const char* data, int length, int) -{ - m_data.append(data, length); -} - -void WebCoreSynchronousLoader::didFinishLoading(ResourceHandle*, double) -{ - if (!m_replyFinished) - m_eventLoop.exit(); -} - -void WebCoreSynchronousLoader::didFail(ResourceHandle*, const ResourceError& error) -{ - m_error = error; - if (!m_replyFinished) - m_eventLoop.exit(); -} - -void WebCoreSynchronousLoader::waitForCompletion() -{ - m_eventLoop.exec(QEventLoop::ExcludeUserInputEvents); -} - ResourceHandleInternal::~ResourceHandleInternal() { } @@ -191,7 +151,7 @@ PassRefPtr<SharedBuffer> ResourceHandle::bufferedData() void ResourceHandle::loadResourceSynchronously(NetworkingContext* context, const ResourceRequest& request, StoredCredentials /*storedCredentials*/, ResourceError& error, ResourceResponse& response, Vector<char>& data) { - WebCoreSynchronousLoader syncLoader; + WebCoreSynchronousLoader syncLoader(error, response, data); RefPtr<ResourceHandle> handle = adoptRef(new ResourceHandle(request, &syncLoader, true, false)); ResourceHandleInternal* d = handle->getInternal(); @@ -204,20 +164,10 @@ void ResourceHandle::loadResourceSynchronously(NetworkingContext* context, const d->m_firstRequest.setURL(urlWithCredentials); } d->m_context = context; - d->m_job = new QNetworkReplyHandler(handle.get(), QNetworkReplyHandler::SynchronousLoad); - - QNetworkReply* reply = d->m_job->reply(); - // When using synchronous calls, we are finished when reaching this point. - if (reply->isFinished()) { - syncLoader.setReplyFinished(true); - d->m_job->forwardData(); - d->m_job->finish(); - } else - syncLoader.waitForCompletion(); - - error = syncLoader.resourceError(); - data = syncLoader.data(); - response = syncLoader.resourceResponse(); + + // starting in deferred mode gives d->m_job the chance of being set before sending the request. + d->m_job = new QNetworkReplyHandler(handle.get(), QNetworkReplyHandler::SynchronousLoad, true); + d->m_job->setLoadingDeferred(false); } void ResourceHandle::platformSetDefersLoading(bool defers) diff --git a/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp b/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp index e5da0e3..dc22fca 100644 --- a/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp +++ b/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp @@ -69,7 +69,7 @@ public: ~WebCoreSynchronousLoader(); virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&); - virtual void didReceiveData(ResourceHandle*, const char*, int, int lengthReceived); + virtual void didReceiveData(ResourceHandle*, const char*, int, int encodedDataLength); virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/); virtual void didFail(ResourceHandle*, const ResourceError&); @@ -135,11 +135,6 @@ ResourceHandleInternal::~ResourceHandleInternal() { if (m_soupRequest) g_object_set_data(G_OBJECT(m_soupRequest.get()), "webkit-resource", 0); - - if (m_idleHandler) { - g_source_remove(m_idleHandler); - m_idleHandler = 0; - } } ResourceHandle::~ResourceHandle() diff --git a/Source/WebCore/platform/network/win/ResourceHandleWin.cpp b/Source/WebCore/platform/network/win/ResourceHandleWin.cpp index dc5adc8..3e596be 100644 --- a/Source/WebCore/platform/network/win/ResourceHandleWin.cpp +++ b/Source/WebCore/platform/network/win/ResourceHandleWin.cpp @@ -85,7 +85,7 @@ public: HINTERNET internetHandle() const { return m_internetHandle; } virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&); - virtual void didReceiveData(ResourceHandle*, const char*, int, int lengthReceived); + virtual void didReceiveData(ResourceHandle*, const char*, int, int encodedDataLength); virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/); virtual void didFail(ResourceHandle*, const ResourceError&); diff --git a/Source/WebCore/platform/qt/ClipboardQt.cpp b/Source/WebCore/platform/qt/ClipboardQt.cpp index c14d362..723cdd4 100644 --- a/Source/WebCore/platform/qt/ClipboardQt.cpp +++ b/Source/WebCore/platform/qt/ClipboardQt.cpp @@ -299,6 +299,7 @@ void ClipboardQt::declareAndWriteDragImage(Element* element, const KURL& url, co m_writableData->setText(title); m_writableData->setUrls(urls); + m_writableData->setHtml(createMarkup(element, IncludeNode, 0, AbsoluteURLs)); #ifndef QT_NO_CLIPBOARD if (isForCopyAndPaste()) QApplication::clipboard()->setMimeData(m_writableData); diff --git a/Source/WebCore/platform/qt/QtMobileWebStyle.cpp b/Source/WebCore/platform/qt/QtMobileWebStyle.cpp index 240faa5..6ca1817 100644 --- a/Source/WebCore/platform/qt/QtMobileWebStyle.cpp +++ b/Source/WebCore/platform/qt/QtMobileWebStyle.cpp @@ -34,12 +34,13 @@ static inline void drawRectangularControlBackground(QPainter* painter, const QPe { QPen oldPen = painter->pen(); QBrush oldBrush = painter->brush(); + painter->setRenderHint(QPainter::Antialiasing, true); painter->setPen(pen); painter->setBrush(brush); int line = 1; - painter->drawRect(rect.adjusted(line, line, -line, -line)); - + painter->drawRoundedRect(rect.adjusted(line, line, -line, -line), + /* xRadius */ 5.0, /* yRadious */ 5.0); painter->setPen(oldPen); painter->setBrush(oldBrush); } @@ -71,8 +72,8 @@ QPixmap QtMobileWebStyle::findChecker(const QRect& rect, bool disabled) const { int size = qMin(rect.width(), rect.height()); QPixmap result; - static const QString prefix = "$qt-maemo5-" + QLatin1String(metaObject()->className()) + "-checker-"; - QString key = prefix + QString::number(size) + "-" + (disabled ? "disabled" : "enabled"); + static const QString prefix = QLatin1String("$qt-maemo5-") + QLatin1String(metaObject()->className())+ QLatin1String("-checker-"); + QString key = prefix + QString::number(size) + QLatin1String("-") + (disabled ? QLatin1String("disabled") : QLatin1String("enabled")); if (!QPixmapCache::find(key, result)) { result = QPixmap(size, size); result.fill(Qt::transparent); @@ -87,8 +88,10 @@ void QtMobileWebStyle::drawRadio(QPainter* painter, const QSize& size, bool chec { painter->setRenderHint(QPainter::Antialiasing, true); + // get minor size to do not paint a wide elipse + qreal squareSize = qMin(size.width(), size.height()); // deflate one pixel - QRect rect = QRect(QPoint(1, 1), QSize(size.width() - 2, size.height() - 2)); + QRect rect = QRect(QPoint(1, 1), QSize(squareSize - 2, squareSize - 2)); const QPoint centerGradient(rect.bottomRight() * 0.7); QRadialGradient radialGradient(centerGradient, centerGradient.x() - 1); @@ -115,9 +118,9 @@ void QtMobileWebStyle::drawRadio(QPainter* painter, const QSize& size, bool chec QPixmap QtMobileWebStyle::findRadio(const QSize& size, bool checked, bool disabled) const { QPixmap result; - static const QString prefix = "$qt-maemo5-" + QLatin1String(metaObject()->className()) + "-radio-"; - QString key = prefix + QString::number(size.width()) + "-" + QString::number(size.height()) + - + "-" + (disabled ? "disabled" : "enabled") + (checked ? "-checked" : ""); + static const QString prefix = QLatin1String("$qt-maemo5-") + QLatin1String(metaObject()->className()) + QLatin1String("-radio-"); + QString key = prefix + QString::number(size.width()) + QLatin1String("-") + QString::number(size.height()) + QLatin1String("-") + + (disabled ? QLatin1String("disabled") : QLatin1String("enabled")) + (checked ? QLatin1String("-checked") : QLatin1String("")); if (!QPixmapCache::find(key, result)) { result = QPixmap(size); result.fill(Qt::transparent); @@ -144,7 +147,9 @@ void QtMobileWebStyle::drawControl(ControlElement element, const QStyleOption* o linearGradient.setColorAt(0.5, Qt::white); } - drawRectangularControlBackground(painter, QPen(disabled ? Qt::lightGray : Qt::darkGray), rect, linearGradient); + painter->setPen(QPen(disabled ? Qt::lightGray : Qt::darkGray)); + painter->setBrush(linearGradient); + painter->drawRect(rect); rect.adjust(1, 1, -1, -1); if (option->state & State_Off) @@ -167,10 +172,75 @@ void QtMobileWebStyle::drawControl(ControlElement element, const QStyleOption* o painter->drawPixmap(option->rect.x(), option->rect.y(), radio); break; } + case CE_PushButton: { + const bool disabled = !(option->state & State_Enabled); + QRect rect = option->rect; + QPen pen(Qt::darkGray, 1.0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); + painter->setPen(pen); + + const bool sunken = (option->state & State_Sunken); + if (sunken) { + drawRectangularControlBackground(painter, pen, rect, QBrush(Qt::darkGray)); + break; + } + + QLinearGradient linearGradient; + if (disabled) { + linearGradient.setStart(rect.bottomLeft()); + linearGradient.setFinalStop(rect.topLeft()); + linearGradient.setColorAt(0.0, Qt::gray); + linearGradient.setColorAt(1.0, Qt::white); + } else { + linearGradient.setStart(rect.bottomLeft()); + linearGradient.setFinalStop(QPoint(rect.bottomLeft().x(), + rect.bottomLeft().y() - /* offset limit for gradient */ 20)); + linearGradient.setColorAt(0.0, Qt::gray); + linearGradient.setColorAt(0.4, Qt::white); + } + + drawRectangularControlBackground(painter, pen, rect, linearGradient); + break; + } default: QWindowsStyle::drawControl(element, option, painter, widget); } } +void QtMobileWebStyle::drawPrimitive(PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const +{ + switch (element) { + case QStyle::PE_PanelLineEdit: { + const bool disabled = !(option->state & State_Enabled); + const bool sunken = (option->state & State_Sunken); + QRect rect = option->rect; + QPen pen(Qt::darkGray, 1.0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); + painter->setPen(pen); + + if (sunken) { + drawRectangularControlBackground(painter, pen, rect, QBrush(Qt::darkGray)); + break; + } + + QLinearGradient linearGradient; + if (disabled) { + linearGradient.setStart(rect.topLeft()); + linearGradient.setFinalStop(rect.bottomLeft()); + linearGradient.setColorAt(0.0, Qt::lightGray); + linearGradient.setColorAt(1.0, Qt::white); + } else { + linearGradient.setStart(rect.topLeft()); + linearGradient.setFinalStop(QPoint(rect.topLeft().x(), + rect.topLeft().y() + /* offset limit for gradient */ 20)); + linearGradient.setColorAt(0.0, Qt::darkGray); + linearGradient.setColorAt(0.35, Qt::white); + } + + drawRectangularControlBackground(painter, pen, rect, linearGradient); + break; + } + default: + QWindowsStyle::drawPrimitive(element, option, painter, widget); + } +} void QtMobileWebStyle::drawMultipleComboButton(QPainter* painter, const QSize& size, QColor color) const { @@ -230,10 +300,10 @@ QPixmap QtMobileWebStyle::findComboButton(const QSize& size, bool multiple, bool if (imageSize.isNull()) return QPixmap(); - static const QString prefix = "$qt-maemo5-" + QLatin1String(metaObject()->className()) + "-combo-"; - QString key = prefix + (multiple ? "multiple-" : "simple-") + - QString::number(imageSize.width()) + "-" + QString::number(imageSize.height()) + - + "-" + (disabled ? "disabled" : "enabled"); + static const QString prefix = QLatin1String("$qt-maemo5-") + QLatin1String(metaObject()->className()) + QLatin1String("-combo-"); + QString key = prefix + (multiple ? QLatin1String("multiple-") : QLatin1String("simple-")) + + QString::number(imageSize.width()) + QLatin1String("-") + QString::number(imageSize.height()) + + QLatin1String("-") + (disabled ? QLatin1String("disabled") : QLatin1String("enabled")); if (!QPixmapCache::find(key, result)) { result = QPixmap(imageSize); result.fill(Qt::transparent); @@ -251,7 +321,6 @@ void QtMobileWebStyle::drawComplexControl(ComplexControl control, const QStyleOp { switch (control) { case CC_ComboBox: { - bool multiple = false; const bool disabled = !(option->state & State_Enabled); @@ -272,7 +341,25 @@ void QtMobileWebStyle::drawComplexControl(ComplexControl control, const QStyleOp if (!(cmb->subControls & SC_ComboBoxArrow)) break; - QRect rect = subControlRect(CC_ComboBox, cmb, SC_ComboBoxArrow, widget); + QRect rect = option->rect; + QPen pen(Qt::darkGray, 1.0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); + QLinearGradient linearGradient; + if (disabled) { + linearGradient.setStart(rect.bottomLeft()); + linearGradient.setFinalStop(rect.topLeft()); + linearGradient.setColorAt(0.0, Qt::gray); + linearGradient.setColorAt(1.0, Qt::white); + } else { + linearGradient.setStart(rect.bottomLeft()); + linearGradient.setFinalStop(QPoint(rect.bottomLeft().x(), + rect.bottomLeft().y() - /* offset limit for gradient */ 20)); + linearGradient.setColorAt(0.0, Qt::gray); + linearGradient.setColorAt(0.4, Qt::white); + } + + drawRectangularControlBackground(painter, pen, rect, linearGradient); + + rect = subControlRect(CC_ComboBox, cmb, SC_ComboBoxArrow, widget); QPixmap pic = findComboButton(rect.size(), multiple, disabled); if (pic.isNull()) @@ -291,3 +378,4 @@ void QtMobileWebStyle::drawComplexControl(ComplexControl control, const QStyleOp QWindowsStyle::drawComplexControl(control, option, painter, widget); } } + diff --git a/Source/WebCore/platform/qt/QtMobileWebStyle.h b/Source/WebCore/platform/qt/QtMobileWebStyle.h index 779bd26..1b99d2b 100644 --- a/Source/WebCore/platform/qt/QtMobileWebStyle.h +++ b/Source/WebCore/platform/qt/QtMobileWebStyle.h @@ -27,8 +27,9 @@ class QtMobileWebStyle : public QWindowsStyle { public: QtMobileWebStyle(); - void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = 0) const; - void drawComplexControl(ComplexControl cc, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget = 0) const; + void drawControl(ControlElement, const QStyleOption*, QPainter*, const QWidget*) const; + void drawComplexControl(ComplexControl, const QStyleOptionComplex*, QPainter*, const QWidget*) const; + void drawPrimitive(PrimitiveElement, const QStyleOption*, QPainter*, const QWidget*) const; private: void drawChecker(QPainter* painter, int size, QColor color) const; diff --git a/Source/WebCore/platform/qt/RenderThemeQt.cpp b/Source/WebCore/platform/qt/RenderThemeQt.cpp index cc654d5..8cb59c1 100644 --- a/Source/WebCore/platform/qt/RenderThemeQt.cpp +++ b/Source/WebCore/platform/qt/RenderThemeQt.cpp @@ -46,6 +46,9 @@ #if USE(QT_MOBILE_THEME) #include "QtMobileWebStyle.h" #endif +#if ENABLE(VIDEO) +#include "MediaControlElements.h" +#endif #include "NotImplemented.h" #include "PaintInfo.h" #include "Page.h" @@ -78,7 +81,6 @@ #include <QStyleOptionSlider> #include <QWidget> - namespace WebCore { using namespace HTMLNames; @@ -105,6 +107,16 @@ static const float minSearchFieldResultsDecorationSize = 9; static const float maxSearchFieldResultsDecorationSize = 30; static const float defaultSearchFieldResultsButtonWidth = 18; +#if USE(QT_MOBILE_THEME) +namespace { + float buttonPaddingLeft = 18; + float buttonPaddingRight = 18; + float buttonPaddingTop = 2; + float buttonPaddingBottom = 3; + float menuListPadding = 9; + float textFieldPadding = 5; +} +#endif StylePainter::StylePainter(RenderThemeQt* theme, const PaintInfo& paintInfo) { @@ -198,10 +210,13 @@ bool RenderThemeQt::isControlStyled(const RenderStyle* style, const BorderData& case PushButtonPart: case ButtonPart: case MenulistPart: - // FIXME: Need to add SearchFieldPart if it should be style-able. + case SearchFieldPart: case TextFieldPart: case TextAreaPart: - return true; + // Test the style to see if the UA border and background match. + return (style->border() != border + || *style->backgroundLayers() != fill + || style->visitedDependentColor(CSSPropertyBackgroundColor) != backgroundColor); case CheckboxPart: case RadioPart: return false; @@ -258,9 +273,6 @@ String RenderThemeQt::extraDefaultStyleSheet() #if ENABLE(NO_LISTBOX_RENDERING) result += String(themeQtNoListboxesUserAgentStyleSheet, sizeof(themeQtNoListboxesUserAgentStyleSheet)); #endif -#if USE(QT_MOBILE_THEME) - result += String(themeQtMobileUserAgentStyleSheet, sizeof(themeQtMobileUserAgentStyleSheet)); -#endif return result; } @@ -448,7 +460,6 @@ void RenderThemeQt::computeSizeBasedOnStyle(RenderStyle* renderStyle) const case SearchFieldPart: case TextFieldPart: { int padding = findFrameLineWidth(style); - renderStyle->setPaddingLeft(Length(padding, Fixed)); renderStyle->setPaddingRight(Length(padding, Fixed)); renderStyle->setPaddingTop(Length(padding, Fixed)); @@ -458,7 +469,6 @@ void RenderThemeQt::computeSizeBasedOnStyle(RenderStyle* renderStyle) const default: break; } - // If the width and height are both specified, then we have nothing to do. if (!renderStyle->width().isIntrinsicOrAuto() && !renderStyle->height().isAuto()) return; @@ -480,6 +490,7 @@ void RenderThemeQt::computeSizeBasedOnStyle(RenderStyle* renderStyle) const size = QSize(radioWidth, radioWidth); break; } +#if !USE(QT_MOBILE_THEME) case PushButtonPart: case ButtonPart: { QStyleOptionButton styleOption; @@ -509,6 +520,7 @@ void RenderThemeQt::computeSizeBasedOnStyle(RenderStyle* renderStyle) const size.setHeight(menuListSize.height()); break; } +#endif default: break; } @@ -564,13 +576,14 @@ void RenderThemeQt::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* s fontDescription.setComputedSize(style->fontSize()); #endif +#if !USE(QT_MOBILE_THEME) FontFamily fontFamily; fontFamily.setFamily(m_buttonFontFamily); fontDescription.setFamily(fontFamily); style->setFontDescription(fontDescription); style->font().update(selector->fontSelector()); +#endif style->setLineHeight(RenderStyle::initialLineHeight()); - setButtonSize(style); setButtonPadding(style); } @@ -580,6 +593,7 @@ void RenderThemeQt::setButtonSize(RenderStyle* style) const computeSizeBasedOnStyle(style); } +#if !USE(QT_MOBILE_THEME) void RenderThemeQt::setButtonPadding(RenderStyle* style) const { QStyleOptionButton styleOption; @@ -609,12 +623,22 @@ void RenderThemeQt::setButtonPadding(RenderStyle* style) const // Can't use this right now because we don't have the baseline to compensate // paddingBottom = layoutRect.bottom() - contentsRect.bottom(); } - style->setPaddingLeft(Length(paddingLeft, Fixed)); style->setPaddingRight(Length(paddingRight, Fixed)); style->setPaddingTop(Length(paddingTop, Fixed)); style->setPaddingBottom(Length(paddingBottom, Fixed)); } +#else +void RenderThemeQt::setButtonPadding(RenderStyle* style) const +{ + if (!style) + return; + style->setPaddingLeft(Length(buttonPaddingLeft, Fixed)); + style->setPaddingRight(Length(buttonPaddingRight, Fixed)); + style->setPaddingTop(Length(buttonPaddingTop, Fixed)); + style->setPaddingBottom(Length(buttonPaddingBottom, Fixed)); +} +#endif bool RenderThemeQt::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& r) { @@ -650,6 +674,10 @@ void RenderThemeQt::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, style->resetBorder(); style->resetPadding(); computeSizeBasedOnStyle(style); +#if USE(QT_MOBILE_THEME) + style->setPaddingLeft(Length(textFieldPadding, Fixed)); + style->setPaddingRight(Length(textFieldPadding, Fixed)); +#endif } bool RenderThemeQt::paintTextField(RenderObject* o, const PaintInfo& i, const IntRect& r) @@ -662,7 +690,12 @@ bool RenderThemeQt::paintTextField(RenderObject* o, const PaintInfo& i, const In initStyleOption(p.widget, panel); panel.rect = r; panel.lineWidth = findFrameLineWidth(qStyle()); +#if USE(QT_MOBILE_THEME) + if (isPressed(o)) + panel.state |= QStyle::State_Sunken; +#else panel.state |= QStyle::State_Sunken; +#endif panel.features = QStyleOptionFrameV2::None; // Get the correct theme data for a text field @@ -675,7 +708,6 @@ bool RenderThemeQt::paintTextField(RenderObject* o, const PaintInfo& i, const In // Now paint the text field. p.drawPrimitive(QStyle::PE_PanelLineEdit, panel); - return false; } @@ -703,6 +735,9 @@ void RenderThemeQt::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, E // Add in the padding that we'd like to use. setPopupPadding(style); +#if USE(QT_MOBILE_THEME) + style->setPaddingLeft(Length(menuListPadding, Fixed)); +#endif } void RenderThemeQt::setPopupPadding(RenderStyle* style) const @@ -1076,9 +1111,6 @@ ControlPart RenderThemeQt::initializeCommonQStyleOptions(QStyleOption& option, R // Default bits: no focus, no mouse over option.state &= ~(QStyle::State_HasFocus | QStyle::State_MouseOver); - if (!isEnabled(o)) - option.state &= ~QStyle::State_Enabled; - if (isReadOnlyControl(o)) // Readonly is supported on textfields. option.state |= QStyle::State_ReadOnly; @@ -1089,6 +1121,12 @@ ControlPart RenderThemeQt::initializeCommonQStyleOptions(QStyleOption& option, R option.state |= QStyle::State_MouseOver; setPaletteFromPageClientIfExists(option.palette); + + if (!isEnabled(o)) { + option.palette.setCurrentColorGroup(QPalette::Disabled); + option.state &= ~QStyle::State_Enabled; + } + RenderStyle* style = o->style(); if (!style) return NoControlPart; @@ -1156,16 +1194,6 @@ private: QTransform m_originalTransform; }; -HTMLMediaElement* RenderThemeQt::getMediaElementFromRenderObject(RenderObject* o) const -{ - Node* node = o->node(); - Node* mediaNode = node ? node->shadowAncestorNode() : 0; - if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag))) - return 0; - - return static_cast<HTMLMediaElement*>(mediaNode); -} - double RenderThemeQt::mediaControlsBaselineOpacity() const { return 0.4; @@ -1189,7 +1217,7 @@ QColor RenderThemeQt::getMediaControlForegroundColor(RenderObject* o) const bool RenderThemeQt::paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { - HTMLMediaElement* mediaElement = getMediaElementFromRenderObject(o); + HTMLMediaElement* mediaElement = toParentMediaElement(o); if (!mediaElement) return false; @@ -1213,7 +1241,7 @@ bool RenderThemeQt::paintMediaFullscreenButton(RenderObject* o, const PaintInfo& bool RenderThemeQt::paintMediaMuteButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { - HTMLMediaElement* mediaElement = getMediaElementFromRenderObject(o); + HTMLMediaElement* mediaElement = toParentMediaElement(o); if (!mediaElement) return false; @@ -1237,7 +1265,7 @@ bool RenderThemeQt::paintMediaMuteButton(RenderObject* o, const PaintInfo& paint bool RenderThemeQt::paintMediaPlayButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { - HTMLMediaElement* mediaElement = getMediaElementFromRenderObject(o); + HTMLMediaElement* mediaElement = toParentMediaElement(o); if (!mediaElement) return false; @@ -1356,7 +1384,7 @@ bool RenderThemeQt::paintMediaVolumeSliderThumb(RenderObject *o, const PaintInfo bool RenderThemeQt::paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { - HTMLMediaElement* mediaElement = getMediaElementFromRenderObject(o); + HTMLMediaElement* mediaElement = toParentMediaElement(o); if (!mediaElement) return false; diff --git a/Source/WebCore/platform/qt/RenderThemeQt.h b/Source/WebCore/platform/qt/RenderThemeQt.h index 6981641..b436a03 100644 --- a/Source/WebCore/platform/qt/RenderThemeQt.h +++ b/Source/WebCore/platform/qt/RenderThemeQt.h @@ -158,8 +158,8 @@ protected: virtual bool paintMediaVolumeSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); virtual String formatMediaControlsCurrentTime(float currentTime, float duration) const; virtual String formatMediaControlsRemainingTime(float currentTime, float duration) const; + virtual bool hasOwnDisabledStateHandlingFor(ControlPart) const { return true; } private: - HTMLMediaElement* getMediaElementFromRenderObject(RenderObject* o) const; void paintMediaBackground(QPainter* painter, const IntRect& r) const; double mediaControlsBaselineOpacity() const; QColor getMediaControlForegroundColor(RenderObject* o = 0) const; diff --git a/Source/WebCore/platform/qt/ScrollbarThemeQt.cpp b/Source/WebCore/platform/qt/ScrollbarThemeQt.cpp index 67226b0..079c676 100644 --- a/Source/WebCore/platform/qt/ScrollbarThemeQt.cpp +++ b/Source/WebCore/platform/qt/ScrollbarThemeQt.cpp @@ -110,8 +110,12 @@ static QStyleOptionSlider* styleOptionSlider(Scrollbar* scrollbar, QWidget* widg if (scrollbar->controlSize() != RegularScrollbar) opt.state |= QStyle::State_Mini; opt.orientation = (scrollbar->orientation() == VerticalScrollbar) ? Qt::Vertical : Qt::Horizontal; + if (scrollbar->orientation() == HorizontalScrollbar) opt.state |= QStyle::State_Horizontal; + else + opt.state &= ~QStyle::State_Horizontal; + opt.sliderValue = scrollbar->value(); opt.sliderPosition = opt.sliderValue; opt.pageStep = scrollbar->pageStep(); @@ -190,6 +194,9 @@ void ScrollbarThemeQt::invalidatePart(Scrollbar* scrollbar, ScrollbarPart) int ScrollbarThemeQt::scrollbarThickness(ScrollbarControlSize controlSize) { +#if USE(QT_MOBILE_THEME) + return 0; +#endif QStyleOptionSlider o; o.orientation = Qt::Vertical; o.state &= ~QStyle::State_Horizontal; diff --git a/Source/WebCore/platform/text/BidiResolver.h b/Source/WebCore/platform/text/BidiResolver.h index 5b92ee2..c6efdd8 100644 --- a/Source/WebCore/platform/text/BidiResolver.h +++ b/Source/WebCore/platform/text/BidiResolver.h @@ -23,6 +23,7 @@ #define BidiResolver_h #include "BidiContext.h" +#include "BidiRunList.h" #include <wtf/Noncopyable.h> #include <wtf/PassRefPtr.h> #include <wtf/Vector.h> @@ -147,17 +148,15 @@ enum VisualDirectionOverride { VisualRightToLeftOverride }; +// BidiResolver is WebKit's implementation of the Unicode Bidi Algorithm +// http://unicode.org/reports/tr9 template <class Iterator, class Run> class BidiResolver { WTF_MAKE_NONCOPYABLE(BidiResolver); public: BidiResolver() : m_direction(WTF::Unicode::OtherNeutral) , m_reachedEndOfLine(false) - , emptyRun(true) - , m_firstRun(0) - , m_lastRun(0) - , m_logicallyLastRun(0) - , m_runCount(0) + , m_emptyRun(true) { } @@ -186,22 +185,16 @@ public: void createBidiRunsForLine(const Iterator& end, VisualDirectionOverride = NoVisualOverride, bool hardLineBreak = false); - Run* firstRun() const { return m_firstRun; } - Run* lastRun() const { return m_lastRun; } - Run* logicallyLastRun() const { return m_logicallyLastRun; } - unsigned runCount() const { return m_runCount; } + BidiRunList<Run>& runs() { return m_runs; } - void addRun(Run*); - void prependRun(Run*); - - void moveRunToEnd(Run*); - void moveRunToBeginning(Run*); - - void deleteRuns(); + // FIXME: This used to be part of deleteRuns() but was a layering violation. + // It's unclear if this is still needed. + void markCurrentRunEmpty() { m_emptyRun = true; } protected: + // FIXME: Instead of InlineBidiResolvers subclassing this method, we should + // pass in some sort of Traits object which knows how to create runs for appending. void appendRun(); - void reverseRuns(unsigned start, unsigned end); Iterator m_current; // sor and eor are "start of run" and "end of run" respectively and correpond @@ -213,13 +206,13 @@ protected: WTF::Unicode::Direction m_direction; Iterator endOfLine; bool m_reachedEndOfLine; - Iterator lastBeforeET; - bool emptyRun; + Iterator m_lastBeforeET; // Before a EuropeanNumberTerminator + bool m_emptyRun; + + // FIXME: This should not belong to the resolver, but rather be passed + // into createBidiRunsForLine by the caller. + BidiRunList<Run> m_runs; - Run* m_firstRun; - Run* m_lastRun; - Run* m_logicallyLastRun; - unsigned m_runCount; MidpointState<Iterator> m_midpointState; private: @@ -234,79 +227,9 @@ private: }; template <class Iterator, class Run> -inline void BidiResolver<Iterator, Run>::addRun(Run* run) -{ - if (!m_firstRun) - m_firstRun = run; - else - m_lastRun->m_next = run; - m_lastRun = run; - m_runCount++; -} - -template <class Iterator, class Run> -inline void BidiResolver<Iterator, Run>::prependRun(Run* run) -{ - ASSERT(!run->m_next); - - if (!m_lastRun) - m_lastRun = run; - else - run->m_next = m_firstRun; - m_firstRun = run; - m_runCount++; -} - -template <class Iterator, class Run> -inline void BidiResolver<Iterator, Run>::moveRunToEnd(Run* run) -{ - ASSERT(m_firstRun); - ASSERT(m_lastRun); - ASSERT(run->m_next); - - Run* current = 0; - Run* next = m_firstRun; - while (next != run) { - current = next; - next = current->next(); - } - - if (!current) - m_firstRun = run->next(); - else - current->m_next = run->m_next; - - run->m_next = 0; - m_lastRun->m_next = run; - m_lastRun = run; -} - -template <class Iterator, class Run> -inline void BidiResolver<Iterator, Run>::moveRunToBeginning(Run* run) -{ - ASSERT(m_firstRun); - ASSERT(m_lastRun); - ASSERT(run != m_firstRun); - - Run* current = m_firstRun; - Run* next = current->next(); - while (next != run) { - current = next; - next = current->next(); - } - - current->m_next = run->m_next; - if (run == m_lastRun) - m_lastRun = current; - - run->m_next = m_firstRun; - m_firstRun = run; -} - -template <class Iterator, class Run> void BidiResolver<Iterator, Run>::appendRun() { - if (!emptyRun && !m_eor.atEnd()) { + if (!m_emptyRun && !m_eor.atEnd()) { unsigned startOffset = m_sor.offset(); unsigned endOffset = m_eor.offset(); @@ -316,7 +239,7 @@ void BidiResolver<Iterator, Run>::appendRun() } if (endOffset >= startOffset) - addRun(new Run(startOffset, endOffset + 1, context(), m_direction)); + m_runs.addRun(new Run(startOffset, endOffset + 1, context(), m_direction)); m_eor.increment(); m_sor = m_eor; @@ -357,7 +280,7 @@ void BidiResolver<Iterator, Run>::lowerExplicitEmbeddingLevel(WTF::Unicode::Dire { using namespace WTF::Unicode; - if (!emptyRun && m_eor != m_last) { + if (!m_emptyRun && m_eor != m_last) { checkDirectionInLowerRaiseEmbeddingLevel(); // bidi.sor ... bidi.eor ... bidi.last eor; need to append the bidi.sor-bidi.eor run or extend it through bidi.last if (from == LeftToRight) { @@ -380,8 +303,10 @@ void BidiResolver<Iterator, Run>::lowerExplicitEmbeddingLevel(WTF::Unicode::Dire } m_eor = m_last; } + appendRun(); - emptyRun = true; + m_emptyRun = true; + // sor for the new run is determined by the higher level (rule X10) setLastDir(from); setLastStrongDir(from); @@ -393,7 +318,7 @@ void BidiResolver<Iterator, Run>::raiseExplicitEmbeddingLevel(WTF::Unicode::Dire { using namespace WTF::Unicode; - if (!emptyRun && m_eor != m_last) { + if (!m_emptyRun && m_eor != m_last) { checkDirectionInLowerRaiseEmbeddingLevel(); // bidi.sor ... bidi.eor ... bidi.last eor; need to append the bidi.sor-bidi.eor run or extend it through bidi.last if (to == LeftToRight) { @@ -418,8 +343,10 @@ void BidiResolver<Iterator, Run>::raiseExplicitEmbeddingLevel(WTF::Unicode::Dire } m_eor = m_last; } + appendRun(); - emptyRun = true; + m_emptyRun = true; + setLastDir(to); setLastStrongDir(to); m_eor = Iterator(); @@ -466,75 +393,6 @@ bool BidiResolver<Iterator, Run>::commitExplicitEmbedding() } template <class Iterator, class Run> -void BidiResolver<Iterator, Run>::deleteRuns() -{ - emptyRun = true; - if (!m_firstRun) - return; - - Run* curr = m_firstRun; - while (curr) { - Run* s = curr->next(); - curr->destroy(); - curr = s; - } - - m_firstRun = 0; - m_lastRun = 0; - m_runCount = 0; -} - -template <class Iterator, class Run> -void BidiResolver<Iterator, Run>::reverseRuns(unsigned start, unsigned end) -{ - if (start >= end) - return; - - ASSERT(end < m_runCount); - - // Get the item before the start of the runs to reverse and put it in - // |beforeStart|. |curr| should point to the first run to reverse. - Run* curr = m_firstRun; - Run* beforeStart = 0; - unsigned i = 0; - while (i < start) { - i++; - beforeStart = curr; - curr = curr->next(); - } - - Run* startRun = curr; - while (i < end) { - i++; - curr = curr->next(); - } - Run* endRun = curr; - Run* afterEnd = curr->next(); - - i = start; - curr = startRun; - Run* newNext = afterEnd; - while (i <= end) { - // Do the reversal. - Run* next = curr->next(); - curr->m_next = newNext; - newNext = curr; - curr = next; - i++; - } - - // Now hook up beforeStart and afterEnd to the startRun and endRun. - if (beforeStart) - beforeStart->m_next = endRun; - else - m_firstRun = endRun; - - startRun->m_next = afterEnd; - if (!afterEnd) - m_lastRun = startRun; -} - -template <class Iterator, class Run> inline void BidiResolver<Iterator, Run>::updateStatusLastFromCurrentDirection(WTF::Unicode::Direction dirCurrent) { using namespace WTF::Unicode; @@ -581,7 +439,7 @@ inline void BidiResolver<Iterator, Run>::reorderRunsFromLevels() { unsigned char levelLow = 128; unsigned char levelHigh = 0; - for (Run* run = firstRun(); run; run = run->next()) { + for (Run* run = m_runs.firstRun(); run; run = run->next()) { levelHigh = std::max(run->level(), levelHigh); levelLow = std::min(run->level(), levelLow); } @@ -595,11 +453,11 @@ inline void BidiResolver<Iterator, Run>::reorderRunsFromLevels() if (!(levelLow % 2)) levelLow++; - unsigned count = runCount() - 1; + unsigned count = m_runs.runCount() - 1; while (levelHigh >= levelLow) { unsigned i = 0; - Run* run = firstRun(); + Run* run = m_runs.firstRun(); while (i < count) { for (;i < count && run && run->level() < levelHigh; i++) run = run->next(); @@ -607,7 +465,7 @@ inline void BidiResolver<Iterator, Run>::reorderRunsFromLevels() for (;i <= count && run && run->level() >= levelHigh; i++) run = run->next(); unsigned end = i - 1; - reverseRuns(start, end); + m_runs.reverseRuns(start, end); } levelHigh--; } @@ -621,7 +479,7 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis ASSERT(m_direction == OtherNeutral); if (override != NoVisualOverride) { - emptyRun = false; + m_emptyRun = false; m_sor = m_current; m_eor = Iterator(); while (m_current != end && !m_current.atEnd()) { @@ -630,13 +488,13 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis } m_direction = override == VisualLeftToRightOverride ? LeftToRight : RightToLeft; appendRun(); - m_logicallyLastRun = m_lastRun; + m_runs.setLogicallyLastRun(m_runs.lastRun()); if (override == VisualRightToLeftOverride) - reverseRuns(0, runCount() - 1); + m_runs.reverseRuns(0, m_runs.runCount() - 1); return; } - emptyRun = true; + m_emptyRun = true; m_eor = Iterator(); @@ -818,7 +676,7 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis // Terminate the EN run. appendRun(); // Make an R run. - m_eor = m_status.last == EuropeanNumberTerminator ? lastBeforeET : m_last; + m_eor = m_status.last == EuropeanNumberTerminator ? m_lastBeforeET : m_last; m_direction = RightToLeft; appendRun(); // Begin a new EN run. @@ -829,7 +687,7 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis appendRun(); if (m_status.lastStrong == RightToLeft || context()->dir() == RightToLeft) { // Make an R run. - m_eor = m_status.last == EuropeanNumberTerminator ? lastBeforeET : m_last; + m_eor = m_status.last == EuropeanNumberTerminator ? m_lastBeforeET : m_last; m_direction = RightToLeft; appendRun(); // Begin a new EN run. @@ -837,7 +695,7 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis } } else if (m_status.lastStrong == RightToLeft) { // Extend the R run to include the neutrals. - m_eor = m_status.last == EuropeanNumberTerminator ? lastBeforeET : m_last; + m_eor = m_status.last == EuropeanNumberTerminator ? m_lastBeforeET : m_last; m_direction = RightToLeft; appendRun(); // Begin a new EN run. @@ -905,7 +763,7 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis m_eor = m_current; m_status.eor = dirCurrent; } else if (m_status.last != EuropeanNumberTerminator) - lastBeforeET = emptyRun ? m_eor : m_last; + m_lastBeforeET = m_emptyRun ? m_eor : m_last; break; // boundary neutrals should be ignored @@ -951,8 +809,8 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis m_eor = stateAtEnd.m_eor; m_last = stateAtEnd.m_last; m_reachedEndOfLine = stateAtEnd.m_reachedEndOfLine; - lastBeforeET = stateAtEnd.lastBeforeET; - emptyRun = stateAtEnd.emptyRun; + m_lastBeforeET = stateAtEnd.m_lastBeforeET; + m_emptyRun = stateAtEnd.m_emptyRun; m_direction = OtherNeutral; break; } @@ -960,9 +818,9 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis updateStatusLastFromCurrentDirection(dirCurrent); m_last = m_current; - if (emptyRun) { + if (m_emptyRun) { m_sor = m_current; - emptyRun = false; + m_emptyRun = false; } increment(); @@ -975,29 +833,29 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis m_eor = stateAtEnd.m_eor; m_last = stateAtEnd.m_last; m_reachedEndOfLine = stateAtEnd.m_reachedEndOfLine; - lastBeforeET = stateAtEnd.lastBeforeET; - emptyRun = stateAtEnd.emptyRun; + m_lastBeforeET = stateAtEnd.m_lastBeforeET; + m_emptyRun = stateAtEnd.m_emptyRun; m_direction = OtherNeutral; break; } } if (!pastEnd && (m_current == end || m_current.atEnd())) { - if (emptyRun) + if (m_emptyRun) break; stateAtEnd.m_status = m_status; stateAtEnd.m_sor = m_sor; stateAtEnd.m_eor = m_eor; stateAtEnd.m_last = m_last; stateAtEnd.m_reachedEndOfLine = m_reachedEndOfLine; - stateAtEnd.lastBeforeET = lastBeforeET; - stateAtEnd.emptyRun = emptyRun; + stateAtEnd.m_lastBeforeET = m_lastBeforeET; + stateAtEnd.m_emptyRun = m_emptyRun; endOfLine = m_last; pastEnd = true; } } - m_logicallyLastRun = m_lastRun; + m_runs.setLogicallyLastRun(m_runs.lastRun()); reorderRunsFromLevels(); endOfLine = Iterator(); } diff --git a/Source/WebCore/platform/text/BidiRunList.h b/Source/WebCore/platform/text/BidiRunList.h new file mode 100644 index 0000000..a4aa3c2 --- /dev/null +++ b/Source/WebCore/platform/text/BidiRunList.h @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * Copyright (C) 2003, 2004, 2006, 2007, 2008 Apple Inc. All right reserved. + * Copyright (C) 2011 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 + * 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 BidiRunList_h +#define BidiRunList_h + +#include <wtf/Noncopyable.h> + +namespace WebCore { + +template <class Run> +class BidiRunList { + WTF_MAKE_NONCOPYABLE(BidiRunList); +public: + BidiRunList() + : m_firstRun(0) + , m_lastRun(0) + , m_logicallyLastRun(0) + , m_runCount(0) + { + } + + // FIXME: Once BidiResolver no longer owns the BidiRunList, + // then ~BidiRunList should call deleteRuns() automatically. + + Run* firstRun() const { return m_firstRun; } + Run* lastRun() const { return m_lastRun; } + Run* logicallyLastRun() const { return m_logicallyLastRun; } + unsigned runCount() const { return m_runCount; } + + void addRun(Run*); + void prependRun(Run*); + + void moveRunToEnd(Run*); + void moveRunToBeginning(Run*); + + void deleteRuns(); + void reverseRuns(unsigned start, unsigned end); + void reorderRunsFromLevels(); + + void setLogicallyLastRun(Run* run) { m_logicallyLastRun = run; } + +private: + Run* m_firstRun; + Run* m_lastRun; + Run* m_logicallyLastRun; + unsigned m_runCount; +}; + +template <class Run> +inline void BidiRunList<Run>::addRun(Run* run) +{ + if (!m_firstRun) + m_firstRun = run; + else + m_lastRun->m_next = run; + m_lastRun = run; + m_runCount++; +} + +template <class Run> +inline void BidiRunList<Run>::prependRun(Run* run) +{ + ASSERT(!run->m_next); + + if (!m_lastRun) + m_lastRun = run; + else + run->m_next = m_firstRun; + m_firstRun = run; + m_runCount++; +} + +template <class Run> +inline void BidiRunList<Run>::moveRunToEnd(Run* run) +{ + ASSERT(m_firstRun); + ASSERT(m_lastRun); + ASSERT(run->m_next); + + Run* current = 0; + Run* next = m_firstRun; + while (next != run) { + current = next; + next = current->next(); + } + + if (!current) + m_firstRun = run->next(); + else + current->m_next = run->m_next; + + run->m_next = 0; + m_lastRun->m_next = run; + m_lastRun = run; +} + +template <class Run> +inline void BidiRunList<Run>::moveRunToBeginning(Run* run) +{ + ASSERT(m_firstRun); + ASSERT(m_lastRun); + ASSERT(run != m_firstRun); + + Run* current = m_firstRun; + Run* next = current->next(); + while (next != run) { + current = next; + next = current->next(); + } + + current->m_next = run->m_next; + if (run == m_lastRun) + m_lastRun = current; + + run->m_next = m_firstRun; + m_firstRun = run; +} + +template <class Run> +void BidiRunList<Run>::deleteRuns() +{ + if (!m_firstRun) + return; + + Run* curr = m_firstRun; + while (curr) { + Run* s = curr->next(); + curr->destroy(); + curr = s; + } + + m_firstRun = 0; + m_lastRun = 0; + m_runCount = 0; +} + +template <class Run> +void BidiRunList<Run>::reverseRuns(unsigned start, unsigned end) +{ + if (start >= end) + return; + + ASSERT(end < m_runCount); + + // Get the item before the start of the runs to reverse and put it in + // |beforeStart|. |curr| should point to the first run to reverse. + Run* curr = m_firstRun; + Run* beforeStart = 0; + unsigned i = 0; + while (i < start) { + i++; + beforeStart = curr; + curr = curr->next(); + } + + Run* startRun = curr; + while (i < end) { + i++; + curr = curr->next(); + } + Run* endRun = curr; + Run* afterEnd = curr->next(); + + i = start; + curr = startRun; + Run* newNext = afterEnd; + while (i <= end) { + // Do the reversal. + Run* next = curr->next(); + curr->m_next = newNext; + newNext = curr; + curr = next; + i++; + } + + // Now hook up beforeStart and afterEnd to the startRun and endRun. + if (beforeStart) + beforeStart->m_next = endRun; + else + m_firstRun = endRun; + + startRun->m_next = afterEnd; + if (!afterEnd) + m_lastRun = startRun; +} + +} // namespace WebCore + +#endif // BidiRunList diff --git a/Source/WebCore/platform/text/LocalizedNumberICU.cpp b/Source/WebCore/platform/text/LocalizedNumberICU.cpp index 7c4b1cb..da16262 100644 --- a/Source/WebCore/platform/text/LocalizedNumberICU.cpp +++ b/Source/WebCore/platform/text/LocalizedNumberICU.cpp @@ -37,6 +37,7 @@ #include <wtf/MathExtras.h> #include <wtf/PassOwnPtr.h> +using namespace icu; using namespace std; namespace WebCore { diff --git a/Source/WebCore/platform/text/StringWithDirection.h b/Source/WebCore/platform/text/StringWithDirection.h new file mode 100644 index 0000000..3302f81 --- /dev/null +++ b/Source/WebCore/platform/text/StringWithDirection.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef StringWithDirection_h +#define StringWithDirection_h + +#include "PlatformString.h" +#include "TextDirection.h" + +namespace WebCore { + +// In some circumstances we want to store a String along with the TextDirection +// of the String as learned from the context of the String. For example, +// consider storing the title derived from <title dir='rtl'>some title</title> +// in the history. +// +// Note that is explicitly *not* the direction of the string as learned +// from the characters of the string; it's extra metadata we have external +// to the string. +class StringWithDirection { +public: + StringWithDirection() + : m_direction(LTR) + { + } + + StringWithDirection(const String& string, TextDirection dir) + : m_string(string) + , m_direction(dir) + { + } + + const String& string() const { return m_string; } + TextDirection direction() const { return m_direction; } + + bool isEmpty() const { return m_string.isEmpty(); } + bool isNull() const { return m_string.isNull(); } + + bool operator==(const StringWithDirection& other) const + { + return other.m_string == m_string && other.m_direction == m_direction; + } + bool operator!=(const StringWithDirection& other) const { return !((*this) == other); } + +private: + String m_string; + TextDirection m_direction; +}; + +} + +#endif // StringWithDirection_h diff --git a/Source/WebCore/platform/text/TextCheckerClient.h b/Source/WebCore/platform/text/TextCheckerClient.h index 8abbed4..d16ade1 100644 --- a/Source/WebCore/platform/text/TextCheckerClient.h +++ b/Source/WebCore/platform/text/TextCheckerClient.h @@ -45,16 +45,6 @@ struct GrammarDetail { String userDescription; }; -enum TextCheckingType { - TextCheckingTypeSpelling = 1 << 1, - TextCheckingTypeGrammar = 1 << 2, - TextCheckingTypeLink = 1 << 5, - TextCheckingTypeQuote = 1 << 6, - TextCheckingTypeDash = 1 << 7, - TextCheckingTypeReplacement = 1 << 8, - TextCheckingTypeCorrection = 1 << 9 -}; - struct TextCheckingResult { TextCheckingType type; int location; @@ -72,15 +62,16 @@ public: virtual void checkSpellingOfString(const UChar*, int length, int* misspellingLocation, int* misspellingLength) = 0; virtual String getAutoCorrectSuggestionForMisspelledWord(const String& misspelledWord) = 0; virtual void checkGrammarOfString(const UChar*, int length, Vector<GrammarDetail>&, int* badGrammarLocation, int* badGrammarLength) = 0; + #if USE(UNIFIED_TEXT_CHECKING) - virtual void checkTextOfParagraph(const UChar* text, int length, uint64_t checkingTypes, Vector<TextCheckingResult>& results) = 0; + virtual void checkTextOfParagraph(const UChar* text, int length, TextCheckingTypeMask checkingTypes, Vector<TextCheckingResult>& results) = 0; #endif // For spellcheckers that support multiple languages, it's often important to be able to identify the language in order to // provide more accurate correction suggestions. Caller can pass in more text in "context" to aid such spellcheckers on language // identification. Noramlly it's the text surrounding the "word" for which we are getting correction suggestions. virtual void getGuessesForWord(const String& word, const String& context, Vector<String>& guesses) = 0; - virtual void requestCheckingOfString(SpellChecker*, int, const String&) = 0; + virtual void requestCheckingOfString(SpellChecker*, int, TextCheckingTypeMask, const String&) = 0; }; } diff --git a/Source/WebCore/platform/text/TextChecking.h b/Source/WebCore/platform/text/TextChecking.h index 022fb82..d2040d5 100644 --- a/Source/WebCore/platform/text/TextChecking.h +++ b/Source/WebCore/platform/text/TextChecking.h @@ -42,6 +42,18 @@ namespace WebCore { #define WTF_USE_AUTOMATIC_TEXT_REPLACEMENT 1 #endif +enum TextCheckingType { + TextCheckingTypeSpelling = 1 << 1, + TextCheckingTypeGrammar = 1 << 2, + TextCheckingTypeLink = 1 << 5, + TextCheckingTypeQuote = 1 << 6, + TextCheckingTypeDash = 1 << 7, + TextCheckingTypeReplacement = 1 << 8, + TextCheckingTypeCorrection = 1 << 9 +}; + +typedef unsigned TextCheckingTypeMask; + } #endif // TextChecking_h diff --git a/Source/WebCore/platform/text/UnicodeBidi.h b/Source/WebCore/platform/text/UnicodeBidi.h new file mode 100644 index 0000000..8e0d86e --- /dev/null +++ b/Source/WebCore/platform/text/UnicodeBidi.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2011 Google, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 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 UnicodeBidi_h +#define UnicodeBidi_h + +namespace WebCore { + +enum EUnicodeBidi { + UBNormal, + Embed, + Override, + Isolate +}; + +} + +#endif diff --git a/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp b/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp index 33d8ccd..7bd97d6 100644 --- a/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp +++ b/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp @@ -444,7 +444,7 @@ String getURL(const DragDataMap* data, DragData::FilenameConversionPolicy filena if (stringData.isEmpty() || (!PathFileExists(stringData.charactersWithNullTermination()) && !PathIsUNC(stringData.charactersWithNullTermination()))) return url; - RetainPtr<CFStringRef> pathAsCFString(AdoptCF, CFStringCreateWithCharacters(kCFAllocatorDefault, (const UniChar *)stringData.charactersWithNullTermination(), stringData.length())); + RetainPtr<CFStringRef> pathAsCFString(AdoptCF, CFStringCreateWithCharacters(kCFAllocatorDefault, (const UniChar *)stringData.charactersWithNullTermination(), wcslen(stringData.charactersWithNullTermination()))); if (urlFromPath(pathAsCFString.get(), url) && title) *title = url; #endif diff --git a/Source/WebCore/platform/win/ClipboardWin.cpp b/Source/WebCore/platform/win/ClipboardWin.cpp index 791ec86..0b5a3d3 100644 --- a/Source/WebCore/platform/win/ClipboardWin.cpp +++ b/Source/WebCore/platform/win/ClipboardWin.cpp @@ -703,7 +703,6 @@ void ClipboardWin::declareAndWriteDragImage(Element* element, const KURL& url, c return; STGMEDIUM medium = {0}; medium.tymed = TYMED_HGLOBAL; - ExceptionCode ec = 0; // Put img tag on the clipboard referencing the image Vector<char> data; @@ -791,7 +790,6 @@ void ClipboardWin::writePlainText(const String& text) STGMEDIUM medium = {0}; medium.tymed = TYMED_HGLOBAL; - ExceptionCode ec = 0; String str = text; replaceNewlinesWithWindowsStyleNewlines(str); diff --git a/Source/WebCore/platform/win/DragImageCairoWin.cpp b/Source/WebCore/platform/win/DragImageCairoWin.cpp index e356575..a67a82c 100644 --- a/Source/WebCore/platform/win/DragImageCairoWin.cpp +++ b/Source/WebCore/platform/win/DragImageCairoWin.cpp @@ -29,26 +29,20 @@ #include "BitmapInfo.h" #include "CachedImage.h" #include "GraphicsContext.h" +#include "GraphicsContextPlatformPrivateCairo.h" #include "Image.h" #include "RetainPtr.h" - #include <cairo-win32.h> -#include "GraphicsContextPlatformPrivateCairo.h" - #include <windows.h> -extern "C" { -typedef struct _cairo* CairoContextRef; -} - namespace WebCore { -void deallocContext(CairoContextRef target) +void deallocContext(PlatformContextCairo* target) { - cairo_destroy(target); + delete target; } -HBITMAP allocImage(HDC dc, IntSize size, CairoContextRef* targetRef) +HBITMAP allocImage(HDC dc, IntSize size, PlatformContextCairo** targetRef) { BitmapInfo bmpInfo = BitmapInfo::create(size); @@ -72,8 +66,8 @@ HBITMAP allocImage(HDC dc, IntSize size, CairoContextRef* targetRef) return 0; } - *targetRef = cairo_create (bitmapContext); - cairo_surface_destroy (bitmapContext); + cairo_t* cr = cairo_create(bitmapContext); + cairo_surface_destroy(bitmapContext); // At this point, we have a Cairo surface that points to a Windows DIB. The DIB interprets // with the opposite meaning of positive Y axis, so everything we draw into this cairo @@ -83,7 +77,10 @@ HBITMAP allocImage(HDC dc, IntSize size, CairoContextRef* targetRef) // before they get written to the internal buffer. cairo_matrix_t matrix; cairo_matrix_init(&matrix, 1.0, 0.0, 0.0, -1.0, 0.0, size.height()); - cairo_set_matrix(*targetRef, &matrix); + cairo_set_matrix(cr, &matrix); + + *targetRef = new PlatformGraphicsContext(cr); + cairo_destroy(cr); return hbmp; } @@ -121,7 +118,7 @@ DragImageRef scaleDragImage(DragImageRef image, FloatSize scale) if (!dstDC) goto exit; - CairoContextRef targetContext; + PlatformContextCairo* targetContext; hbmp = allocImage(dstDC, dstSize, &targetContext); if (!hbmp) goto exit; @@ -131,15 +128,16 @@ DragImageRef scaleDragImage(DragImageRef image, FloatSize scale) // 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(targetContext, 0, dstSize.height()); - cairo_scale(targetContext, scale.width(), -scale.height()); - cairo_set_source_surface (targetContext, srcImage, 0.0, 0.0); + cairo_t* cr = targetContext->cr(); + cairo_translate(cr, 0, dstSize.height()); + cairo_scale(cr, scale.width(), -scale.height()); + cairo_set_source_surface(cr, srcImage, 0.0, 0.0); // Now we can paint and get the correct result - cairo_paint(targetContext); + cairo_paint(cr); - cairo_surface_destroy (srcImage); - cairo_destroy(targetContext); + cairo_surface_destroy(srcImage); + deallocContext(targetContext); ::DeleteObject(image); image = 0; @@ -160,7 +158,7 @@ DragImageRef createDragImageFromImage(Image* img) if (!workingDC) goto exit; - CairoContextRef drawContext = 0; + PlatformContextCairo* drawContext = 0; hbmp = allocImage(workingDC, img->size(), &drawContext); if (!hbmp) goto exit; @@ -170,16 +168,17 @@ DragImageRef createDragImageFromImage(Image* img) hbmp = 0; } - cairo_set_source_rgb (drawContext, 1.0, 0.0, 1.0); - cairo_fill_preserve (drawContext); + cairo_t* cr = drawContext->cr(); + cairo_set_source_rgb(cr, 1.0, 0.0, 1.0); + cairo_fill_preserve(cr); cairo_surface_t* srcImage = img->nativeImageForCurrentFrame(); // Draw the image. - cairo_set_source_surface(drawContext, srcImage, 0.0, 0.0); - cairo_paint(drawContext); + cairo_set_source_surface(cr, srcImage, 0.0, 0.0); + cairo_paint(cr); - cairo_destroy (drawContext); + deallocContext(drawContext); exit: if (workingDC) diff --git a/Source/WebCore/platform/win/FileSystemWin.cpp b/Source/WebCore/platform/win/FileSystemWin.cpp index 03a2eaf..7d1c8f2 100644 --- a/Source/WebCore/platform/win/FileSystemWin.cpp +++ b/Source/WebCore/platform/win/FileSystemWin.cpp @@ -136,7 +136,12 @@ String pathGetFileName(const String& path) String directoryName(const String& path) { - return path.left(path.length() - pathGetFileName(path).length()); + String name = path.left(path.length() - pathGetFileName(path).length()); + if (name.characterStartingAt(name.length() - 1) == '\\') { + // Remove any trailing "\". + name.truncate(name.length() - 1); + } + return name; } static String bundleName() @@ -241,9 +246,11 @@ PlatformFileHandle openFile(const String& path, FileOpenMode mode) case OpenForRead: desiredAccess = GENERIC_READ; creationDisposition = OPEN_EXISTING; + break; case OpenForWrite: desiredAccess = GENERIC_WRITE; creationDisposition = CREATE_ALWAYS; + break; default: ASSERT_NOT_REACHED(); } diff --git a/Source/WebCore/platform/win/LocalizedStringsWin.cpp b/Source/WebCore/platform/win/LocalizedStringsWin.cpp index 67de0fc..c079441 100644 --- a/Source/WebCore/platform/win/LocalizedStringsWin.cpp +++ b/Source/WebCore/platform/win/LocalizedStringsWin.cpp @@ -26,14 +26,66 @@ #include "config.h" #include "LocalizedStrings.h" +#include "WebCoreInstanceHandle.h" +#include <wtf/Assertions.h> +#include <wtf/StdLibExtras.h> +#include <wtf/Threading.h> #include <wtf/text/WTFString.h> +#if USE(CF) +#include <CoreFoundation/CFBundle.h> +#include <wtf/RetainPtr.h> +#endif + namespace WebCore { +#if USE(CF) + +static CFBundleRef createWebKitBundle() +{ + if (CFBundleRef existingBundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.WebKit"))) { + CFRetain(existingBundle); + return existingBundle; + } + + wchar_t dllPathBuffer[MAX_PATH]; + DWORD length = ::GetModuleFileNameW(instanceHandle(), dllPathBuffer, WTF_ARRAY_LENGTH(dllPathBuffer)); + ASSERT(length); + ASSERT(length < WTF_ARRAY_LENGTH(dllPathBuffer)); + + RetainPtr<CFStringRef> dllPath(AdoptCF, CFStringCreateWithCharactersNoCopy(0, reinterpret_cast<const UniChar*>(dllPathBuffer), length, kCFAllocatorNull)); + RetainPtr<CFURLRef> dllURL(AdoptCF, CFURLCreateWithFileSystemPath(0, dllPath.get(), kCFURLWindowsPathStyle, false)); + RetainPtr<CFURLRef> dllDirectoryURL(AdoptCF, CFURLCreateCopyDeletingLastPathComponent(0, dllURL.get())); + RetainPtr<CFURLRef> resourcesDirectoryURL(AdoptCF, CFURLCreateCopyAppendingPathComponent(0, dllDirectoryURL.get(), CFSTR("WebKit.resources"), true)); + + return CFBundleCreate(0, resourcesDirectoryURL.get()); +} + +static CFBundleRef webKitBundle() +{ + static CFBundleRef bundle = createWebKitBundle(); + ASSERT(bundle); + return bundle; +} + +#endif // USE(CF) + String localizedString(const char* key) { - // FIXME: <rdar://problem/9119405> Win: WebKit2 needs to be made localizable + ASSERT(isMainThread()); + +#if USE(CF) + static CFStringRef notFound = CFSTR("localized string not found"); + + RetainPtr<CFStringRef> keyString(AdoptCF, CFStringCreateWithCStringNoCopy(NULL, key, kCFStringEncodingUTF8, kCFAllocatorNull)); + RetainPtr<CFStringRef> result(AdoptCF, CFCopyLocalizedStringWithDefaultValue(keyString.get(), 0, webKitBundle(), notFound, 0)); + ASSERT_WITH_MESSAGE(result.get() != notFound, "could not find localizable string %s in bundle", key); + + return result.get(); +#else + // FIXME: Implement localizedString() for !USE(CF). return String::fromUTF8(key, strlen(key)); +#endif } } // namespace WebCore diff --git a/Source/WebCore/platform/win/LoggingWin.cpp b/Source/WebCore/platform/win/LoggingWin.cpp index 1d051ae..5e9fbda 100644 --- a/Source/WebCore/platform/win/LoggingWin.cpp +++ b/Source/WebCore/platform/win/LoggingWin.cpp @@ -88,6 +88,7 @@ void InitializeLoggingChannelsIfNecessary() initializeWithUserDefault(LogHistory); initializeWithUserDefault(LogPageCache); initializeWithUserDefault(LogPlatformLeaks); + initializeWithUserDefault(LogResourceLoading); initializeWithUserDefault(LogNetwork); initializeWithUserDefault(LogFTP); initializeWithUserDefault(LogThreading); @@ -95,6 +96,8 @@ void InitializeLoggingChannelsIfNecessary() initializeWithUserDefault(LogMedia); initializeWithUserDefault(LogPlugins); initializeWithUserDefault(LogArchives); + initializeWithUserDefault(LogProgress); + initializeWithUserDefault(LogFileAPI); } } // namespace WebCore diff --git a/Source/WebCore/platform/win/PopupMenuWin.h b/Source/WebCore/platform/win/PopupMenuWin.h index 05edb07..0684424 100644 --- a/Source/WebCore/platform/win/PopupMenuWin.h +++ b/Source/WebCore/platform/win/PopupMenuWin.h @@ -95,8 +95,10 @@ private: virtual int scrollPosition(Scrollbar*) const; virtual void setScrollOffset(const IntPoint&); virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&); + virtual void invalidateScrollCornerRect(const WebCore::IntRect&) { } virtual bool isActive() const { return true; } - virtual bool scrollbarCornerPresent() const { return false; } + virtual bool isScrollCornerVisible() const { return false; } + virtual WebCore::IntRect scrollCornerRect() const { return WebCore::IntRect(); } virtual Scrollbar* verticalScrollbar() const { return m_scrollbar.get(); } // NOTE: This should only be called by the overriden setScrollOffset from ScrollableArea. diff --git a/Source/WebCore/platform/win/WindowsTouch.h b/Source/WebCore/platform/win/WindowsTouch.h new file mode 100644 index 0000000..9048103 --- /dev/null +++ b/Source/WebCore/platform/win/WindowsTouch.h @@ -0,0 +1,112 @@ +/* + * 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 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 WindowsTouch_h +#define WindowsTouch_h + +/* + * The following constants are used to determine multitouch and gesture behavior + * for Windows 7. For more information, see: + * http://msdn.microsoft.com/en-us/library/dd562197(VS.85).aspx + */ + +// Value used in WebViewWndProc for Gestures +#define WM_GESTURE 0x0119 +#define WM_GESTURENOTIFY 0x011A + +// Gesture Information Flags +#define GF_BEGIN 0x00000001 +#define GF_INERTIA 0x00000002 +#define GF_END 0x00000004 + +// Gesture IDs +#define GID_BEGIN 1 +#define GID_END 2 +#define GID_ZOOM 3 +#define GID_PAN 4 +#define GID_ROTATE 5 +#define GID_TWOFINGERTAP 6 +#define GID_PRESSANDTAP 7 +#define GID_ROLLOVER GID_PRESSANDTAP + +// Zoom Gesture Confiration Flags +#define GC_ZOOM 0x00000001 + +// Pan Gesture Configuration Flags +#define GC_PAN 0x00000001 +#define GC_PAN_WITH_SINGLE_FINGER_VERTICALLY 0x00000002 +#define GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY 0x00000004 +#define GC_PAN_WITH_GUTTER 0x00000008 +#define GC_PAN_WITH_INERTIA 0x00000010 + +// Rotate Gesture Configuration Flags +#define GC_ROTATE 0x00000001 + +// Two finger tap configuration flags +#define GC_TWOFINGERTAP 0x00000001 + +// Press and tap Configuration Flags +#define GC_PRESSANDTAP 0x00000001 +#define GC_ROLLOVER GC_PRESSANDTAP + +// GESTUREINFO struct definition +typedef struct tagGESTUREINFO { + UINT cbSize; // size, in bytes, of this structure (including variable length Args field) + DWORD dwFlags; // see GF_* flags + DWORD dwID; // gesture ID, see GID_* defines + HWND hwndTarget; // handle to window targeted by this gesture + POINTS ptsLocation; // current location of this gesture + DWORD dwInstanceID; // internally used + DWORD dwSequenceID; // internally used + ULONGLONG ullArguments; // arguments for gestures whose arguments fit in 8 BYTES + UINT cbExtraArgs; // size, in bytes, of extra arguments, if any, that accompany this gesture +} GESTUREINFO, *PGESTUREINFO; +typedef GESTUREINFO const * PCGESTUREINFO; + +// GESTURECONFIG struct defintion +typedef struct tagGESTURECONFIG { + DWORD dwID; // gesture ID + DWORD dwWant; // settings related to gesture ID that are to be turned on + DWORD dwBlock; // settings related to gesture ID that are to be turned off +} GESTURECONFIG, *PGESTURECONFIG; + +/* + * Gesture notification structure + * - The WM_GESTURENOTIFY message lParam contains a pointer to this structure. + * - The WM_GESTURENOTIFY message notifies a window that gesture recognition is + * in progress and a gesture will be generated if one is recognized under the + * current gesture settings. + */ +typedef struct tagGESTURENOTIFYSTRUCT { + UINT cbSize; // size, in bytes, of this structure + DWORD dwFlags; // unused + HWND hwndTarget; // handle to window targeted by the gesture + POINTS ptsLocation; // starting location + DWORD dwInstanceID; // internally used +} GESTURENOTIFYSTRUCT, *PGESTURENOTIFYSTRUCT; + +DECLARE_HANDLE(HGESTUREINFO); + +#endif diff --git a/Source/WebCore/platform/wx/FileSystemWx.cpp b/Source/WebCore/platform/wx/FileSystemWx.cpp index 3c2b453..3644a42 100644 --- a/Source/WebCore/platform/wx/FileSystemWx.cpp +++ b/Source/WebCore/platform/wx/FileSystemWx.cpp @@ -78,8 +78,11 @@ bool getFileSize(const String& path, long long& resultSize) bool getFileModificationTime(const String& path, time_t& t) { - t = wxFileName(path).GetModificationTime().GetTicks(); - return true; + if (wxFileExists(path)) { + t = wxFileName(path).GetModificationTime().GetTicks(); + return true; + } + return false; } bool makeAllDirectories(const String& path) @@ -107,22 +110,26 @@ String directoryName(const String& path) return wxFileName(path).GetPath(); } -String openTemporaryFile(const String&, PlatformFileHandle& handle) +String openTemporaryFile(const String& prefix, PlatformFileHandle& handle) { - notImplemented(); - handle = invalidPlatformFileHandle; - return String(); + wxString sFilename = wxFileName::CreateTempFileName(prefix); + wxFile* temp = new wxFile(); + temp->Open(sFilename.c_str(), wxFile::read_write); + handle = temp; + return String(sFilename); } -void closeFile(PlatformFileHandle&) +void closeFile(PlatformFileHandle& handle) { - notImplemented(); + if (handle) + delete handle; } -int writeToFile(PlatformFileHandle, const char* data, int length) +int writeToFile(PlatformFileHandle handle, const char* data, int length) { - notImplemented(); - return 0; + if (handle) + return static_cast<wxFile*>(handle)->Write(data, length); + return -1; } bool unloadModule(PlatformModule mod) diff --git a/Source/WebCore/platform/wx/WidgetWx.cpp b/Source/WebCore/platform/wx/WidgetWx.cpp index 9de4c3d..e9a3c98 100644 --- a/Source/WebCore/platform/wx/WidgetWx.cpp +++ b/Source/WebCore/platform/wx/WidgetWx.cpp @@ -27,8 +27,10 @@ #include "Cursor.h" #include "GraphicsContext.h" +#include "HostWindow.h" #include "IntRect.h" #include "NotImplemented.h" +#include "ScrollView.h" #include <wx/defs.h> #include <wx/scrolwin.h> @@ -54,8 +56,10 @@ void Widget::setFocus(bool focused) void Widget::setCursor(const Cursor& cursor) { - if (platformWidget() && cursor.impl()) - platformWidget()->SetCursor(*cursor.impl()); + ScrollView* view = root(); + if (!view) + return; + view->hostWindow()->setCursor(cursor); } void Widget::show() |