diff options
Diffstat (limited to 'Source/WebCore/platform')
380 files changed, 12820 insertions, 3576 deletions
diff --git a/Source/WebCore/platform/ColorData.gperf b/Source/WebCore/platform/ColorData.gperf index 2a72237..277d83e 100644 --- a/Source/WebCore/platform/ColorData.gperf +++ b/Source/WebCore/platform/ColorData.gperf @@ -107,7 +107,7 @@ maroon, 0xff800000 mediumaquamarine, 0xff66cdaa mediumblue, 0xff0000cd mediumorchid, 0xffba55d3 -mediumpurple, 0xff9370d8 +mediumpurple, 0xff9370db mediumseagreen, 0xff3cb371 mediumslateblue, 0xff7b68ee mediumspringgreen, 0xff00fa9a @@ -128,7 +128,7 @@ orchid, 0xffda70d6 palegoldenrod, 0xffeee8aa palegreen, 0xff98fb98 paleturquoise, 0xffafeeee -palevioletred, 0xffd87093 +palevioletred, 0xffdb7093 papayawhip, 0xffffefd5 peachpuff, 0xffffdab9 peru, 0xffcd853f diff --git a/Source/WebCore/platform/CrossThreadCopier.h b/Source/WebCore/platform/CrossThreadCopier.h index 5eb40ee..a25d6fa 100644 --- a/Source/WebCore/platform/CrossThreadCopier.h +++ b/Source/WebCore/platform/CrossThreadCopier.h @@ -56,7 +56,7 @@ namespace WebCore { } }; - template<bool isConvertibleToInteger, bool isThreadsafeShared, typename T> struct CrossThreadCopierBase; + template<bool isConvertibleToInteger, bool isThreadSafeRefCounted, typename T> struct CrossThreadCopierBase; // Integers get passed through without any changes. template<typename T> struct CrossThreadCopierBase<true, false, T> : public CrossThreadCopierPassThrough<T> { @@ -114,8 +114,8 @@ namespace WebCore { }; template<typename T> struct CrossThreadCopier : public CrossThreadCopierBase<WTF::IsConvertibleToInteger<T>::value, - WTF::IsSubclassOfTemplate<typename WTF::RemoveTemplate<T, RefPtr>::Type, ThreadSafeShared>::value - || WTF::IsSubclassOfTemplate<typename WTF::RemoveTemplate<T, PassRefPtr>::Type, ThreadSafeShared>::value, + WTF::IsSubclassOfTemplate<typename WTF::RemoveTemplate<T, RefPtr>::Type, ThreadSafeRefCounted>::value + || WTF::IsSubclassOfTemplate<typename WTF::RemoveTemplate<T, PassRefPtr>::Type, ThreadSafeRefCounted>::value, T> { }; diff --git a/Source/WebCore/platform/DefaultLocalizationStrategy.cpp b/Source/WebCore/platform/DefaultLocalizationStrategy.cpp new file mode 100644 index 0000000..1a50c3c --- /dev/null +++ b/Source/WebCore/platform/DefaultLocalizationStrategy.cpp @@ -0,0 +1,874 @@ +/* + * Copyright (C) 2010, 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 "DefaultLocalizationStrategy.h" + +#if USE(PLATFORM_STRATEGIES) + +#include "IntSize.h" +#include "LocalizedStrings.h" +#include "NotImplemented.h" +#include <wtf/MathExtras.h> +#include <wtf/text/CString.h> +#include <wtf/UnusedParam.h> + +#if USE(CF) +#include <wtf/RetainPtr.h> +#endif + +namespace WebCore { + +// We can't use String::format for two reasons: +// 1) It doesn't handle non-ASCII characters in the format string. +// 2) It doesn't handle the %2$d syntax. +// Note that because |format| is used as the second parameter to va_start, it cannot be a reference +// type according to section 18.7/3 of the C++ N1905 standard. +static String formatLocalizedString(String format, ...) +{ +#if USE(CF) + va_list arguments; + va_start(arguments, format); + RetainPtr<CFStringRef> formatCFString(AdoptCF, format.createCFString()); + RetainPtr<CFStringRef> result(AdoptCF, CFStringCreateWithFormatAndArguments(0, 0, formatCFString.get(), arguments)); + va_end(arguments); + return result.get(); +#elif PLATFORM(QT) + va_list arguments; + va_start(arguments, format); + QString result; + result.vsprintf(format.latin1().data(), arguments); + va_end(arguments); + return result; +#else + notImplemented(); + return format; +#endif +} + +DefaultLocalizationStrategy::DefaultLocalizationStrategy() +{ +} + +String DefaultLocalizationStrategy::inputElementAltText() +{ + return 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"); +} + +String DefaultLocalizationStrategy::searchableIndexIntroduction() +{ + return 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"); +} + +String DefaultLocalizationStrategy::fileButtonChooseFileLabel() +{ + return 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"); +} + +String DefaultLocalizationStrategy::defaultDetailsSummaryText() +{ + return 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"); +} +#endif + +#if ENABLE(CONTEXT_MENUS) + +String DefaultLocalizationStrategy::contextMenuItemTagOpenLinkInNewWindow() +{ + return 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"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagCopyLinkToClipboard() +{ + return 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"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagDownloadImageToDisk() +{ + return UI_STRING("Download Image", "Download Image context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagCopyImageToClipboard() +{ + return 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"); +} +#endif + +String DefaultLocalizationStrategy::contextMenuItemTagOpenVideoInNewWindow() +{ + return 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"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagCopyVideoLinkToClipboard() +{ + return 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"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagToggleMediaControls() +{ + return UI_STRING("Controls", "Media Controls context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagToggleMediaLoop() +{ + return UI_STRING("Loop", "Media Loop context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagEnterVideoFullscreen() +{ + return UI_STRING("Enter Fullscreen", "Video Enter Fullscreen context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagMediaPlay() +{ + return UI_STRING("Play", "Media Play context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagMediaPause() +{ + return UI_STRING("Pause", "Media Pause context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagMediaMute() +{ + return 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"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagCopy() +{ + return UI_STRING("Copy", "Copy context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagGoBack() +{ + return UI_STRING("Back", "Back context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagGoForward() +{ + return UI_STRING("Forward", "Forward context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagStop() +{ + return UI_STRING("Stop", "Stop context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagReload() +{ + return UI_STRING("Reload", "Reload context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagCut() +{ + return UI_STRING("Cut", "Cut context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagPaste() +{ + return UI_STRING("Paste", "Paste context menu item"); +} + +#if PLATFORM(GTK) + +String DefaultLocalizationStrategy::contextMenuItemTagDelete() +{ + notImplemented(); + return "Delete"; +} + +String DefaultLocalizationStrategy::contextMenuItemTagInputMethods() +{ + notImplemented(); + return "Input Methods"; +} + +String DefaultLocalizationStrategy::contextMenuItemTagUnicode() +{ + notImplemented(); + return "Unicode"; +} + +#endif + +#if PLATFORM(GTK) || PLATFORM(QT) + +String DefaultLocalizationStrategy::contextMenuItemTagSelectAll() +{ + notImplemented(); + return "Select All"; +} + +#endif + +String DefaultLocalizationStrategy::contextMenuItemTagNoGuessesFound() +{ + return UI_STRING("No Guesses Found", "No Guesses Found context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagIgnoreSpelling() +{ + return UI_STRING("Ignore Spelling", "Ignore Spelling context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagLearnSpelling() +{ + return UI_STRING("Learn Spelling", "Learn Spelling context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagSearchWeb() +{ + return 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"); +#else + return UI_STRING("Look Up “<selection>”", "Look Up context menu item with selected word").replace("<selection>", selectedString); +#endif +} + +String DefaultLocalizationStrategy::contextMenuItemTagOpenLink() +{ + return UI_STRING("Open Link", "Open Link context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagIgnoreGrammar() +{ + return 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"); +} + +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"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagCheckSpelling() +{ + return 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"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagCheckGrammarWithSpelling() +{ + return 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"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagBold() +{ + return UI_STRING("Bold", "Bold context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagItalic() +{ + return UI_STRING("Italic", "Italic context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagUnderline() +{ + return UI_STRING("Underline", "Underline context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagOutline() +{ + return UI_STRING("Outline", "Outline context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagWritingDirectionMenu() +{ + return UI_STRING("Paragraph Direction", "Paragraph direction context sub-menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagTextDirectionMenu() +{ + return UI_STRING("Selection Direction", "Selection direction context sub-menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagDefaultDirection() +{ + return UI_STRING("Default", "Default writing direction context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagLeftToRight() +{ + return 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"); +} + +#if PLATFORM(MAC) + +String DefaultLocalizationStrategy::contextMenuItemTagSearchInSpotlight() +{ + return UI_STRING("Search in Spotlight", "Search in Spotlight context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagShowFonts() +{ + return UI_STRING("Show Fonts", "Show fonts context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagStyles() +{ + return UI_STRING("Styles...", "Styles context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagShowColors() +{ + return UI_STRING("Show Colors", "Show colors context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagSpeechMenu() +{ + return UI_STRING("Speech", "Speech context sub-menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagStartSpeaking() +{ + return UI_STRING("Start Speaking", "Start speaking context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagStopSpeaking() +{ + return UI_STRING("Stop Speaking", "Stop speaking context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagCorrectSpellingAutomatically() +{ + return UI_STRING("Correct Spelling Automatically", "Correct Spelling Automatically context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagSubstitutionsMenu() +{ + return 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"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagSmartCopyPaste() +{ + return UI_STRING("Smart Copy/Paste", "Smart Copy/Paste context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagSmartQuotes() +{ + return UI_STRING("Smart Quotes", "Smart Quotes context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagSmartDashes() +{ + return UI_STRING("Smart Dashes", "Smart Dashes context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagSmartLinks() +{ + return UI_STRING("Smart Links", "Smart Links context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagTextReplacement() +{ + return UI_STRING("Text Replacement", "Text Replacement context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagTransformationsMenu() +{ + return UI_STRING("Transformations", "Transformations context sub-menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagMakeUpperCase() +{ + return 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"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagCapitalize() +{ + return UI_STRING("Capitalize", "Capitalize context menu item"); +} + +String DefaultLocalizationStrategy::contextMenuItemTagChangeBack(const String& replacedString) +{ + notImplemented(); + return replacedString; +} + +#endif + +String DefaultLocalizationStrategy::contextMenuItemTagInspectElement() +{ + return 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"); +} + +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"); +} + +String DefaultLocalizationStrategy::searchMenuClearRecentSearchesText() +{ + return 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"); +} + +String DefaultLocalizationStrategy::AXLinkText() +{ + return UI_STRING("link", "accessibility role description for link"); +} + +String DefaultLocalizationStrategy::AXListMarkerText() +{ + return UI_STRING("list marker", "accessibility role description for list marker"); +} + +String DefaultLocalizationStrategy::AXImageMapText() +{ + return UI_STRING("image map", "accessibility role description for image map"); +} + +String DefaultLocalizationStrategy::AXHeadingText() +{ + return UI_STRING("heading", "accessibility role description for headings"); +} + +String DefaultLocalizationStrategy::AXDefinitionListTermText() +{ + return UI_STRING("term", "term word of a definition"); +} + +String DefaultLocalizationStrategy::AXDefinitionListDefinitionText() +{ + return 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."); + if (ariaType == "ARIAApplicationAlertDialog") + return 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."); + if (ariaType == "ARIAApplicationLog") + return 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."); + if (ariaType == "ARIAApplicationStatus") + return 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."); + if (ariaType == "ARIADocument") + return 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."); + if (ariaType == "ARIADocumentNote") + return 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."); + if (ariaType == "ARIALandmarkApplication") + return 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."); + if (ariaType == "ARIALandmarkComplementary") + return 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."); + if (ariaType == "ARIALandmarkMain") + return 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."); + if (ariaType == "ARIALandmarkSearch") + return 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."); + if (ariaType == "ARIATabPanel") + return 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 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"); +} + +String DefaultLocalizationStrategy::AXRadioButtonActionVerb() +{ + return 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"); +} + +String DefaultLocalizationStrategy::AXCheckedCheckBoxActionVerb() +{ + return 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"); +} + +String DefaultLocalizationStrategy::AXMenuListActionVerb() +{ + notImplemented(); + return "select"; +} + +String DefaultLocalizationStrategy::AXMenuListPopupActionVerb() +{ + notImplemented(); + return "select"; +} + +String DefaultLocalizationStrategy::AXLinkActionVerb() +{ + return 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"); +} + +String DefaultLocalizationStrategy::crashedPluginText() +{ + return 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); +} + +String DefaultLocalizationStrategy::unknownFileSizeText() +{ + return UI_STRING("Unknown", "Unknown filesize FTP directory listing item"); +} + +#if PLATFORM(WIN) + +String DefaultLocalizationStrategy::uploadFileText() +{ + notImplemented(); + return "upload"; +} + +String DefaultLocalizationStrategy::allFilesText() +{ + notImplemented(); + return "all files"; +} + +#endif + +#if PLATFORM(MAC) + +String DefaultLocalizationStrategy::keygenMenuItem512() +{ + return 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"); +} + +String DefaultLocalizationStrategy::keygenMenuItem2048() +{ + return 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); +} + +#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); +} + +String DefaultLocalizationStrategy::mediaElementLoadingStateText() +{ + return 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"); +} + +String DefaultLocalizationStrategy::localizedMediaControlElementString(const String& name) +{ + if (name == "AudioElement") + return 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"); + if (name == "MuteButton") + return UI_STRING("mute", "accessibility role description for mute button"); + if (name == "UnMuteButton") + return UI_STRING("unmute", "accessibility role description for turn mute off button"); + if (name == "PlayButton") + return UI_STRING("play", "accessibility role description for play button"); + if (name == "PauseButton") + return UI_STRING("pause", "accessibility role description for pause button"); + if (name == "Slider") + return 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"); + if (name == "RewindButton") + return 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"); + if (name == "CurrentTimeDisplay") + return 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"); + if (name == "StatusDisplay") + return UI_STRING("status", "accessibility role description for movie status"); + if (name == "FullscreenButton") + return 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"); + if (name == "SeekBackButton") + return 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"); + if (name == "HideClosedCaptionsButton") + return 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") + return String(); + + ASSERT_NOT_REACHED(); + return String(); +} + +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"); + if (name == "VideoElement") + return 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"); + if (name == "UnMuteButton") + return 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"); + if (name == "PauseButton") + return 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"); + if (name == "SliderThumb") + return 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"); + if (name == "ReturnToRealtimeButton") + return 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"); + if (name == "TimeRemainingDisplay") + return 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"); + if (name == "SeekBackButton") + return 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"); + if (name == "FullscreenButton") + return 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"); + if (name == "HideClosedCaptionsButton") + return UI_STRING("stop displaying closed captions", "accessibility help text for hide closed captions button"); + + ASSERT_NOT_REACHED(); + return String(); +} + +String DefaultLocalizationStrategy::localizedMediaTimeDescription(float time) +{ + if (!isfinite(time)) + return 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); + int hours = seconds / (60 * 60); + int minutes = (seconds / 60) % 60; + 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); + 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); + 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); +} + +String DefaultLocalizationStrategy::validationMessageValueMissingText() +{ + return 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"); +} + +String DefaultLocalizationStrategy::validationMessagePatternMismatchText() +{ + return 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"); +} + +String DefaultLocalizationStrategy::validationMessageRangeUnderflowText() +{ + return 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"); +} + +String DefaultLocalizationStrategy::validationMessageStepMismatchText() +{ + return UI_STRING("step mismatch", "Validation message for input form controls with value not respecting the step attribute"); +} + +} // namespace WebCore + +#endif // USE(PLATFORM_STRATEGIES) diff --git a/Source/WebCore/platform/DefaultLocalizationStrategy.h b/Source/WebCore/platform/DefaultLocalizationStrategy.h new file mode 100644 index 0000000..56120e0 --- /dev/null +++ b/Source/WebCore/platform/DefaultLocalizationStrategy.h @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2010, 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. + */ + +#ifndef DefaultLocalizationStrategy_h +#define DefaultLocalizationStrategy_h + +#if USE(PLATFORM_STRATEGIES) + +#include "LocalizationStrategy.h" +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class DefaultLocalizationStrategy : public LocalizationStrategy { +public: + DefaultLocalizationStrategy(); + +private: + virtual String inputElementAltText(); + virtual String resetButtonDefaultLabel(); + virtual String searchableIndexIntroduction(); + virtual String submitButtonDefaultLabel(); + virtual String fileButtonChooseFileLabel(); + virtual String fileButtonNoFileSelectedLabel(); + virtual String defaultDetailsSummaryText(); +#if PLATFORM(MAC) + virtual String copyImageUnknownFileLabel(); +#endif +#if ENABLE(CONTEXT_MENUS) + virtual String contextMenuItemTagOpenLinkInNewWindow(); + virtual String contextMenuItemTagDownloadLinkToDisk(); + virtual String contextMenuItemTagCopyLinkToClipboard(); + virtual String contextMenuItemTagOpenImageInNewWindow(); + virtual String contextMenuItemTagDownloadImageToDisk(); + virtual String contextMenuItemTagCopyImageToClipboard(); +#if PLATFORM(QT) + virtual String contextMenuItemTagCopyImageUrlToClipboard(); +#endif + virtual String contextMenuItemTagOpenFrameInNewWindow(); + virtual String contextMenuItemTagCopy(); + virtual String contextMenuItemTagGoBack(); + virtual String contextMenuItemTagGoForward(); + virtual String contextMenuItemTagStop(); + virtual String contextMenuItemTagReload(); + virtual String contextMenuItemTagCut(); + virtual String contextMenuItemTagPaste(); +#if PLATFORM(GTK) + virtual String contextMenuItemTagDelete(); + virtual String contextMenuItemTagInputMethods(); + virtual String contextMenuItemTagUnicode(); +#endif +#if PLATFORM(GTK) || PLATFORM(QT) + virtual String contextMenuItemTagSelectAll(); +#endif + virtual String contextMenuItemTagNoGuessesFound(); + virtual String contextMenuItemTagIgnoreSpelling(); + virtual String contextMenuItemTagLearnSpelling(); + virtual String contextMenuItemTagSearchWeb(); + virtual String contextMenuItemTagLookUpInDictionary(const String& selectedString); + virtual String contextMenuItemTagOpenLink(); + virtual String contextMenuItemTagIgnoreGrammar(); + virtual String contextMenuItemTagSpellingMenu(); + virtual String contextMenuItemTagShowSpellingPanel(bool show); + virtual String contextMenuItemTagCheckSpelling(); + virtual String contextMenuItemTagCheckSpellingWhileTyping(); + virtual String contextMenuItemTagCheckGrammarWithSpelling(); + virtual String contextMenuItemTagFontMenu(); + virtual String contextMenuItemTagBold(); + virtual String contextMenuItemTagItalic(); + virtual String contextMenuItemTagUnderline(); + virtual String contextMenuItemTagOutline(); + virtual String contextMenuItemTagWritingDirectionMenu(); + virtual String contextMenuItemTagTextDirectionMenu(); + virtual String contextMenuItemTagDefaultDirection(); + virtual String contextMenuItemTagLeftToRight(); + virtual String contextMenuItemTagRightToLeft(); +#if PLATFORM(MAC) + virtual String contextMenuItemTagSearchInSpotlight(); + virtual String contextMenuItemTagShowFonts(); + virtual String contextMenuItemTagStyles(); + virtual String contextMenuItemTagShowColors(); + virtual String contextMenuItemTagSpeechMenu(); + virtual String contextMenuItemTagStartSpeaking(); + virtual String contextMenuItemTagStopSpeaking(); + virtual String contextMenuItemTagCorrectSpellingAutomatically(); + virtual String contextMenuItemTagSubstitutionsMenu(); + virtual String contextMenuItemTagShowSubstitutions(bool show); + virtual String contextMenuItemTagSmartCopyPaste(); + virtual String contextMenuItemTagSmartQuotes(); + virtual String contextMenuItemTagSmartDashes(); + virtual String contextMenuItemTagSmartLinks(); + virtual String contextMenuItemTagTextReplacement(); + virtual String contextMenuItemTagTransformationsMenu(); + virtual String contextMenuItemTagMakeUpperCase(); + virtual String contextMenuItemTagMakeLowerCase(); + virtual String contextMenuItemTagCapitalize(); + virtual String contextMenuItemTagChangeBack(const String& replacedString); +#endif + virtual String contextMenuItemTagInspectElement(); + virtual String contextMenuItemTagOpenVideoInNewWindow(); + virtual String contextMenuItemTagOpenAudioInNewWindow(); + virtual String contextMenuItemTagCopyVideoLinkToClipboard(); + virtual String contextMenuItemTagCopyAudioLinkToClipboard(); + virtual String contextMenuItemTagToggleMediaControls(); + virtual String contextMenuItemTagToggleMediaLoop(); + virtual String contextMenuItemTagEnterVideoFullscreen(); + virtual String contextMenuItemTagMediaPlay(); + virtual String contextMenuItemTagMediaPause(); + virtual String contextMenuItemTagMediaMute(); +#endif // ENABLE(CONTEXT_MENUS) + virtual String searchMenuNoRecentSearchesText(); + virtual String searchMenuRecentSearchesText(); + virtual String searchMenuClearRecentSearchesText(); + virtual String AXWebAreaText(); + virtual String AXLinkText(); + virtual String AXListMarkerText(); + virtual String AXImageMapText(); + virtual String AXHeadingText(); + virtual String AXDefinitionListTermText(); + virtual String AXDefinitionListDefinitionText(); +#if PLATFORM(MAC) + virtual String AXARIAContentGroupText(const String& ariaType); +#endif + virtual String AXButtonActionVerb(); + virtual String AXRadioButtonActionVerb(); + virtual String AXTextFieldActionVerb(); + virtual String AXCheckedCheckBoxActionVerb(); + virtual String AXUncheckedCheckBoxActionVerb(); + virtual String AXMenuListActionVerb(); + virtual String AXMenuListPopupActionVerb(); + virtual String AXLinkActionVerb(); + virtual String missingPluginText(); + virtual String crashedPluginText(); + virtual String multipleFileUploadText(unsigned numberOfFiles); + virtual String unknownFileSizeText(); +#if PLATFORM(WIN) + virtual String uploadFileText(); + virtual String allFilesText(); +#endif +#if PLATFORM(MAC) + virtual String keygenMenuItem512(); + virtual String keygenMenuItem1024(); + virtual String keygenMenuItem2048(); + virtual String keygenKeychainItemName(const String& host); +#endif + virtual String imageTitle(const String& filename, const IntSize&); + virtual String mediaElementLoadingStateText(); + virtual String mediaElementLiveBroadcastStateText(); + virtual String localizedMediaControlElementString(const String&); + virtual String localizedMediaControlElementHelpText(const String&); + virtual String localizedMediaTimeDescription(float); + virtual String validationMessageValueMissingText(); + virtual String validationMessageTypeMismatchText(); + virtual String validationMessagePatternMismatchText(); + virtual String validationMessageTooLongText(); + virtual String validationMessageRangeUnderflowText(); + virtual String validationMessageRangeOverflowText(); + virtual String validationMessageStepMismatchText(); +}; + +} // namespace WebCore + +#endif // USE(PLATFORM_STRATEGIES) + +#endif // DefaultLocalizationStrategy_h diff --git a/Source/WebCore/platform/FileMetadata.h b/Source/WebCore/platform/FileMetadata.h index 9b7d09b..99fe2f3 100644 --- a/Source/WebCore/platform/FileMetadata.h +++ b/Source/WebCore/platform/FileMetadata.h @@ -31,6 +31,8 @@ #ifndef FileMetadata_h #define FileMetadata_h +#include <wtf/text/WTFString.h> + #if ENABLE(FILE_SYSTEM) namespace WebCore { @@ -52,6 +54,8 @@ struct FileMetadata { Type type; + String platformPath; + FileMetadata() : modificationTime(0.0), length(-1), type(TypeUnknown) { } }; diff --git a/Source/WebCore/platform/FileSystem.cpp b/Source/WebCore/platform/FileSystem.cpp index 0f69b7f..cc2e904 100644 --- a/Source/WebCore/platform/FileSystem.cpp +++ b/Source/WebCore/platform/FileSystem.cpp @@ -26,6 +26,8 @@ #include "config.h" #include "FileSystem.h" +#include <wtf/HexNumber.h> + namespace WebCore { // The following lower-ASCII characters need escaping to be used in a filename @@ -75,8 +77,6 @@ static inline bool shouldEscapeUChar(UChar c) return c > 127 ? false : needsEscaping[c]; } -static const char hexDigits[17] = "0123456789ABCDEF"; - String encodeForFileName(const String& inputStr) { unsigned length = inputStr.length(); @@ -90,8 +90,7 @@ String encodeForFileName(const String& inputStr) UChar c = *str++; if (shouldEscapeUChar(c)) { *p++ = '%'; - *p++ = hexDigits[(c >> 4) & 0xF]; - *p++ = hexDigits[c & 0xF]; + placeByteAsHex(c, p); } else *p++ = c; } diff --git a/Source/WebCore/platform/FileSystem.h b/Source/WebCore/platform/FileSystem.h index 8b7d0f0..49a78e8 100644 --- a/Source/WebCore/platform/FileSystem.h +++ b/Source/WebCore/platform/FileSystem.h @@ -172,7 +172,7 @@ CString fileSystemRepresentation(const String&); inline bool isHandleValid(const PlatformFileHandle& handle) { return handle != invalidPlatformFileHandle; } // Prefix is what the filename should be prefixed with, not the full path. -CString openTemporaryFile(const char* prefix, PlatformFileHandle&); +String openTemporaryFile(const String& prefix, PlatformFileHandle&); PlatformFileHandle openFile(const String& path, FileOpenMode); void closeFile(PlatformFileHandle&); // Returns the resulting offset from the beginning of the file if successful, -1 otherwise. diff --git a/Source/WebCore/platform/HostWindow.h b/Source/WebCore/platform/HostWindow.h index 0d19356..316f043 100644 --- a/Source/WebCore/platform/HostWindow.h +++ b/Source/WebCore/platform/HostWindow.h @@ -52,7 +52,7 @@ public: #if ENABLE(TILED_BACKING_STORE) // Requests the host to do the actual scrolling. This is only used in combination with a tiled backing store. - virtual void delegatedScrollRequested(const IntSize& scrollDelta) = 0; + virtual void delegatedScrollRequested(const IntPoint& scrollPoint) = 0; #endif // Methods for doing coordinate conversions to and from screen coordinates. diff --git a/Source/WebCore/platform/KURL.cpp b/Source/WebCore/platform/KURL.cpp index 0032f09..88ad3d9 100644 --- a/Source/WebCore/platform/KURL.cpp +++ b/Source/WebCore/platform/KURL.cpp @@ -30,6 +30,7 @@ #include "TextEncoding.h" #include <wtf/text/CString.h> #include <wtf/HashMap.h> +#include <wtf/HexNumber.h> #include <wtf/StdLibExtras.h> #include <wtf/text/StringHash.h> @@ -89,8 +90,6 @@ enum URLCharacterClasses { BadChar = 1 << 6 }; -static const char hexDigits[17] = "0123456789ABCDEF"; - static const unsigned char characterClassTable[256] = { /* 0 nul */ PathSegmentEndChar, /* 1 soh */ BadChar, /* 2 stx */ BadChar, /* 3 etx */ BadChar, @@ -221,7 +220,6 @@ static const unsigned char characterClassTable[256] = { static int copyPathRemovingDots(char* dst, const char* src, int srcStart, int srcEnd); static void encodeRelativeString(const String& rel, const TextEncoding&, CharBuffer& ouput); static String substituteBackslashes(const String&); -static bool isValidProtocol(const String&); static inline bool isSchemeFirstChar(char c) { return characterClassTable[static_cast<unsigned char>(c)] & SchemeFirstChar; } static inline bool isSchemeFirstChar(UChar c) { return c <= 0xff && (characterClassTable[c] & SchemeFirstChar); } @@ -861,7 +859,11 @@ void KURL::setPath(const String& s) // FIXME: encodeWithURLEscapeSequences does not correctly escape '#' and '?', so fragment and query parts // may be inadvertently affected. - parse(m_string.left(m_portEnd) + encodeWithURLEscapeSequences(s) + m_string.substring(m_pathEnd)); + String path = s; + if (path.isEmpty() || path[0] != '/') + path = "/" + path; + + parse(m_string.left(m_portEnd) + encodeWithURLEscapeSequences(path) + m_string.substring(m_pathEnd)); } String KURL::prettyURL() const @@ -971,8 +973,7 @@ String decodeURLEscapeSequences(const String& str, const TextEncoding& encoding) static void appendEscapedChar(char*& buffer, unsigned char c) { *buffer++ = '%'; - *buffer++ = hexDigits[c >> 4]; - *buffer++ = hexDigits[c & 0xF]; + placeByteAsHex(c, buffer); } static void appendEscapingBadChars(char*& buffer, const char* strStart, size_t length) @@ -1131,6 +1132,11 @@ static inline bool isDefaultPortForScheme(const char* port, size_t portLength, c return false; } +static inline bool hostPortIsEmptyButCredentialsArePresent(int hostStart, int portEnd, char userEndChar) +{ + return userEndChar == '@' && hostStart == portEnd; +} + void KURL::parse(const char* url, const String* originalString) { if (!url || url[0] == '\0') { @@ -1256,6 +1262,12 @@ void KURL::parse(const char* url, const String* originalString) return; } + if (hostPortIsEmptyButCredentialsArePresent(hostStart, portEnd, url[userEnd])) { + // in this circumstance, act as if there is an erroneous hostname containing an '@' + userEnd = userStart; + hostStart = userEnd; + } + if (userStart == portEnd && !m_protocolInHTTPFamily && !isFile) { // No authority found, which means that this is not a net_path, but rather an abs_path whose first two // path segments are empty. For file, http and https only, an empty authority is allowed. diff --git a/Source/WebCore/platform/KURL.h b/Source/WebCore/platform/KURL.h index be72824..5764494 100644 --- a/Source/WebCore/platform/KURL.h +++ b/Source/WebCore/platform/KURL.h @@ -279,6 +279,8 @@ bool protocolIsJavaScript(const String& url); bool isDefaultPortForProtocol(unsigned short port, const String& protocol); bool portAllowed(const KURL&); // Blacklist ports that should never be used for Web resources. +bool isValidProtocol(const String&); + String mimeTypeFromDataURL(const String& url); // Unescapes the given string using URL escaping rules, given an optional diff --git a/Source/WebCore/platform/KURLGoogle.cpp b/Source/WebCore/platform/KURLGoogle.cpp index 231c43d..88120a8 100644 --- a/Source/WebCore/platform/KURLGoogle.cpp +++ b/Source/WebCore/platform/KURLGoogle.cpp @@ -133,6 +133,22 @@ static inline bool isSchemeChar(char c) return isSchemeFirstChar(c) || (c >= '0' && c <= '9') || c == '.' || c == '-' || c == '*'; } +bool isValidProtocol(const String& protocol) +{ + // NOTE This is a copy of the function in KURL.cpp. + // RFC3986: ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + if (protocol.isEmpty()) + return false; + if (!isSchemeFirstChar(protocol[0])) + return false; + unsigned protocolLength = protocol.length(); + for (unsigned i = 1; i < protocolLength; i++) { + if (!isSchemeChar(protocol[i])) + return false; + } + return true; +} + // KURLGooglePrivate ----------------------------------------------------------- diff --git a/Source/WebCore/platform/KillRingNone.cpp b/Source/WebCore/platform/KillRingNone.cpp index 35098aa..310aa08 100644 --- a/Source/WebCore/platform/KillRingNone.cpp +++ b/Source/WebCore/platform/KillRingNone.cpp @@ -28,11 +28,11 @@ namespace WebCore { -void KillRing::append(const String& string) +void KillRing::append(const String&) { } -void KillRing::prepend(const String& string) +void KillRing::prepend(const String&) { } diff --git a/Source/WebCore/platform/Length.h b/Source/WebCore/platform/Length.h index 886dfec..2b11a5f 100644 --- a/Source/WebCore/platform/Length.h +++ b/Source/WebCore/platform/Length.h @@ -1,6 +1,7 @@ /* Copyright (C) 1999 Lars Knoll (knoll@kde.org) Copyright (C) 2006, 2008 Apple Inc. All rights reserved. + Copyright (C) 2011 Rik Cabanier (cabanier@adobe.com) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -30,7 +31,6 @@ namespace WebCore { const int undefinedLength = -1; -const int percentScaleFactor = 128; const int intMaxForLength = 0x7ffffff; // max value for a 28-bit int const int intMinForLength = (-0x7ffffff - 1); // min value for a 28-bit int @@ -40,72 +40,79 @@ struct Length { WTF_MAKE_FAST_ALLOCATED; public: Length() - : m_value(0) + : m_intValue(0), m_quirk(false), m_type(Auto), m_isFloat(false) { } Length(LengthType t) - : m_value(t) + : m_intValue(0), m_quirk(false), m_type(t), m_isFloat(false) { } Length(int v, LengthType t, bool q = false) - : m_value((v * 16) | (q << 3) | t) // FIXME: Doesn't work if the passed-in value is very large! + : m_intValue(v), m_quirk(q), m_type(t), m_isFloat(false) { - ASSERT(t != Percent); + } + + Length(float v, LengthType t, bool q = false) + : m_floatValue(v), m_quirk(q), m_type(t), m_isFloat(true) + { } Length(double v, LengthType t, bool q = false) - : m_value(static_cast<int>(v * percentScaleFactor) * 16 | (q << 3) | t) - { - ASSERT(t == Percent); + : m_quirk(q), m_type(t), m_isFloat(true) + { + m_floatValue = static_cast<float>(v); } - bool operator==(const Length& o) const { return m_value == o.m_value; } - bool operator!=(const Length& o) const { return m_value != o.m_value; } + bool operator==(const Length& o) const { return (getFloatValue() == o.getFloatValue()) && (m_type == o.m_type) && (m_quirk == o.m_quirk); } + bool operator!=(const Length& o) const { return (getFloatValue() != o.getFloatValue()) || (m_type != o.m_type) || (m_quirk != o.m_quirk); } + const Length& operator*=(float v) + { + if (m_isFloat) + m_floatValue = static_cast<float>(m_floatValue * v); + else + m_intValue = static_cast<int>(m_intValue * v); + + return *this; + } + int value() const { - ASSERT(type() != Percent); - return rawValue(); + return getIntValue(); } - int rawValue() const { return (m_value & ~0xF) / 16; } - - double percent() const + float percent() const { ASSERT(type() == Percent); - return static_cast<double>(rawValue()) / percentScaleFactor; + return getFloatValue(); } - LengthType type() const { return static_cast<LengthType>(m_value & 7); } - bool quirk() const { return (m_value >> 3) & 1; } + LengthType type() const { return static_cast<LengthType>(m_type); } + bool quirk() const { return m_quirk; } void setValue(LengthType t, int value) { - ASSERT(t != Percent); - setRawValue(t, value); + m_type = t; + m_intValue = value; + m_isFloat = false; } - void setRawValue(LengthType t, int value) { m_value = value * 16 | (m_value & 0x8) | t; } - void setValue(int value) { - ASSERT(!value || type() != Percent); - setRawValue(value); + setValue(Fixed, value); } - void setRawValue(int value) { m_value = value * 16 | (m_value & 0xF); } - - void setValue(LengthType t, double value) + void setValue(LengthType t, float value) { - ASSERT(t == Percent); - m_value = static_cast<int>(value * percentScaleFactor) * 16 | (m_value & 0x8) | t; + m_type = t; + m_floatValue = value; + m_isFloat = true; } - void setValue(double value) + void setValue(float value) { - ASSERT(type() == Percent); - m_value = static_cast<int>(value * percentScaleFactor) * 16 | (m_value & 0xF); + *this = Length(value, Fixed); } // note: works only for certain types, returns undefinedLength otherwise @@ -113,11 +120,8 @@ public: { switch (type()) { case Fixed: - return value(); case Percent: - if (roundPercentages) - return static_cast<int>(round(maxValue * percent() / 100.0)); - return maxValue * rawValue() / (100 * percentScaleFactor); + return calcMinValue(maxValue, roundPercentages); case Auto: return maxValue; default: @@ -132,8 +136,9 @@ public: return value(); case Percent: if (roundPercentages) - return static_cast<int>(round(maxValue * percent() / 100.0)); - return maxValue * rawValue() / (100 * percentScaleFactor); + return static_cast<int>(round(maxValue * percent() / 100.0f)); + // Don't remove the extra cast to float. It is needed for rounding on 32-bit Intel machines that use the FPU stack. + return static_cast<int>(static_cast<float>(maxValue * percent() / 100.0f)); case Auto: default: return 0; @@ -144,9 +149,9 @@ public: { switch (type()) { case Fixed: - return static_cast<float>(value()); + return getFloatValue(); case Percent: - return static_cast<float>(maxValue * percent() / 100.0); + return static_cast<float>(maxValue * percent() / 100.0f); case Auto: return static_cast<float>(maxValue); default: @@ -154,10 +159,14 @@ public: } } - bool isUndefined() const { return rawValue() == undefinedLength; } - bool isZero() const { return !(m_value & ~0xF); } - bool isPositive() const { return rawValue() > 0; } - bool isNegative() const { return rawValue() < 0; } + bool isUndefined() const { return value() == undefinedLength; } + bool isZero() const + { + return m_isFloat ? !m_floatValue : !m_intValue; + } + + bool isPositive() const { return getFloatValue() > 0; } + bool isNegative() const { return getFloatValue() < 0; } bool isAuto() const { return type() == Auto; } bool isRelative() const { return type() == Relative; } @@ -165,7 +174,7 @@ public: bool isFixed() const { return type() == Fixed; } bool isIntrinsicOrAuto() const { return type() == Auto || type() == MinIntrinsic || type() == Intrinsic; } - Length blend(const Length& from, double progress) const + Length blend(const Length& from, float progress) const { // Blend two lengths to produce a new length that is in between them. Used for animation. if (!from.isZero() && !isZero() && from.type() != type()) @@ -179,18 +188,34 @@ public: resultType = from.type(); if (resultType == Percent) { - double fromPercent = from.isZero() ? 0. : from.percent(); - double toPercent = isZero() ? 0. : percent(); + float fromPercent = from.isZero() ? 0 : from.percent(); + float toPercent = isZero() ? 0 : percent(); return Length(fromPercent + (toPercent - fromPercent) * progress, Percent); } - int fromValue = from.isZero() ? 0 : from.value(); - int toValue = isZero() ? 0 : value(); - return Length(int(fromValue + (toValue - fromValue) * progress), resultType); + float fromValue = from.isZero() ? 0 : from.value(); + float toValue = isZero() ? 0 : value(); + return Length(fromValue + (toValue - fromValue) * progress, resultType); } private: - int m_value; + int getIntValue() const + { + return m_isFloat ? static_cast<int>(m_floatValue) : m_intValue; + } + + float getFloatValue() const + { + return m_isFloat ? m_floatValue : m_intValue; + } + + union { + int m_intValue; + float m_floatValue; + }; + bool m_quirk; + unsigned char m_type; + bool m_isFloat; }; PassOwnArrayPtr<Length> newCoordsArray(const String&, int& len); diff --git a/Source/WebCore/platform/LinkHash.cpp b/Source/WebCore/platform/LinkHash.cpp index a2acad1..29671a0 100644 --- a/Source/WebCore/platform/LinkHash.cpp +++ b/Source/WebCore/platform/LinkHash.cpp @@ -197,7 +197,7 @@ static inline bool needsTrailingSlash(const UChar* characters, unsigned length) static ALWAYS_INLINE LinkHash visitedLinkHashInline(const UChar* url, unsigned length) { - return AlreadyHashed::avoidDeletedValue(WTF::StringHasher::createHash(url, length)); + return AlreadyHashed::avoidDeletedValue(StringHasher::computeHash(url, length)); } LinkHash visitedLinkHash(const UChar* url, unsigned length) diff --git a/Source/WebCore/platform/LocalizationStrategy.h b/Source/WebCore/platform/LocalizationStrategy.h index eba0e7c..f883893 100644 --- a/Source/WebCore/platform/LocalizationStrategy.h +++ b/Source/WebCore/platform/LocalizationStrategy.h @@ -79,7 +79,7 @@ public: virtual String contextMenuItemTagIgnoreSpelling() = 0; virtual String contextMenuItemTagLearnSpelling() = 0; virtual String contextMenuItemTagSearchWeb() = 0; - virtual String contextMenuItemTagLookUpInDictionary() = 0; + virtual String contextMenuItemTagLookUpInDictionary(const String& selectedString) = 0; virtual String contextMenuItemTagOpenLink() = 0; virtual String contextMenuItemTagIgnoreGrammar() = 0; virtual String contextMenuItemTagSpellingMenu() = 0; @@ -167,6 +167,13 @@ public: virtual String allFilesText() = 0; #endif +#if PLATFORM(MAC) + virtual String keygenMenuItem512() = 0; + virtual String keygenMenuItem1024() = 0; + virtual String keygenMenuItem2048() = 0; + virtual String keygenKeychainItemName(const String& host) = 0; +#endif + virtual String imageTitle(const String& filename, const IntSize& size) = 0; virtual String mediaElementLoadingStateText() = 0; diff --git a/Source/WebCore/platform/LocalizedStrings.cpp b/Source/WebCore/platform/LocalizedStrings.cpp index 9656dbe..f5ad0b7 100644 --- a/Source/WebCore/platform/LocalizedStrings.cpp +++ b/Source/WebCore/platform/LocalizedStrings.cpp @@ -190,9 +190,9 @@ String contextMenuItemTagSearchWeb() return platformStrategies()->localizationStrategy()->contextMenuItemTagSearchWeb(); } -String contextMenuItemTagLookUpInDictionary() +String contextMenuItemTagLookUpInDictionary(const String& selectedString) { - return platformStrategies()->localizationStrategy()->contextMenuItemTagLookUpInDictionary(); + return platformStrategies()->localizationStrategy()->contextMenuItemTagLookUpInDictionary(selectedString); } String contextMenuItemTagOpenLink() @@ -569,6 +569,29 @@ String allFilesText() } #endif +#if PLATFORM(MAC) +String keygenMenuItem512() +{ + return platformStrategies()->localizationStrategy()->keygenMenuItem512(); +} + +String keygenMenuItem1024() +{ + return platformStrategies()->localizationStrategy()->keygenMenuItem1024(); +} + +String keygenMenuItem2048() +{ + return platformStrategies()->localizationStrategy()->keygenMenuItem2048(); +} + +String keygenKeychainItemName(const String& host) +{ + return platformStrategies()->localizationStrategy()->keygenKeychainItemName(host); +} + +#endif + String imageTitle(const String& filename, const IntSize& size) { return platformStrategies()->localizationStrategy()->imageTitle(filename, size); @@ -676,4 +699,11 @@ String validationMessageStepMismatchText(const String&, const String&) #endif // USE(PLATFORM_STRATEGIES) +#if !PLATFORM(MAC) && !PLATFORM(WIN) +String localizedString(const char* key) +{ + return String::fromUTF8(key, strlen(key)); +} +#endif + } // namespace WebCore diff --git a/Source/WebCore/platform/LocalizedStrings.h b/Source/WebCore/platform/LocalizedStrings.h index f22c975..3885439 100644 --- a/Source/WebCore/platform/LocalizedStrings.h +++ b/Source/WebCore/platform/LocalizedStrings.h @@ -75,7 +75,7 @@ namespace WebCore { String contextMenuItemTagIgnoreSpelling(); String contextMenuItemTagLearnSpelling(); String contextMenuItemTagSearchWeb(); - String contextMenuItemTagLookUpInDictionary(); + String contextMenuItemTagLookUpInDictionary(const String& selectedString); String contextMenuItemTagOpenLink(); String contextMenuItemTagIgnoreGrammar(); String contextMenuItemTagSpellingMenu(); @@ -163,6 +163,13 @@ namespace WebCore { String allFilesText(); #endif +#if PLATFORM(MAC) + String keygenMenuItem512(); + String keygenMenuItem1024(); + String keygenMenuItem2048(); + String keygenKeychainItemName(const String& host); +#endif + String imageTitle(const String& filename, const IntSize& size); String mediaElementLoadingStateText(); @@ -187,9 +194,11 @@ namespace WebCore { String validationMessageRangeOverflowText(const String& maximum); String validationMessageStepMismatchText(const String& base, const String& step); -#if PLATFORM(MAC) + +#define UI_STRING(string, description) WebCore::localizedString(string) +#define UI_STRING_KEY(string, key, description) WebCore::localizedString(key) + String localizedString(const char* key); -#endif } // namespace WebCore diff --git a/Source/WebCore/platform/MIMETypeRegistry.cpp b/Source/WebCore/platform/MIMETypeRegistry.cpp index e76906e..d0ad985 100644 --- a/Source/WebCore/platform/MIMETypeRegistry.cpp +++ b/Source/WebCore/platform/MIMETypeRegistry.cpp @@ -55,6 +55,7 @@ static HashSet<String>* supportedImageMIMETypesForEncoding; static HashSet<String>* supportedJavaScriptMIMETypes; static HashSet<String>* supportedNonImageMIMETypes; static HashSet<String>* supportedMediaMIMETypes; +static HashSet<String>* unsupportedTextMIMETypes; typedef HashMap<String, Vector<String>*, CaseFoldingHash> MediaMIMETypeMap; @@ -419,6 +420,27 @@ static void initializeSupportedMediaMIMETypes() #endif } +static void initializeUnsupportedTextMIMETypes() +{ + static const char* types[] = { + "text/calendar", + "text/x-calendar", + "text/x-vcalendar", + "text/vcalendar", + "text/vcard", + "text/x-vcard", + "text/directory", + "text/ldif", + "text/qif", + "text/x-qif", + "text/x-csv", + "text/x-vcf", + "text/rtf", + }; + for (size_t i = 0; i < WTF_ARRAY_LENGTH(types); ++i) + unsupportedTextMIMETypes->add(types[i]); +} + static void initializeMIMETypeRegistry() { supportedJavaScriptMIMETypes = new HashSet<String>; @@ -430,6 +452,9 @@ static void initializeMIMETypeRegistry() supportedImageResourceMIMETypes = new HashSet<String>; supportedImageMIMETypes = new HashSet<String>; initializeSupportedImageMIMETypes(); + + unsupportedTextMIMETypes = new HashSet<String>; + initializeUnsupportedTextMIMETypes(); } String MIMETypeRegistry::getMIMETypeForPath(const String& path) @@ -500,6 +525,15 @@ bool MIMETypeRegistry::isSupportedMediaMIMEType(const String& mimeType) return supportedMediaMIMETypes->contains(mimeType); } +bool MIMETypeRegistry::isUnsupportedTextMIMEType(const String& mimeType) +{ + if (mimeType.isEmpty()) + return false; + if (!unsupportedTextMIMETypes) + initializeMIMETypeRegistry(); + return unsupportedTextMIMETypes->contains(mimeType); +} + bool MIMETypeRegistry::isJavaAppletMIMEType(const String& mimeType) { // Since this set is very limited and is likely to remain so we won't bother with the overhead @@ -546,6 +580,13 @@ HashSet<String>& MIMETypeRegistry::getSupportedMediaMIMETypes() return *supportedMediaMIMETypes; } +HashSet<String>& MIMETypeRegistry::getUnsupportedTextMIMETypes() +{ + if (!unsupportedTextMIMETypes) + initializeMIMETypeRegistry(); + return *unsupportedTextMIMETypes; +} + const String& defaultMIMEType() { DEFINE_STATIC_LOCAL(const String, defaultMIMEType, ("application/octet-stream")); diff --git a/Source/WebCore/platform/MIMETypeRegistry.h b/Source/WebCore/platform/MIMETypeRegistry.h index d069035..19d1b4b 100644 --- a/Source/WebCore/platform/MIMETypeRegistry.h +++ b/Source/WebCore/platform/MIMETypeRegistry.h @@ -68,6 +68,10 @@ public: // Check to see if a mime type is suitable for being loaded using <video> and <audio> static bool isSupportedMediaMIMEType(const String& mimeType); + // Check to see if the mime type is not suitable for being loaded as a text + // document in a frame. Only valid for mime types begining with "text/". + static bool isUnsupportedTextMIMEType(const String& mimeType); + // Check to see if a mime type is a valid Java applet mime type static bool isJavaAppletMIMEType(const String& mimeType); @@ -80,6 +84,7 @@ public: static HashSet<String>& getSupportedImageMIMETypesForEncoding(); static HashSet<String>& getSupportedNonImageMIMETypes(); static HashSet<String>& getSupportedMediaMIMETypes(); + static HashSet<String>& getUnsupportedTextMIMETypes(); }; const String& defaultMIMEType(); diff --git a/Source/WebCore/platform/PlatformGestureRecognizer.cpp b/Source/WebCore/platform/PlatformGestureRecognizer.cpp new file mode 100644 index 0000000..38fc3fe --- /dev/null +++ b/Source/WebCore/platform/PlatformGestureRecognizer.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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PlatformGestureRecognizer.h" + +namespace WebCore { + +PlatformGestureRecognizer::PlatformGestureRecognizer() { } +PlatformGestureRecognizer::~PlatformGestureRecognizer() { } + +// To get a useful GestureRecognizer, a specific platform should return something +// here that meets its needs. EventHandler will ignore null GestureRecognizers. +PlatformGestureRecognizer* PlatformGestureRecognizer::create() +{ + return 0; +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/PlatformGestureRecognizer.h b/Source/WebCore/platform/PlatformGestureRecognizer.h new file mode 100644 index 0000000..f6e85a5 --- /dev/null +++ b/Source/WebCore/platform/PlatformGestureRecognizer.h @@ -0,0 +1,64 @@ +/* + * 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 PlatformGestureRecognizer_h +#define PlatformGestureRecognizer_h + +namespace WebCore { + +class EventHandler; +class PlatformGestureRecognizer; +class PlatformTouchEvent; + +// A GestureRecognizer detects gestures occurring in the touch event. +// In response to a given touch event, the GestureRecognizer, updates +// its internal state and optionally dispatches synthetic events to the +// invoking EventHandler instance. +class PlatformGestureRecognizer { +protected: + PlatformGestureRecognizer(); + +public: + virtual ~PlatformGestureRecognizer(); + + // Invoked for each touch event that could contribute to the current gesture. + // Takes a PlatformTouchEvent and the EventHandler that originated it and which will also + // be the target of any generated synthetic event. Finally, |handled| + // specifies if the |event| was actually handled by |source| (by the JavaScript) + // Returns true if the event resulted in firing a synthetic event. + virtual bool processTouchEventForGesture(const PlatformTouchEvent&, EventHandler*, bool handled) = 0; + + // Factory method for GestureManagers. + static PlatformGestureRecognizer* create(); +}; + +} // namespace WebCore + +#endif // PlatformGestureRecognizer_h diff --git a/Source/WebCore/platform/PlatformKeyboardEvent.h b/Source/WebCore/platform/PlatformKeyboardEvent.h index fcca8bd..a3127c7 100644 --- a/Source/WebCore/platform/PlatformKeyboardEvent.h +++ b/Source/WebCore/platform/PlatformKeyboardEvent.h @@ -96,7 +96,7 @@ namespace WebCore { AltKey = 1 << 0, CtrlKey = 1 << 1, MetaKey = 1 << 2, - ShiftKey = 1 << 3, + ShiftKey = 1 << 3 }; PlatformKeyboardEvent() diff --git a/Source/WebCore/platform/PlatformStrategies.cpp b/Source/WebCore/platform/PlatformStrategies.cpp index e0baa70..9623108 100644 --- a/Source/WebCore/platform/PlatformStrategies.cpp +++ b/Source/WebCore/platform/PlatformStrategies.cpp @@ -29,6 +29,8 @@ #include "PlatformStrategies.h" +#include "DefaultLocalizationStrategy.h" + namespace WebCore { static PlatformStrategies* s_platformStrategies; @@ -51,7 +53,12 @@ void setPlatformStrategies(PlatformStrategies* platformStrategies) // throw an exception here in release builds. ASSERT(platformStrategies != s_platformStrategies); } - + +LocalizationStrategy* PlatformStrategies::createLocalizationStrategy() +{ + return new DefaultLocalizationStrategy; +} + } // namespace WebCore #endif // USE(PLATFORM_STRATEGIES) diff --git a/Source/WebCore/platform/PlatformStrategies.h b/Source/WebCore/platform/PlatformStrategies.h index bda7c90..6768658 100644 --- a/Source/WebCore/platform/PlatformStrategies.h +++ b/Source/WebCore/platform/PlatformStrategies.h @@ -81,7 +81,7 @@ protected: private: virtual CookiesStrategy* createCookiesStrategy() = 0; virtual PluginStrategy* createPluginStrategy() = 0; - virtual LocalizationStrategy* createLocalizationStrategy() = 0; + virtual LocalizationStrategy* createLocalizationStrategy(); virtual VisitedLinkStrategy* createVisitedLinkStrategy() = 0; CookiesStrategy* m_cookiesStrategy; diff --git a/Source/WebCore/platform/ScrollAnimator.h b/Source/WebCore/platform/ScrollAnimator.h index 060511c..6698b63 100644 --- a/Source/WebCore/platform/ScrollAnimator.h +++ b/Source/WebCore/platform/ScrollAnimator.h @@ -68,6 +68,8 @@ public: FloatPoint currentPosition() const; + virtual void cancelAnimations() { } + virtual void contentAreaWillPaint() const { } virtual void mouseEnteredContentArea() const { } virtual void mouseExitedContentArea() const { } diff --git a/Source/WebCore/platform/ScrollTypes.h b/Source/WebCore/platform/ScrollTypes.h index f07fb1a..1f8e095 100644 --- a/Source/WebCore/platform/ScrollTypes.h +++ b/Source/WebCore/platform/ScrollTypes.h @@ -119,7 +119,7 @@ namespace WebCore { enum ScrollbarControlStateMask { ActiveScrollbarState = 1, EnabledScrollbarState = 1 << 1, - PressedScrollbarState = 1 << 2, + PressedScrollbarState = 1 << 2 }; enum ScrollbarPart { @@ -133,7 +133,7 @@ namespace WebCore { ForwardButtonEndPart = 1 << 6, ScrollbarBGPart = 1 << 7, TrackBGPart = 1 << 8, - AllParts = 0xffffffff, + AllParts = 0xffffffff }; enum ScrollbarButtonsPlacement { diff --git a/Source/WebCore/platform/ScrollView.cpp b/Source/WebCore/platform/ScrollView.cpp index baf2e32..58615fb 100644 --- a/Source/WebCore/platform/ScrollView.cpp +++ b/Source/WebCore/platform/ScrollView.cpp @@ -124,7 +124,7 @@ void ScrollView::setHasVerticalScrollbar(bool hasBar) axObjectCache()->handleScrollbarUpdate(this); } -#if !PLATFORM(GTK) +#if !USE(NATIVE_GTK_MAIN_FRAME_SCROLLBAR) PassRefPtr<Scrollbar> ScrollView::createScrollbar(ScrollbarOrientation orientation) { return Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar); @@ -224,7 +224,7 @@ void ScrollView::setDelegatesScrolling(bool delegatesScrolling) m_delegatesScrolling = delegatesScrolling; } -#if !PLATFORM(GTK) +#if !USE(NATIVE_GTK_MAIN_FRAME_SCROLLBAR) IntRect ScrollView::visibleContentRect(bool includeScrollbars) const { if (platformWidget()) @@ -357,6 +357,10 @@ void ScrollView::didCompleteRubberBand(const IntSize&) const { } +void ScrollView::notifyPageThatContentAreaWillPaint() const +{ +} + void ScrollView::setScrollOffset(const IntPoint& offset) { int horizontalOffset = offset.x(); @@ -408,7 +412,7 @@ void ScrollView::setScrollPosition(const IntPoint& scrollPoint) #if ENABLE(TILED_BACKING_STORE) if (delegatesScrolling()) { - hostWindow()->delegatedScrollRequested(IntSize(scrollPoint.x(), scrollPoint.y())); + hostWindow()->delegatedScrollRequested(scrollPoint); if (!m_actualVisibleContentRect.isEmpty()) m_actualVisibleContentRect.setLocation(scrollPoint); return; @@ -439,15 +443,18 @@ bool ScrollView::logicalScroll(ScrollLogicalDirection direction, ScrollGranulari IntSize ScrollView::overhangAmount() const { IntSize stretch; - if (scrollY() < 0) - stretch.setHeight(scrollY()); - else if (scrollY() > contentsHeight() - visibleContentRect().height()) - stretch.setHeight(scrollY() - (contentsHeight() - visibleContentRect().height())); - if (scrollX() < 0) - stretch.setWidth(scrollX()); - else if (scrollX() > contentsWidth() - visibleContentRect().width()) - stretch.setWidth(scrollX() - (contentsWidth() - visibleContentRect().width())); + int physicalScrollY = scrollPosition().y() + m_scrollOrigin.y(); + if (physicalScrollY < 0) + stretch.setHeight(physicalScrollY); + else if (physicalScrollY > contentsHeight() - visibleContentRect().height()) + stretch.setHeight(physicalScrollY - (contentsHeight() - visibleContentRect().height())); + + int physicalScrollX = scrollPosition().x() + m_scrollOrigin.x(); + if (physicalScrollX < 0) + stretch.setWidth(physicalScrollX); + else if (physicalScrollX > contentsWidth() - visibleContentRect().width()) + stretch.setWidth(physicalScrollX - (contentsWidth() - visibleContentRect().width())); return stretch; } @@ -947,7 +954,7 @@ void ScrollView::paint(GraphicsContext* context, const IntRect& rect) if (context->paintingDisabled() && !context->updatingControlTints()) return; - scrollAnimator()->contentAreaWillPaint(); + notifyPageThatContentAreaWillPaint(); IntRect documentDirtyRect = rect; documentDirtyRect.intersect(frameRect()); @@ -1000,26 +1007,28 @@ void ScrollView::calculateOverhangAreasForPainting(IntRect& horizontalOverhangRe int horizontalScrollbarHeight = (horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar()) ? horizontalScrollbar()->height() : 0; - if (scrollY() < 0) { + int physicalScrollY = scrollPosition().y() + m_scrollOrigin.y(); + if (physicalScrollY < 0) { horizontalOverhangRect = frameRect(); - horizontalOverhangRect.setHeight(-scrollY()); - } else if (scrollY() > contentsHeight() - visibleContentRect().height()) { - int height = scrollY() - (contentsHeight() - visibleContentRect().height()); + horizontalOverhangRect.setHeight(-physicalScrollY); + } else if (physicalScrollY > contentsHeight() - visibleContentRect().height()) { + int height = physicalScrollY - (contentsHeight() - visibleContentRect().height()); horizontalOverhangRect = frameRect(); horizontalOverhangRect.setY(frameRect().maxY() - height - horizontalScrollbarHeight); horizontalOverhangRect.setHeight(height); } - if (scrollX() < 0) { - verticalOverhangRect.setWidth(-scrollX()); + int physicalScrollX = scrollPosition().x() + m_scrollOrigin.x(); + if (physicalScrollX < 0) { + verticalOverhangRect.setWidth(-physicalScrollX); verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhangRect.height()); verticalOverhangRect.setX(frameRect().x()); if (horizontalOverhangRect.y() == frameRect().y()) verticalOverhangRect.setY(frameRect().y() + horizontalOverhangRect.height()); else verticalOverhangRect.setY(frameRect().y()); - } else if (scrollX() > contentsWidth() - visibleContentRect().width()) { - int width = scrollX() - (contentsWidth() - visibleContentRect().width()); + } else if (physicalScrollX > contentsWidth() - visibleContentRect().width()) { + int width = physicalScrollX - (contentsWidth() - visibleContentRect().width()); verticalOverhangRect.setWidth(width); verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhangRect.height()); verticalOverhangRect.setX(frameRect().maxX() - width - verticalScrollbarWidth); @@ -1195,7 +1204,7 @@ void ScrollView::setScrollOrigin(const IntPoint& origin, bool updatePositionAtAl updateScrollbars(scrollOffset()); } -#if !PLATFORM(WX) && !PLATFORM(GTK) && !PLATFORM(EFL) +#if !PLATFORM(WX) && !USE(NATIVE_GTK_MAIN_FRAME_SCROLLBAR) && !PLATFORM(EFL) void ScrollView::platformInit() { diff --git a/Source/WebCore/platform/ScrollView.h b/Source/WebCore/platform/ScrollView.h index 1d6fba5..bff77d5 100644 --- a/Source/WebCore/platform/ScrollView.h +++ b/Source/WebCore/platform/ScrollView.h @@ -62,6 +62,7 @@ public: virtual int scrollPosition(Scrollbar*) const; virtual void setScrollOffset(const IntPoint&); virtual void didCompleteRubberBand(const IntSize&) const; + virtual void notifyPageThatContentAreaWillPaint() const; // NOTE: This should only be called by the overriden setScrollOffset from ScrollableArea. virtual void scrollTo(const IntSize& newOffset); @@ -354,19 +355,6 @@ private: bool m_clipsRepaints; bool m_delegatesScrolling; - // 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 - // horizontal-tb / ltr NO NO - // horizontal-tb / rtl YES NO - // horizontal-bt / ltr NO YES - // horizontal-bt / rtl YES YES - // vertical-lr / ltr NO NO - // vertical-lr / rtl NO YES - // vertical-rl / ltr YES NO - // vertical-rl / rtl YES YES - IntPoint m_scrollOrigin; - IntSize m_boundsSize; void init(); diff --git a/Source/WebCore/platform/ScrollableArea.h b/Source/WebCore/platform/ScrollableArea.h index f1c1308..d08de00 100644 --- a/Source/WebCore/platform/ScrollableArea.h +++ b/Source/WebCore/platform/ScrollableArea.h @@ -69,6 +69,7 @@ public: bool hasOverlayScrollbars() const; ScrollAnimator* scrollAnimator() const { return m_scrollAnimator.get(); } + const IntPoint& scrollOrigin() const { return m_scrollOrigin; } virtual int scrollSize(ScrollbarOrientation) const = 0; virtual int scrollPosition(Scrollbar*) const = 0; @@ -114,6 +115,10 @@ public: virtual IntSize overhangAmount() const { ASSERT_NOT_REACHED(); return IntSize(); } virtual IntPoint currentMousePosition() const { return IntPoint(); } virtual void didCompleteRubberBand(const IntSize&) const { ASSERT_NOT_REACHED(); } + virtual bool shouldSuspendScrollAnimations() const { return true; } + virtual void scrollbarStyleChanged() { } + + virtual void disconnectFromPage() { } private: // NOTE: Only called from the ScrollAnimator. @@ -124,6 +129,20 @@ private: bool m_constrainsScrollingToContentEdge; bool m_inLiveResize; + +protected: + // 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 + // horizontal-tb / ltr NO NO + // horizontal-tb / rtl YES NO + // horizontal-bt / ltr NO YES + // horizontal-bt / rtl YES YES + // vertical-lr / ltr NO NO + // vertical-lr / rtl NO YES + // vertical-rl / ltr YES NO + // vertical-rl / rtl YES YES + IntPoint m_scrollOrigin; }; } // namespace WebCore diff --git a/Source/WebCore/platform/SharedBuffer.cpp b/Source/WebCore/platform/SharedBuffer.cpp index 34553ec..0900ae4 100644 --- a/Source/WebCore/platform/SharedBuffer.cpp +++ b/Source/WebCore/platform/SharedBuffer.cpp @@ -167,6 +167,9 @@ void SharedBuffer::clear() m_buffer.clear(); m_purgeableBuffer.clear(); +#if HAVE(CFNETWORK_DATA_ARRAY_CALLBACK) + m_dataArray.clear(); +#endif } PassRefPtr<SharedBuffer> SharedBuffer::copy() const @@ -206,6 +209,9 @@ const Vector<char>& SharedBuffer::buffer() const freeSegment(m_segments[i]); } m_segments.clear(); +#if HAVE(CFNETWORK_DATA_ARRAY_CALLBACK) + copyDataArrayAndClear(destination, bytesLeft); +#endif } return m_buffer; } diff --git a/Source/WebCore/platform/SharedBuffer.h b/Source/WebCore/platform/SharedBuffer.h index dfde5a1..f7318e3 100644 --- a/Source/WebCore/platform/SharedBuffer.h +++ b/Source/WebCore/platform/SharedBuffer.h @@ -97,6 +97,10 @@ public: const char* platformData() const; unsigned platformDataSize() const; +#if HAVE(CFNETWORK_DATA_ARRAY_CALLBACK) + void append(CFDataRef); +#endif + PassRefPtr<SharedBuffer> copy() const; bool hasPurgeableBuffer() const { return m_purgeableBuffer.get(); } @@ -138,6 +142,10 @@ private: mutable Vector<char> m_buffer; mutable Vector<char*> m_segments; OwnPtr<PurgeableBuffer> m_purgeableBuffer; +#if HAVE(CFNETWORK_DATA_ARRAY_CALLBACK) + mutable Vector<RetainPtr<CFDataRef> > m_dataArray; + void copyDataArrayAndClear(char *destination, unsigned bytesToCopy) const; +#endif #if USE(CF) SharedBuffer(CFDataRef); RetainPtr<CFDataRef> m_cfData; diff --git a/Source/WebCore/platform/UUID.cpp b/Source/WebCore/platform/UUID.cpp index 7f59081..fce0645 100644 --- a/Source/WebCore/platform/UUID.cpp +++ b/Source/WebCore/platform/UUID.cpp @@ -44,6 +44,7 @@ #elif OS(LINUX) && !PLATFORM(CHROMIUM) #include <stdio.h> #elif (OS(LINUX) && PLATFORM(CHROMIUM)) || (OS(DARWIN) && !USE(CF)) +#include <wtf/HexNumber.h> #include <wtf/RandomNumber.h> #include <wtf/text/StringBuilder.h> #endif @@ -100,17 +101,18 @@ String createCanonicalUUIDString() // Format as Version 4 UUID. StringBuilder builder; - builder.append(String::format("%08x", randomData[0])); + appendUnsignedAsHexFixedSize(randomData[0], builder, 8, Lowercase); builder.append("-"); - builder.append(String::format("%04x", randomData[1] >> 16)); + appendUnsignedAsHexFixedSize(randomData[1] >> 16, builder, 4, Lowercase); builder.append("-4"); - builder.append(String::format("%03x", randomData[1] & 0x00000fff)); + appendUnsignedAsHexFixedSize(randomData[1] & 0x00000fff, builder, 3, Lowercase); builder.append("-"); - builder.append(String::format("%x", (randomData[2] >> 30) | 0x8)); // Condense this byte to 8, 9, a, and b. - builder.append(String::format("%03x", (randomData[2] >> 16) & 0x00000fff)); + appendUnsignedAsHexFixedSize((randomData[2] >> 30) | 0x8, builder, 1, Lowercase); + appendUnsignedAsHexFixedSize((randomData[2] >> 16) & 0x00000fff, builder, 3, Lowercase); builder.append("-"); - builder.append(String::format("%04x", randomData[2] & 0x0000ffff)); - builder.append(String::format("%08x", randomData[3])); + appendUnsignedAsHexFixedSize(randomData[2] & 0x0000ffff, builder, 4, Lowercase); + appendUnsignedAsHexFixedSize(randomData[3], builder, 8, Lowercase); + builder.append("\n"); return builder.toString(); #else notImplemented(); diff --git a/Source/WebCore/platform/android/FileSystemAndroid.cpp b/Source/WebCore/platform/android/FileSystemAndroid.cpp index 9ed43f0..5efba84 100644 --- a/Source/WebCore/platform/android/FileSystemAndroid.cpp +++ b/Source/WebCore/platform/android/FileSystemAndroid.cpp @@ -55,26 +55,25 @@ CString fileSystemRepresentation(const String& path) return path.utf8(); } -CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle) +String openTemporaryFile(const String& prefix, PlatformFileHandle& handle) { int number = rand() % 10000 + 1; - CString filename; + String filename; do { StringBuilder builder; builder.append(sPluginPath); builder.append('/'); builder.append(prefix); builder.append(String::number(number)); - filename = builder.toString().utf8(); - const char* fstr = filename.data(); - handle = open(filename.data(), O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); + filename = builder.toString(); + handle = open(filename.utf8().data(), O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); number++; if (handle != -1) return filename; } while (errno == EEXIST); - return CString(); + return String(); } bool unloadModule(PlatformModule module) @@ -87,30 +86,6 @@ String homeDirectoryPath() return sPluginPath; } -Vector<String> listDirectory(const String& path, const String& filter) -{ - Vector<String> entries; - CString cpath = path.utf8(); - CString cfilter = filter.utf8(); - DIR* dir = opendir(cpath.data()); - if (dir) { - struct dirent* dp; - while ((dp = readdir(dir))) { - const char* name = dp->d_name; - if (!strcmp(name, ".") || !strcmp(name, "..")) - continue; - if (fnmatch(cfilter.data(), name, 0)) - continue; - char filePath[1024]; - if (static_cast<int>(sizeof(filePath) - 1) < snprintf(filePath, sizeof(filePath), "%s/%s", cpath.data(), name)) - continue; // buffer overflow - entries.append(filePath); - } - closedir(dir); - } - return entries; -} - // We define our own pathGetFileName rather than use the POSIX versions as we // may get passed a content URI representing the path to the file. We pass // the input through fileSystemRepresentation before using it to resolve it if diff --git a/Source/WebCore/platform/android/LocalizedStringsAndroid.cpp b/Source/WebCore/platform/android/LocalizedStringsAndroid.cpp index 5a96cf6..e5a733a 100644 --- a/Source/WebCore/platform/android/LocalizedStringsAndroid.cpp +++ b/Source/WebCore/platform/android/LocalizedStringsAndroid.cpp @@ -230,7 +230,7 @@ String contextMenuItemTagSearchWeb() return String(); } -String contextMenuItemTagLookUpInDictionary() +String contextMenuItemTagLookUpInDictionary(const String&) { notImplemented(); return String(); diff --git a/Source/WebCore/platform/android/TemporaryLinkStubs.cpp b/Source/WebCore/platform/android/TemporaryLinkStubs.cpp index ede06dc..ca9f24d 100644 --- a/Source/WebCore/platform/android/TemporaryLinkStubs.cpp +++ b/Source/WebCore/platform/android/TemporaryLinkStubs.cpp @@ -396,7 +396,7 @@ PassRefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String&) #if USE(JSC) namespace JSC { namespace Bindings { -bool dispatchJNICall(ExecState*, const void* targetAppletView, jobject obj, bool isStatic, JNIType returnType, +bool dispatchJNICall(ExecState*, const void* targetAppletView, jobject obj, bool isStatic, JavaType returnType, jmethodID methodID, jvalue* args, jvalue& result, const char* callingURL, JSValue& exceptionDescription) { notImplemented(); diff --git a/Source/WebCore/platform/audio/AudioBus.cpp b/Source/WebCore/platform/audio/AudioBus.cpp index dd4746d..6f74471 100644 --- a/Source/WebCore/platform/audio/AudioBus.cpp +++ b/Source/WebCore/platform/audio/AudioBus.cpp @@ -32,6 +32,9 @@ #include "AudioBus.h" +#if !PLATFORM(MAC) +#include "SincResampler.h" +#endif #include "VectorMath.h" #include <algorithm> #include <assert.h> @@ -360,6 +363,90 @@ void AudioBus::sumWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, d processWithGainFrom(sourceBus, lastMixGain, targetGain, true); } +#if !PLATFORM(MAC) +PassOwnPtr<AudioBus> AudioBus::createBySampleRateConverting(AudioBus* sourceBus, bool mixToMono, double newSampleRate) +{ + // sourceBus's sample-rate must be known. + ASSERT(sourceBus && sourceBus->sampleRate()); + if (!sourceBus || !sourceBus->sampleRate()) + return 0; + + double sourceSampleRate = sourceBus->sampleRate(); + double destinationSampleRate = newSampleRate; + unsigned numberOfSourceChannels = sourceBus->numberOfChannels(); + + if (numberOfSourceChannels == 1) + mixToMono = false; // already mono + + if (sourceSampleRate == destinationSampleRate) { + // No sample-rate conversion is necessary. + if (mixToMono) + return AudioBus::createByMixingToMono(sourceBus); + + // Return exact copy. + return AudioBus::createBufferFromRange(sourceBus, 0, sourceBus->length()); + } + + // First, mix to mono (if necessary) then sample-rate convert. + AudioBus* resamplerSourceBus; + OwnPtr<AudioBus> mixedMonoBus; + if (mixToMono) { + mixedMonoBus = AudioBus::createByMixingToMono(sourceBus); + resamplerSourceBus = mixedMonoBus.get(); + } else { + // Directly resample without down-mixing. + resamplerSourceBus = sourceBus; + } + + // Calculate destination length based on the sample-rates. + double sampleRateRatio = sourceSampleRate / destinationSampleRate; + int sourceLength = resamplerSourceBus->length(); + int destinationLength = sourceLength / sampleRateRatio; + + // Create destination bus with same number of channels. + unsigned numberOfDestinationChannels = resamplerSourceBus->numberOfChannels(); + OwnPtr<AudioBus> destinationBus(adoptPtr(new AudioBus(numberOfDestinationChannels, destinationLength))); + + // Sample-rate convert each channel. + for (unsigned i = 0; i < numberOfDestinationChannels; ++i) { + float* source = resamplerSourceBus->channel(i)->data(); + float* destination = destinationBus->channel(i)->data(); + + SincResampler resampler(sampleRateRatio); + resampler.process(source, destination, sourceLength); + } + + return destinationBus.release(); +} +#endif // !PLATFORM(MAC) + +PassOwnPtr<AudioBus> AudioBus::createByMixingToMono(AudioBus* sourceBus) +{ + switch (sourceBus->numberOfChannels()) { + case 1: + // Simply create an exact copy. + return AudioBus::createBufferFromRange(sourceBus, 0, sourceBus->length()); + case 2: + { + unsigned n = sourceBus->length(); + OwnPtr<AudioBus> destinationBus(adoptPtr(new AudioBus(1, n))); + + float* sourceL = sourceBus->channel(0)->data(); + float* sourceR = sourceBus->channel(1)->data(); + float* destination = destinationBus->channel(0)->data(); + + // Do the mono mixdown. + for (unsigned i = 0; i < n; ++i) + destination[i] = 0.5 * (sourceL[i] + sourceR[i]); + + return destinationBus.release(); + } + } + + ASSERT_NOT_REACHED(); + return 0; +} + } // WebCore #endif // ENABLE(WEB_AUDIO) diff --git a/Source/WebCore/platform/audio/AudioBus.h b/Source/WebCore/platform/audio/AudioBus.h index 888f6bf..1943c0d 100644 --- a/Source/WebCore/platform/audio/AudioBus.h +++ b/Source/WebCore/platform/audio/AudioBus.h @@ -89,6 +89,18 @@ public: // 0 may be returned if the range does not fit in the sourceBuffer static PassOwnPtr<AudioBus> createBufferFromRange(AudioBus* sourceBuffer, unsigned startFrame, unsigned endFrame); + +#if !PLATFORM(MAC) + // Creates a new AudioBus by sample-rate converting sourceBus to the newSampleRate. + // setSampleRate() must have been previously called on sourceBus. + // Note: sample-rate conversion is already handled in the file-reading code for the mac port, so we don't need this. + static PassOwnPtr<AudioBus> createBySampleRateConverting(AudioBus* sourceBus, bool mixToMono, double newSampleRate); +#endif + + // Creates a new AudioBus by mixing all the channels down to mono. + // If sourceBus is already mono, then the returned AudioBus will simply be a copy. + static PassOwnPtr<AudioBus> createByMixingToMono(AudioBus* sourceBus); + // Scales all samples by the same amount. void scale(double scale); diff --git a/Source/WebCore/platform/audio/HRTFKernel.cpp b/Source/WebCore/platform/audio/HRTFKernel.cpp index 22d4b12..9db35ba 100644 --- a/Source/WebCore/platform/audio/HRTFKernel.cpp +++ b/Source/WebCore/platform/audio/HRTFKernel.cpp @@ -45,17 +45,18 @@ namespace WebCore { // This represents the initial delay before the most energetic part of the impulse response. // The sample-frame delay is removed from the impulseP impulse response, and this value is returned. // the length of the passed in AudioChannel must be a power of 2. -static double extractAverageGroupDelay(AudioChannel* channel) +static double extractAverageGroupDelay(AudioChannel* channel, size_t analysisFFTSize) { ASSERT(channel); float* impulseP = channel->data(); - size_t length = channel->length(); - // Check that length is power-of-2; - ASSERT(1UL << static_cast<unsigned>(log2(length)) == length); + ASSERT(channel->length() >= analysisFFTSize); + + // Check for power-of-2. + ASSERT(1UL << static_cast<unsigned>(log2(analysisFFTSize)) == analysisFFTSize); - FFTFrame estimationFrame(length); + FFTFrame estimationFrame(analysisFFTSize); estimationFrame.doFFT(impulseP); double frameDelay = estimationFrame.extractAverageGroupDelay(); @@ -71,7 +72,7 @@ HRTFKernel::HRTFKernel(AudioChannel* channel, size_t fftSize, double sampleRate, ASSERT(channel); // Determine the leading delay (average group delay) for the response. - m_frameDelay = extractAverageGroupDelay(channel); + m_frameDelay = extractAverageGroupDelay(channel, fftSize / 2); float* impulseResponse = channel->data(); size_t responseLength = channel->length(); diff --git a/Source/WebCore/platform/audio/SincResampler.cpp b/Source/WebCore/platform/audio/SincResampler.cpp new file mode 100644 index 0000000..e6f34b4 --- /dev/null +++ b/Source/WebCore/platform/audio/SincResampler.cpp @@ -0,0 +1,342 @@ +/* + * 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(WEB_AUDIO) + +#include "SincResampler.h" + +#include <wtf/MathExtras.h> + +using namespace std; + +// Input buffer layout, dividing the total buffer into regions (r0 - r5): +// +// |----------------|----------------------------------------------------------------|----------------| +// +// blockSize + kernelSize / 2 +// <--------------------------------------------------------------------------------> +// r0 +// +// kernelSize / 2 kernelSize / 2 kernelSize / 2 kernelSize / 2 +// <---------------> <---------------> <---------------> <---------------> +// r1 r2 r3 r4 +// +// blockSize +// <--------------------------------------------------------------> +// r5 + +// The Algorithm: +// +// 1) Consume input frames into r0 (r1 is zero-initialized). +// 2) Position kernel centered at start of r0 (r2) and generate output frames until kernel is centered at start of r4. +// or we've finished generating all the output frames. +// 3) Copy r3 to r1 and r4 to r2. +// 4) Consume input frames into r5 (zero-pad if we run out of input). +// 5) Goto (2) until all of input is consumed. +// +// note: we're glossing over how the sub-sample handling works with m_virtualSourceIndex, etc. + +namespace WebCore { + +SincResampler::SincResampler(double scaleFactor, unsigned kernelSize, unsigned numberOfKernelOffsets) + : m_scaleFactor(scaleFactor) + , m_kernelSize(kernelSize) + , m_numberOfKernelOffsets(numberOfKernelOffsets) + , m_kernelStorage(m_kernelSize * (m_numberOfKernelOffsets + 1)) + , m_virtualSourceIndex(0.0) + , m_blockSize(512) + , m_inputBuffer(m_blockSize + m_kernelSize) // See input buffer layout above. + , m_source(0) + , m_sourceFramesAvailable(0) +{ + initializeKernel(); +} + +void SincResampler::initializeKernel() +{ + // Blackman window parameters. + double alpha = 0.16; + double a0 = 0.5 * (1.0 - alpha); + double a1 = 0.5; + double a2 = 0.5 * alpha; + + // sincScaleFactor is basically the normalized cutoff frequency of the low-pass filter. + double sincScaleFactor = m_scaleFactor > 1.0 ? 1.0 / m_scaleFactor : 1.0; + + // The sinc function is an idealized brick-wall filter, but since we're windowing it the + // transition from pass to stop does not happen right away. So we should adjust the + // lowpass filter cutoff slightly downward to avoid some aliasing at the very high-end. + // FIXME: this value is empirical and to be more exact should vary depending on m_kernelSize. + sincScaleFactor *= 0.9; + + int n = m_kernelSize; + int halfSize = n / 2; + + // Generates a set of windowed sinc() kernels. + // We generate a range of sub-sample offsets from 0.0 to 1.0. + for (unsigned offsetIndex = 0; offsetIndex <= m_numberOfKernelOffsets; ++offsetIndex) { + double subsampleOffset = static_cast<double>(offsetIndex) / m_numberOfKernelOffsets; + + for (int i = 0; i < n; ++i) { + // Compute the sinc() with offset. + double s = sincScaleFactor * piDouble * (i - halfSize - subsampleOffset); + double sinc = !s ? 1.0 : sin(s) / s; + sinc *= sincScaleFactor; + + // Compute Blackman window, matching the offset of the sinc(). + double x = (i - subsampleOffset) / n; + double window = a0 - a1 * cos(2.0 * piDouble * x) + a2 * cos(4.0 * piDouble * x); + + // Window the sinc() function and store at the correct offset. + m_kernelStorage[i + offsetIndex * m_kernelSize] = sinc * window; + } + } +} + +void SincResampler::consumeSource(float* buffer, unsigned numberOfSourceFrames) +{ + ASSERT(m_source); + if (!m_source) + return; + + // Clamp to number of frames available and zero-pad. + unsigned framesToCopy = min(m_sourceFramesAvailable, numberOfSourceFrames); + memcpy(buffer, m_source, sizeof(float) * framesToCopy); + + // Zero-pad if necessary. + if (framesToCopy < numberOfSourceFrames) + memset(buffer + framesToCopy, 0, sizeof(float) * (numberOfSourceFrames - framesToCopy)); + + m_sourceFramesAvailable -= framesToCopy; + m_source += numberOfSourceFrames; +} + +void SincResampler::process(float* source, float* destination, unsigned numberOfSourceFrames) +{ + ASSERT(m_blockSize > m_kernelSize); + ASSERT(m_inputBuffer.size() >= m_blockSize + m_kernelSize); + ASSERT(!(m_kernelSize % 2)); + + // Setup various region pointers in the buffer (see diagram above). + float* r0 = m_inputBuffer.data() + m_kernelSize / 2; + float* r1 = m_inputBuffer.data(); + float* r2 = r0; + float* r3 = r0 + m_blockSize - m_kernelSize / 2; + float* r4 = r0 + m_blockSize; + float* r5 = r0 + m_kernelSize / 2; + + m_source = source; + m_sourceFramesAvailable = numberOfSourceFrames; + + unsigned numberOfDestinationFrames = static_cast<unsigned>(numberOfSourceFrames / m_scaleFactor); + + // Step (1) + // Prime the input buffer. + consumeSource(r0, m_blockSize + m_kernelSize / 2); + + // Step (2) + m_virtualSourceIndex = 0; + + while (numberOfDestinationFrames) { + while (m_virtualSourceIndex < m_blockSize) { + // m_virtualSourceIndex lies in between two kernel offsets so figure out what they are. + int sourceIndexI = static_cast<int>(m_virtualSourceIndex); + double subsampleRemainder = m_virtualSourceIndex - sourceIndexI; + + double virtualOffsetIndex = subsampleRemainder * m_numberOfKernelOffsets; + int offsetIndex = static_cast<int>(virtualOffsetIndex); + + float* k1 = m_kernelStorage.data() + offsetIndex * m_kernelSize; + float* k2 = k1 + m_kernelSize; + + // Initialize input pointer based on quantized m_virtualSourceIndex. + float* inputP = r1 + sourceIndexI; + + // We'll compute "convolutions" for the two kernels which straddle m_virtualSourceIndex + float sum1 = 0; + float sum2 = 0; + + // Figure out how much to weight each kernel's "convolution". + double kernelInterpolationFactor = virtualOffsetIndex - offsetIndex; + + // Generate a single output sample. + int n = m_kernelSize; + + // FIXME: add SIMD optimizations for the following. The scalar code-path can probably also be optimized better. + +#define CONVOLVE_ONE_SAMPLE \ + input = *inputP++; \ + sum1 += input * *k1; \ + sum2 += input * *k2; \ + ++k1; \ + ++k2; + + { + float input; + + // Optimize size 32 and size 64 kernels by unrolling the while loop. + // A 20 - 30% speed improvement was measured in some cases by using this approach. + + if (n == 32) { + CONVOLVE_ONE_SAMPLE // 1 + CONVOLVE_ONE_SAMPLE // 2 + CONVOLVE_ONE_SAMPLE // 3 + CONVOLVE_ONE_SAMPLE // 4 + CONVOLVE_ONE_SAMPLE // 5 + CONVOLVE_ONE_SAMPLE // 6 + CONVOLVE_ONE_SAMPLE // 7 + CONVOLVE_ONE_SAMPLE // 8 + CONVOLVE_ONE_SAMPLE // 9 + CONVOLVE_ONE_SAMPLE // 10 + CONVOLVE_ONE_SAMPLE // 11 + CONVOLVE_ONE_SAMPLE // 12 + CONVOLVE_ONE_SAMPLE // 13 + CONVOLVE_ONE_SAMPLE // 14 + CONVOLVE_ONE_SAMPLE // 15 + CONVOLVE_ONE_SAMPLE // 16 + CONVOLVE_ONE_SAMPLE // 17 + CONVOLVE_ONE_SAMPLE // 18 + CONVOLVE_ONE_SAMPLE // 19 + CONVOLVE_ONE_SAMPLE // 20 + CONVOLVE_ONE_SAMPLE // 21 + CONVOLVE_ONE_SAMPLE // 22 + CONVOLVE_ONE_SAMPLE // 23 + CONVOLVE_ONE_SAMPLE // 24 + CONVOLVE_ONE_SAMPLE // 25 + CONVOLVE_ONE_SAMPLE // 26 + CONVOLVE_ONE_SAMPLE // 27 + CONVOLVE_ONE_SAMPLE // 28 + CONVOLVE_ONE_SAMPLE // 29 + CONVOLVE_ONE_SAMPLE // 30 + CONVOLVE_ONE_SAMPLE // 31 + CONVOLVE_ONE_SAMPLE // 32 + } else if (n == 64) { + CONVOLVE_ONE_SAMPLE // 1 + CONVOLVE_ONE_SAMPLE // 2 + CONVOLVE_ONE_SAMPLE // 3 + CONVOLVE_ONE_SAMPLE // 4 + CONVOLVE_ONE_SAMPLE // 5 + CONVOLVE_ONE_SAMPLE // 6 + CONVOLVE_ONE_SAMPLE // 7 + CONVOLVE_ONE_SAMPLE // 8 + CONVOLVE_ONE_SAMPLE // 9 + CONVOLVE_ONE_SAMPLE // 10 + CONVOLVE_ONE_SAMPLE // 11 + CONVOLVE_ONE_SAMPLE // 12 + CONVOLVE_ONE_SAMPLE // 13 + CONVOLVE_ONE_SAMPLE // 14 + CONVOLVE_ONE_SAMPLE // 15 + CONVOLVE_ONE_SAMPLE // 16 + CONVOLVE_ONE_SAMPLE // 17 + CONVOLVE_ONE_SAMPLE // 18 + CONVOLVE_ONE_SAMPLE // 19 + CONVOLVE_ONE_SAMPLE // 20 + CONVOLVE_ONE_SAMPLE // 21 + CONVOLVE_ONE_SAMPLE // 22 + CONVOLVE_ONE_SAMPLE // 23 + CONVOLVE_ONE_SAMPLE // 24 + CONVOLVE_ONE_SAMPLE // 25 + CONVOLVE_ONE_SAMPLE // 26 + CONVOLVE_ONE_SAMPLE // 27 + CONVOLVE_ONE_SAMPLE // 28 + CONVOLVE_ONE_SAMPLE // 29 + CONVOLVE_ONE_SAMPLE // 30 + CONVOLVE_ONE_SAMPLE // 31 + CONVOLVE_ONE_SAMPLE // 32 + CONVOLVE_ONE_SAMPLE // 33 + CONVOLVE_ONE_SAMPLE // 34 + CONVOLVE_ONE_SAMPLE // 35 + CONVOLVE_ONE_SAMPLE // 36 + CONVOLVE_ONE_SAMPLE // 37 + CONVOLVE_ONE_SAMPLE // 38 + CONVOLVE_ONE_SAMPLE // 39 + CONVOLVE_ONE_SAMPLE // 40 + CONVOLVE_ONE_SAMPLE // 41 + CONVOLVE_ONE_SAMPLE // 42 + CONVOLVE_ONE_SAMPLE // 43 + CONVOLVE_ONE_SAMPLE // 44 + CONVOLVE_ONE_SAMPLE // 45 + CONVOLVE_ONE_SAMPLE // 46 + CONVOLVE_ONE_SAMPLE // 47 + CONVOLVE_ONE_SAMPLE // 48 + CONVOLVE_ONE_SAMPLE // 49 + CONVOLVE_ONE_SAMPLE // 50 + CONVOLVE_ONE_SAMPLE // 51 + CONVOLVE_ONE_SAMPLE // 52 + CONVOLVE_ONE_SAMPLE // 53 + CONVOLVE_ONE_SAMPLE // 54 + CONVOLVE_ONE_SAMPLE // 55 + CONVOLVE_ONE_SAMPLE // 56 + CONVOLVE_ONE_SAMPLE // 57 + CONVOLVE_ONE_SAMPLE // 58 + CONVOLVE_ONE_SAMPLE // 59 + CONVOLVE_ONE_SAMPLE // 60 + CONVOLVE_ONE_SAMPLE // 61 + CONVOLVE_ONE_SAMPLE // 62 + CONVOLVE_ONE_SAMPLE // 63 + CONVOLVE_ONE_SAMPLE // 64 + } else { + while (n--) { + // Non-optimized using actual while loop. + CONVOLVE_ONE_SAMPLE + } + } + } + + // Linearly interpolate the two "convolutions". + double result = (1.0 - kernelInterpolationFactor) * sum1 + kernelInterpolationFactor * sum2; + + *destination++ = result; + + --numberOfDestinationFrames; + if (!numberOfDestinationFrames) + return; + + // Advance the virtual index. + m_virtualSourceIndex += m_scaleFactor; + } + + // Wrap back around to the start. + m_virtualSourceIndex -= m_blockSize; + + // Step (3) Copy r3 to r1 and r4 to r2. + // This wraps the last input frames back to the start of the buffer. + memcpy(r1, r3, sizeof(float) * (m_kernelSize / 2)); + memcpy(r2, r4, sizeof(float) * (m_kernelSize / 2)); + + // Step (4) + // Refresh the buffer with more input. + consumeSource(r5, m_blockSize); + } +} + +} // namespace WebCore + +#endif // ENABLE(WEB_AUDIO) diff --git a/Source/WebCore/platform/audio/SincResampler.h b/Source/WebCore/platform/audio/SincResampler.h new file mode 100644 index 0000000..92adb95 --- /dev/null +++ b/Source/WebCore/platform/audio/SincResampler.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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SincResampler_h +#define SincResampler_h + +#include "AudioArray.h" + +namespace WebCore { + +// SincResampler is a high-quality sample-rate converter. + +class SincResampler { +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); + + // Processes numberOfSourceFrames from source to produce numberOfSourceFrames / scaleFactor frames in destination. + void process(float* source, float* destination, unsigned numberOfSourceFrames); + + // FIXME: we can add a process() method which takes an input source callback function for streaming applications + // where the entire input buffer is not all available. + +protected: + void initializeKernel(); + void consumeSource(float* buffer, unsigned numberOfSourceFrames); + + double m_scaleFactor; + unsigned m_kernelSize; + unsigned m_numberOfKernelOffsets; + + // m_kernelStorage has m_numberOfKernelOffsets kernels back-to-back, each of size m_kernelSize. + // The kernel offsets are sub-sample shifts of a windowed sinc() shifted from 0.0 to 1.0 sample. + AudioFloatArray m_kernelStorage; + + // m_virtualSourceIndex is an index on the source input buffer with sub-sample precision. + // It must be double precision to avoid drift. + double m_virtualSourceIndex; + + // This is the number of destination frames we generate per processing pass on the buffer. + unsigned m_blockSize; + + // Source is copied into this buffer for each processing pass. + AudioFloatArray m_inputBuffer; + + float* m_source; + unsigned m_sourceFramesAvailable; +}; + +} // namespace WebCore + +#endif // SincResampler_h diff --git a/Source/WebCore/platform/audio/chromium/AudioBusChromium.cpp b/Source/WebCore/platform/audio/chromium/AudioBusChromium.cpp index de44b1c..f34dc77 100644 --- a/Source/WebCore/platform/audio/chromium/AudioBusChromium.cpp +++ b/Source/WebCore/platform/audio/chromium/AudioBusChromium.cpp @@ -36,22 +36,30 @@ namespace WebCore { PassOwnPtr<AudioBus> AudioBus::loadPlatformResource(const char* name, double sampleRate) { - return PlatformBridge::loadPlatformAudioResource(name, sampleRate); + // FIXME: the sampleRate parameter is ignored. It should be removed from the API. + OwnPtr<AudioBus> audioBus = PlatformBridge::loadPlatformAudioResource(name, sampleRate); + if (!audioBus.get()) + return 0; + + // If the bus is already at the requested sample-rate then return as is. + if (audioBus->sampleRate() == sampleRate) + return audioBus.release(); + + return AudioBus::createBySampleRateConverting(audioBus.get(), false, sampleRate); } PassOwnPtr<AudioBus> createBusFromInMemoryAudioFile(const void* data, size_t dataSize, bool mixToMono, double sampleRate) { + // FIXME: the sampleRate parameter is ignored. It should be removed from the API. OwnPtr<AudioBus> audioBus = PlatformBridge::decodeAudioFileData(static_cast<const char*>(data), dataSize, sampleRate); - if (audioBus.get() && audioBus->numberOfChannels() == 2 && mixToMono) { - OwnPtr<AudioBus> monoAudioBus = adoptPtr(new AudioBus(1, audioBus->length())); - - // FIXME: AudioBus::copyFrom() should be able to do a downmix to mono. - // for now simply copy the left channel. - monoAudioBus->channel(0)->copyFrom(audioBus->channel(0)); - return monoAudioBus.release(); - } + if (!audioBus.get()) + return 0; + + // If the bus needs no conversion then return as is. + if ((!mixToMono || audioBus->numberOfChannels() == 1) && audioBus->sampleRate() == sampleRate) + return audioBus.release(); - return audioBus.release(); + return AudioBus::createBySampleRateConverting(audioBus.get(), mixToMono, sampleRate); } } // namespace WebCore diff --git a/Source/WebCore/platform/audio/mac/AudioDestinationMac.cpp b/Source/WebCore/platform/audio/mac/AudioDestinationMac.cpp index 523729f..d4ecaba 100644 --- a/Source/WebCore/platform/audio/mac/AudioDestinationMac.cpp +++ b/Source/WebCore/platform/audio/mac/AudioDestinationMac.cpp @@ -51,8 +51,8 @@ double AudioDestination::hardwareSampleRate() AudioDeviceID deviceID = kAudioDeviceUnknown; UInt32 infoSize = sizeof(deviceID); - AudioObjectPropertyAddress defaultInputDeviceAddress = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; - OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &defaultInputDeviceAddress, 0, 0, &infoSize, (void*)&deviceID); + AudioObjectPropertyAddress defaultOutputDeviceAddress = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; + OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &defaultOutputDeviceAddress, 0, 0, &infoSize, (void*)&deviceID); if (result) return 0.0; // error diff --git a/Source/WebCore/platform/brew/FileSystemBrew.cpp b/Source/WebCore/platform/brew/FileSystemBrew.cpp index 61d568d..251c004 100644 --- a/Source/WebCore/platform/brew/FileSystemBrew.cpp +++ b/Source/WebCore/platform/brew/FileSystemBrew.cpp @@ -186,7 +186,7 @@ String directoryName(const String& path) return dirName; } -CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle) +String openTemporaryFile(const String& prefix, PlatformFileHandle& handle) { // BREW does not have a system-wide temporary directory, // use "fs:/~/tmp" as our temporary directory. @@ -199,24 +199,24 @@ CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle) // Loop until we find a temporary filename that does not exist. int number = static_cast<int>(randomNumber() * 10000); - CString filename; + String filename; do { StringBuilder builder; builder.append(tempPath); builder.append('/'); builder.append(prefix); builder.append(String::number(number)); - filename = builder.toString().utf8(); + filename = builder.toString(); number++; - } while (IFILEMGR_Test(fileMgr.get(), filename.data()) == SUCCESS); + } while (IFILEMGR_Test(fileMgr.get(), filename.utf8().data()) == SUCCESS); - IFile* tempFile = IFILEMGR_OpenFile(fileMgr.get(), filename.data(), _OFM_CREATE); + IFile* tempFile = IFILEMGR_OpenFile(fileMgr.get(), filename.utf8().data(), _OFM_CREATE); if (tempFile) { handle = tempFile; return filename; } - return CString(); + return String(); } void closeFile(PlatformFileHandle& handle) diff --git a/Source/WebCore/platform/brew/LocalizedStringsBrew.cpp b/Source/WebCore/platform/brew/LocalizedStringsBrew.cpp index c4dac1a..ba5d4a9 100644 --- a/Source/WebCore/platform/brew/LocalizedStringsBrew.cpp +++ b/Source/WebCore/platform/brew/LocalizedStringsBrew.cpp @@ -206,7 +206,7 @@ String contextMenuItemTagSearchWeb() return "Search web"; } -String contextMenuItemTagLookUpInDictionary() +String contextMenuItemTagLookUpInDictionary(const String&) { return "Lookup in dictionary"; } diff --git a/Source/WebCore/platform/cf/BinaryPropertyList.cpp b/Source/WebCore/platform/cf/BinaryPropertyList.cpp index 41769e8..65be70a 100644 --- a/Source/WebCore/platform/cf/BinaryPropertyList.cpp +++ b/Source/WebCore/platform/cf/BinaryPropertyList.cpp @@ -92,7 +92,7 @@ struct IntegerArrayHash { unsigned IntegerArrayHash::hash(const IntegerArray& array) { - return WTF::StringHasher::createBlobHash(array.integers(), array.size()); + return StringHasher::hashMemory(array.integers(), array.size() * sizeof(int)); } bool IntegerArrayHash::equal(const IntegerArray& a, const IntegerArray& b) diff --git a/Source/WebCore/platform/cf/SchedulePair.h b/Source/WebCore/platform/cf/SchedulePair.h index 8361856..cb34d7d 100644 --- a/Source/WebCore/platform/cf/SchedulePair.h +++ b/Source/WebCore/platform/cf/SchedulePair.h @@ -73,7 +73,7 @@ struct SchedulePairHash { static unsigned hash(const RefPtr<SchedulePair>& pair) { uintptr_t hashCodes[2] = { reinterpret_cast<uintptr_t>(pair->runLoop()), pair->mode() ? CFHash(pair->mode()) : 0 }; - return WTF::StringHasher::createBlobHash<sizeof(hashCodes)>(hashCodes); + return StringHasher::hashMemory<sizeof(hashCodes)>(hashCodes); } static bool equal(const RefPtr<SchedulePair>& a, const RefPtr<SchedulePair>& b) { return a == b; } diff --git a/Source/WebCore/platform/cf/SharedBufferCF.cpp b/Source/WebCore/platform/cf/SharedBufferCF.cpp index 18a65c2..319f484 100644 --- a/Source/WebCore/platform/cf/SharedBufferCF.cpp +++ b/Source/WebCore/platform/cf/SharedBufferCF.cpp @@ -91,4 +91,30 @@ void SharedBuffer::clearPlatformData() m_cfData = 0; } +#if HAVE(CFNETWORK_DATA_ARRAY_CALLBACK) +void SharedBuffer::append(CFDataRef data) +{ + ASSERT(data); + m_dataArray.append(data); + m_size += CFDataGetLength(data); +} + +void SharedBuffer::copyDataArrayAndClear(char *destination, unsigned bytesToCopy) const +{ + if (m_dataArray.isEmpty()) + return; + + CFIndex bytesLeft = bytesToCopy; + Vector<RetainPtr<CFDataRef> >::const_iterator end = m_dataArray.end(); + for (Vector<RetainPtr<CFDataRef> >::const_iterator it = m_dataArray.begin(); it != end; ++it) { + CFIndex dataLen = CFDataGetLength(it->get()); + ASSERT(bytesLeft >= dataLen); + memcpy(destination, CFDataGetBytePtr(it->get()), dataLen); + destination += dataLen; + bytesLeft -= dataLen; + } + m_dataArray.clear(); +} +#endif + } diff --git a/Source/WebCore/platform/cf/win/CertificateCFWin.cpp b/Source/WebCore/platform/cf/win/CertificateCFWin.cpp new file mode 100644 index 0000000..88ea933 --- /dev/null +++ b/Source/WebCore/platform/cf/win/CertificateCFWin.cpp @@ -0,0 +1,52 @@ +/* + * 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 "CertificateCFWin.h" + +namespace WebCore { + +static void deallocCertContext(void* ptr, void* info) +{ + if (ptr) + CertFreeCertificateContext(static_cast<PCCERT_CONTEXT>(ptr)); +} + +static CFAllocatorRef createCertContextDeallocator() +{ + CFAllocatorContext allocContext = { + 0, 0, 0, 0, 0, 0, 0, deallocCertContext, 0 + }; + return CFAllocatorCreate(kCFAllocatorDefault, &allocContext); +} + +RetainPtr<CFDataRef> copyCertificateToData(PCCERT_CONTEXT certificate) +{ + static CFAllocatorRef certDealloc = createCertContextDeallocator(); + PCCERT_CONTEXT certificateCopy = CertDuplicateCertificateContext(certificate); + return RetainPtr<CFDataRef>(AdoptCF, CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(certificateCopy), sizeof(*certificateCopy), certDealloc)); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/cf/win/CertificateCFWin.h b/Source/WebCore/platform/cf/win/CertificateCFWin.h new file mode 100644 index 0000000..b3ada0d --- /dev/null +++ b/Source/WebCore/platform/cf/win/CertificateCFWin.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#ifndef CertificateCFWin_h +#define CertificateCFWin_h + +#include <windows.h> +#include <wtf/RetainPtr.h> + +namespace WebCore { + +RetainPtr<CFDataRef> copyCertificateToData(PCCERT_CONTEXT); + +} // namespace WebCore + +#endif // CertificateCFWin_h diff --git a/Source/WebCore/platform/chromium/ClipboardChromium.cpp b/Source/WebCore/platform/chromium/ClipboardChromium.cpp index 7e58f03..6756313 100644 --- a/Source/WebCore/platform/chromium/ClipboardChromium.cpp +++ b/Source/WebCore/platform/chromium/ClipboardChromium.cpp @@ -31,6 +31,7 @@ #include "ChromiumDataObject.h" #include "ClipboardMimeTypes.h" #include "ClipboardUtilitiesChromium.h" +#include "DataTransferItemsChromium.h" #include "Document.h" #include "DragData.h" #include "Element.h" @@ -342,4 +343,22 @@ bool ClipboardChromium::hasData() return m_dataObject->hasData(); } +#if ENABLE(DATA_TRANSFER_ITEMS) +PassRefPtr<DataTransferItems> ClipboardChromium::items() +{ + RefPtr<DataTransferItemsChromium> items = DataTransferItemsChromium::create(this, m_frame->document()->scriptExecutionContext()); + + if (!m_dataObject) + return items; + + if (isForCopyAndPaste() && policy() == ClipboardReadable) { + // Iterate through the types and add them. + HashSet<String> types = m_dataObject->types(); + for (HashSet<String>::const_iterator it = types.begin(); it != types.end(); ++it) + items->addPasteboardItem(*it); + } + return items; +} +#endif + } // namespace WebCore diff --git a/Source/WebCore/platform/chromium/ClipboardChromium.h b/Source/WebCore/platform/chromium/ClipboardChromium.h index d30a1c4..61db0a5 100644 --- a/Source/WebCore/platform/chromium/ClipboardChromium.h +++ b/Source/WebCore/platform/chromium/ClipboardChromium.h @@ -80,6 +80,10 @@ namespace WebCore { virtual bool hasData(); +#if ENABLE(DATA_TRANSFER_ITEMS) + virtual PassRefPtr<DataTransferItems> items(); +#endif + private: ClipboardChromium(ClipboardType, PassRefPtr<ChromiumDataObject>, ClipboardAccessPolicy, Frame*); diff --git a/Source/WebCore/platform/chromium/DataTransferItemChromium.cpp b/Source/WebCore/platform/chromium/DataTransferItemChromium.cpp new file mode 100644 index 0000000..7857336 --- /dev/null +++ b/Source/WebCore/platform/chromium/DataTransferItemChromium.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DataTransferItemChromium.h" + +#if ENABLE(DATA_TRANSFER_ITEMS) + +#include "Clipboard.h" +#include "ClipboardMimeTypes.h" +#include "PlatformBridge.h" +#include "StringCallback.h" + +namespace WebCore { + +PassRefPtr<DataTransferItemChromium> DataTransferItemChromium::createFromPasteboard(PassRefPtr<Clipboard> owner, ScriptExecutionContext* context, const String& type) +{ + if (type == mimeTypeTextPlain || type == mimeTypeTextHTML) + return adoptRef(new DataTransferItemChromium(owner, context, PasteboardSource, DataTransferItem::kindString, type, "")); + return adoptRef(new DataTransferItemChromium(owner, context, PasteboardSource, DataTransferItem::kindFile, type, "")); +} + +PassRefPtr<DataTransferItemChromium> DataTransferItemChromium::create(PassRefPtr<Clipboard> owner, + ScriptExecutionContext* context, + const String& data, + const String& type) +{ + return adoptRef(new DataTransferItemChromium(owner, context, InternalSource, DataTransferItem::kindString, type, data)); +} + +DataTransferItemChromium::DataTransferItemChromium(PassRefPtr<Clipboard> owner, ScriptExecutionContext* context, DataSource source, const String& kind, const String& type, const String& data) + : m_owner(owner) + , m_context(context) + , m_source(source) + , m_kind(kind) + , m_type(type) + , m_data(data) +{ +} + +String DataTransferItemChromium::kind() const +{ + if (m_owner->policy() == ClipboardNumb) + return String(); + return m_kind; +} + +String DataTransferItemChromium::type() const +{ + if (m_owner->policy() == ClipboardNumb) + return String(); + return m_type; +} + +void DataTransferItemChromium::getAsString(PassRefPtr<StringCallback> callback) +{ + if ((m_owner->policy() != ClipboardReadable && m_owner->policy() != ClipboardWritable) + || m_kind != kindString) + return; + if (m_source == InternalSource) { + callback->scheduleCallback(m_context, m_data); + return; + } + // This is ugly but there's no real alternative. + if (m_type == mimeTypeTextPlain) { + callback->scheduleCallback(m_context, PlatformBridge::clipboardReadPlainText(PasteboardPrivate::StandardBuffer)); + return; + } + if (m_type == mimeTypeTextHTML) { + String html; + KURL ignoredSourceURL; + PlatformBridge::clipboardReadHTML(PasteboardPrivate::StandardBuffer, &html, &ignoredSourceURL); + callback->scheduleCallback(m_context, html); + return; + } + ASSERT_NOT_REACHED(); +} + +} // namespace WebCore + +#endif // ENABLE(DATA_TRANSFER_ITEMS) diff --git a/Source/WebCore/platform/chromium/DataTransferItemChromium.h b/Source/WebCore/platform/chromium/DataTransferItemChromium.h new file mode 100644 index 0000000..77f74f2 --- /dev/null +++ b/Source/WebCore/platform/chromium/DataTransferItemChromium.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: + * + * * 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 DataTransferItemChromium_h +#define DataTransferItemChromium_h + +#if ENABLE(DATA_TRANSFER_ITEMS) + +#include "DataTransferItem.h" +#include <wtf/RefPtr.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class Clipboard; +class ScriptExecutionContext; + +class DataTransferItemChromium : public DataTransferItem { +public: + static PassRefPtr<DataTransferItemChromium> createFromPasteboard(PassRefPtr<Clipboard> owner, ScriptExecutionContext*, const String& type); + static PassRefPtr<DataTransferItemChromium> create(PassRefPtr<Clipboard> owner, ScriptExecutionContext*, const String& data, const String& type); + + virtual String kind() const; + virtual String type() const; + + virtual void getAsString(PassRefPtr<StringCallback>); + +private: + enum DataSource { + PasteboardSource, + InternalSource, + }; + + DataTransferItemChromium(PassRefPtr<Clipboard> owner, ScriptExecutionContext*, DataSource, const String& kind, const String& type, const String& data); + + const RefPtr<Clipboard> m_owner; + ScriptExecutionContext* m_context; + const DataSource m_source; + const String m_kind; + const String m_type; + const String m_data; +}; + +} // namespace WebCore + +#endif // ENABLE(DATA_TRANSFER_ITEMS) + +#endif // DataTransferItem_h diff --git a/Source/WebCore/platform/chromium/DataTransferItemsChromium.cpp b/Source/WebCore/platform/chromium/DataTransferItemsChromium.cpp new file mode 100644 index 0000000..418b8b5 --- /dev/null +++ b/Source/WebCore/platform/chromium/DataTransferItemsChromium.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DataTransferItemsChromium.h" + +#if ENABLE(DATA_TRANSFER_ITEMS) + +#include "Clipboard.h" +#include "DataTransferItemChromium.h" +#include "ExceptionCode.h" + +namespace WebCore { + +PassRefPtr<DataTransferItemsChromium> DataTransferItemsChromium::create(PassRefPtr<Clipboard> owner, ScriptExecutionContext* context) +{ + return adoptRef(new DataTransferItemsChromium(owner, context)); +} + +DataTransferItemsChromium::DataTransferItemsChromium(PassRefPtr<Clipboard> owner, ScriptExecutionContext* context) + : m_owner(owner) + , m_context(context) +{ +} + +unsigned long DataTransferItemsChromium::length() const +{ + if (m_owner->policy() == ClipboardNumb) + return 0; + return m_items.size(); +} + +PassRefPtr<DataTransferItem> DataTransferItemsChromium::item(unsigned long index) const +{ + if (m_owner->policy() == ClipboardNumb || index >= length()) + return 0; + return m_items[index]; +} + +void DataTransferItemsChromium::deleteItem(unsigned long index, ExceptionCode& ec) +{ + if (m_owner->policy() != ClipboardWritable) { + ec = INVALID_STATE_ERR; + return; + } + + if (index >= length()) + return; + + m_items.remove(index); +} + +void DataTransferItemsChromium::clear() +{ + if (m_owner->policy() != ClipboardWritable) + return; + + m_items.clear(); +} + +void DataTransferItemsChromium::add(const String& data, const String& type, ExceptionCode& ec) +{ + if (m_owner->policy() != ClipboardWritable) + return; + + // Only one 'string' item with a given type is allowed in the collection. + for (size_t i = 0; i < m_items.size(); ++i) { + if (m_items[i]->type() == type && m_items[i]->kind() == DataTransferItem::kindString) { + ec = INVALID_STATE_ERR; + return; + } + } + + m_items.append(DataTransferItemChromium::create(m_owner, m_context, data, type)); +} + +void DataTransferItemsChromium::addPasteboardItem(const String& type) +{ + m_items.append(DataTransferItemChromium::createFromPasteboard(m_owner, m_context, type)); +} + +} // namespace WebCore + +#endif // ENABLE(DATA_TRANSFER_ITEMS) diff --git a/Source/WebCore/platform/chromium/DataTransferItemsChromium.h b/Source/WebCore/platform/chromium/DataTransferItemsChromium.h new file mode 100644 index 0000000..51c4fdb --- /dev/null +++ b/Source/WebCore/platform/chromium/DataTransferItemsChromium.h @@ -0,0 +1,77 @@ +/* + * 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 DataTransferItemsChromium_h +#define DataTransferItemsChromium_h + +#if ENABLE(DATA_TRANSFER_ITEMS) + +#include "DataTransferItems.h" +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class Clipboard; +class DataTransferItemChromium; +class ScriptExecutionContext; + +typedef int ExceptionCode; + +class DataTransferItemsChromium : public DataTransferItems { +public: + static PassRefPtr<DataTransferItemsChromium> create(PassRefPtr<Clipboard>, ScriptExecutionContext*); + + virtual unsigned long length() const; + virtual PassRefPtr<DataTransferItem> item(unsigned long index) const; + virtual void deleteItem(unsigned long index, ExceptionCode&); + virtual void clear(); + + virtual void add(const String& data, const String& type, ExceptionCode&); + +private: + friend class ClipboardChromium; + + DataTransferItemsChromium(PassRefPtr<Clipboard>, ScriptExecutionContext*); + + virtual void addPasteboardItem(const String& type); + + RefPtr<Clipboard> m_owner; + // Indirectly owned by our parent. + ScriptExecutionContext* m_context; + Vector<RefPtr<DataTransferItemChromium> > m_items; +}; + +} // namespace WebCore + +#endif // ENABLE(DATA_TRANSFER_ITEMS) + +#endif // DataTransferItemsChromium_h + diff --git a/Source/WebCore/platform/chromium/FileSystemChromium.cpp b/Source/WebCore/platform/chromium/FileSystemChromium.cpp index faf5e92..5e03c5b 100644 --- a/Source/WebCore/platform/chromium/FileSystemChromium.cpp +++ b/Source/WebCore/platform/chromium/FileSystemChromium.cpp @@ -112,4 +112,11 @@ int writeToFile(PlatformFileHandle handle, const char* data, int length) return PlatformBridge::writeToFile(handle, data, length); } +Vector<String> listDirectory(const String& path, const String& filter) +{ + notImplemented(); + + return Vector<String>(); +} + } // namespace WebCore diff --git a/Source/WebCore/platform/chromium/PasteboardPrivate.h b/Source/WebCore/platform/chromium/PasteboardPrivate.h index 1de7fe3..5f167ba 100644 --- a/Source/WebCore/platform/chromium/PasteboardPrivate.h +++ b/Source/WebCore/platform/chromium/PasteboardPrivate.h @@ -36,6 +36,7 @@ namespace WebCore { class PasteboardPrivate { public: enum ClipboardFormat { + PlainTextFormat, HTMLFormat, BookmarkFormat, WebSmartPasteFormat, diff --git a/Source/WebCore/platform/chromium/ScrollbarThemeChromiumWin.cpp b/Source/WebCore/platform/chromium/ScrollbarThemeChromiumWin.cpp index 29e8b44..7229c51 100644 --- a/Source/WebCore/platform/chromium/ScrollbarThemeChromiumWin.cpp +++ b/Source/WebCore/platform/chromium/ScrollbarThemeChromiumWin.cpp @@ -35,7 +35,7 @@ #include "PlatformContextSkia.h" #include "PlatformMouseEvent.h" #include "Scrollbar.h" -#include "WindowsVersion.h" +#include "SystemInfo.h" namespace WebCore { @@ -70,7 +70,7 @@ int ScrollbarThemeChromiumWin::scrollbarThickness(ScrollbarControlSize controlSi bool ScrollbarThemeChromiumWin::invalidateOnMouseEnterExit() { - return isVistaOrNewer(); + return windowsVersion() >= WindowsVista; } bool ScrollbarThemeChromiumWin::shouldSnapBackToDragOrigin(Scrollbar* scrollbar, const PlatformMouseEvent& evt) @@ -160,12 +160,12 @@ int ScrollbarThemeChromiumWin::getThemeState(Scrollbar* scrollbar, ScrollbarPart if (scrollbar->pressedPart() == ThumbPart) { if (part == ThumbPart) return SCRBS_PRESSED; - return isVistaOrNewer() ? SCRBS_HOVER : SCRBS_NORMAL; + return (windowsVersion() < WindowsVista) ? SCRBS_NORMAL : SCRBS_HOVER; } if (!scrollbar->enabled()) return SCRBS_DISABLED; if (scrollbar->hoveredPart() != part || part == BackTrackPart || part == ForwardTrackPart) - return (scrollbar->hoveredPart() == NoPart || !isVistaOrNewer()) ? SCRBS_NORMAL : SCRBS_HOVER; + return (scrollbar->hoveredPart() == NoPart || (windowsVersion() < WindowsVista)) ? SCRBS_NORMAL : SCRBS_HOVER; if (scrollbar->pressedPart() == NoPart) return SCRBS_HOT; return (scrollbar->pressedPart() == part) ? SCRBS_PRESSED : SCRBS_NORMAL; @@ -179,43 +179,43 @@ int ScrollbarThemeChromiumWin::getThemeArrowState(Scrollbar* scrollbar, Scrollba if (part == BackButtonStartPart || part == ForwardButtonStartPart) { if (scrollbar->orientation() == HorizontalScrollbar) { if (scrollbar->pressedPart() == ThumbPart) - return !isVistaOrNewer() ? ABS_LEFTNORMAL : ABS_LEFTHOVER; + return (windowsVersion() < WindowsVista) ? ABS_LEFTNORMAL : ABS_LEFTHOVER; if (!scrollbar->enabled()) return ABS_LEFTDISABLED; if (scrollbar->hoveredPart() != part) - return ((scrollbar->hoveredPart() == NoPart) || !isVistaOrNewer()) ? ABS_LEFTNORMAL : ABS_LEFTHOVER; + return ((scrollbar->hoveredPart() == NoPart) || (windowsVersion() < WindowsVista)) ? ABS_LEFTNORMAL : ABS_LEFTHOVER; if (scrollbar->pressedPart() == NoPart) return ABS_LEFTHOT; return (scrollbar->pressedPart() == part) ? ABS_LEFTPRESSED : ABS_LEFTNORMAL; } if (scrollbar->pressedPart() == ThumbPart) - return !isVistaOrNewer() ? ABS_UPNORMAL : ABS_UPHOVER; + return (windowsVersion() < WindowsVista) ? ABS_UPNORMAL : ABS_UPHOVER; if (!scrollbar->enabled()) return ABS_UPDISABLED; if (scrollbar->hoveredPart() != part) - return ((scrollbar->hoveredPart() == NoPart) || !isVistaOrNewer()) ? ABS_UPNORMAL : ABS_UPHOVER; + return ((scrollbar->hoveredPart() == NoPart) || (windowsVersion() < WindowsVista)) ? ABS_UPNORMAL : ABS_UPHOVER; if (scrollbar->pressedPart() == NoPart) return ABS_UPHOT; return (scrollbar->pressedPart() == part) ? ABS_UPPRESSED : ABS_UPNORMAL; } if (scrollbar->orientation() == HorizontalScrollbar) { if (scrollbar->pressedPart() == ThumbPart) - return !isVistaOrNewer() ? ABS_RIGHTNORMAL : ABS_RIGHTHOVER; + return (windowsVersion() < WindowsVista) ? ABS_RIGHTNORMAL : ABS_RIGHTHOVER; if (!scrollbar->enabled()) return ABS_RIGHTDISABLED; if (scrollbar->hoveredPart() != part) - return ((scrollbar->hoveredPart() == NoPart) || !isVistaOrNewer()) ? ABS_RIGHTNORMAL : ABS_RIGHTHOVER; + return ((scrollbar->hoveredPart() == NoPart) || (windowsVersion() < WindowsVista)) ? ABS_RIGHTNORMAL : ABS_RIGHTHOVER; if (scrollbar->pressedPart() == NoPart) return ABS_RIGHTHOT; return (scrollbar->pressedPart() == part) ? ABS_RIGHTPRESSED : ABS_RIGHTNORMAL; } if (scrollbar->pressedPart() == ThumbPart) - return !isVistaOrNewer() ? ABS_DOWNNORMAL : ABS_DOWNHOVER; + return (windowsVersion() < WindowsVista) ? ABS_DOWNNORMAL : ABS_DOWNHOVER; if (!scrollbar->enabled()) return ABS_DOWNDISABLED; if (scrollbar->hoveredPart() != part) - return ((scrollbar->hoveredPart() == NoPart) || !isVistaOrNewer()) ? ABS_DOWNNORMAL : ABS_DOWNHOVER; + return ((scrollbar->hoveredPart() == NoPart) || (windowsVersion() < WindowsVista)) ? ABS_DOWNNORMAL : ABS_DOWNHOVER; if (scrollbar->pressedPart() == NoPart) return ABS_DOWNHOT; return (scrollbar->pressedPart() == part) ? ABS_DOWNPRESSED : ABS_DOWNNORMAL; diff --git a/Source/WebCore/platform/chromium/TraceEvent.h b/Source/WebCore/platform/chromium/TraceEvent.h new file mode 100644 index 0000000..9b92d58 --- /dev/null +++ b/Source/WebCore/platform/chromium/TraceEvent.h @@ -0,0 +1,74 @@ +/* + * 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 TraceEvent_h +#define TraceEvent_h + +#include "PlatformBridge.h" + +// Implementation detail: trace event macros create temporary variables +// to keep instrumentation overhead low. These macros give each temporary +// variable a unique name based on the line number to prevent name collissions. +#define TRACE_EVENT_MAKE_UNIQUE_IDENTIFIER3(a, b) a##b +#define TRACE_EVENT_MAKE_UNIQUE_IDENTIFIER2(a, b) TRACE_EVENT_MAKE_UNIQUE_IDENTIFIER3(a, b) +#define TRACE_EVENT_MAKE_UNIQUE_IDENTIFIER(name_prefix) TRACE_EVENT_MAKE_UNIQUE_IDENTIFIER2(name_prefix, __LINE__) + +// Issues PlatformBridge::traceEventBegin and traceEventEnd calls for the enclosing scope +#define TRACE_EVENT(name, id, extra) WebCore::internal::ScopeTracer TRACE_EVENT_MAKE_UNIQUE_IDENTIFIER(__traceEventScope)(name, id, extra); + +namespace WebCore { + +namespace internal { + +// Used by TRACE_EVENT macro. Do not use directly. +class ScopeTracer { +public: + ScopeTracer(const char* name, void*, const char* extra); + ~ScopeTracer(); + +private: + const char* m_name; + void* m_id; + OwnPtr<char*> m_extra; +}; + +inline ScopeTracer::ScopeTracer(const char* name, void* id, const char* extra) + : m_name(name) + , m_id(id) +{ + PlatformBridge::traceEventBegin(name, id, extra); \ + if (extra) + m_extra = adoptPtr(strdup(extra)); +} + +inline ScopeTracer::~ScopeTracer() +{ + PlatformBridge::traceEventEnd(m_name, m_id, m_extra.get()); +} + +} // namespace internal + +} // namespace WebCore + +#endif diff --git a/Source/WebCore/platform/chromium/WindowsVersion.cpp b/Source/WebCore/platform/chromium/WindowsVersion.cpp deleted file mode 100644 index a9632cb..0000000 --- a/Source/WebCore/platform/chromium/WindowsVersion.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2008, Google Inc. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "config.h" -#include "WindowsVersion.h" - -#include <windows.h> - -namespace WebCore { - -bool isVistaOrNewer() -{ - // Cache the result to avoid asking every time. - static bool haveResult = false; - static bool result = false; - if (!haveResult) { - OSVERSIONINFO versionInfo; - versionInfo.dwOSVersionInfoSize = sizeof(versionInfo); - GetVersionEx(&versionInfo); - - haveResult = true; - result = versionInfo.dwMajorVersion >= 6; - } - return result; -} - -} // namespace WebCore diff --git a/Source/WebCore/platform/efl/ContextMenuEfl.cpp b/Source/WebCore/platform/efl/ContextMenuEfl.cpp index a5c6524..45d1758 100644 --- a/Source/WebCore/platform/efl/ContextMenuEfl.cpp +++ b/Source/WebCore/platform/efl/ContextMenuEfl.cpp @@ -2,7 +2,7 @@ * Copyright (C) 2007 Holger Hans Peter Freyther * Copyright (C) 2008 INdT - Instituto Nokia de Tecnologia * Copyright (C) 2009-2010 ProFUSION embedded systems - * Copyright (C) 2009-2010 Samsung Electronics + * Copyright (C) 2011 Samsung Electronics * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -26,16 +26,12 @@ namespace WebCore { +#if USE(CROSS_PLATFORM_CONTEXT_MENUS) ContextMenu::ContextMenu(void* menu) { getContextMenuItems(menu, m_items); } -ContextMenu::ContextMenu() -{ - notImplemented(); -} - void ContextMenu::getContextMenuItems(void* menu, Vector<ContextMenuItem>& items) { notImplemented(); @@ -51,5 +47,11 @@ void* ContextMenu::nativeMenu() const { return createNativeMenuFromItems(m_items); } +#else +ContextMenu::ContextMenu() +{ + notImplemented(); +} +#endif } diff --git a/Source/WebCore/platform/efl/ContextMenuItemEfl.cpp b/Source/WebCore/platform/efl/ContextMenuItemEfl.cpp index 5ce8fab..425c6a6 100644 --- a/Source/WebCore/platform/efl/ContextMenuItemEfl.cpp +++ b/Source/WebCore/platform/efl/ContextMenuItemEfl.cpp @@ -3,7 +3,7 @@ * Copyright (C) 2007 Staikos Computing Services Inc. <info@staikos.net> * Copyright (C) 2008 INdT - Instituto Nokia de Tecnologia * Copyright (C) 2009-2010 ProFUSION embedded systems - * Copyright (C) 2009-2010 Samsung Electronics + * Copyright (C) 2011 Samsung Electronics * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,11 +34,13 @@ namespace WebCore { -ContextMenuItem::ContextMenuItem(void* const&) +#if USE(CROSS_PLATFORM_CONTEXT_MENUS) +void* ContextMenuItem::nativeMenuItem() const { notImplemented(); + return 0; } - +#else ContextMenuItem::ContextMenuItem(ContextMenuItemType, ContextMenuAction, const String&, ContextMenu*) { notImplemented(); @@ -49,12 +51,6 @@ ContextMenuItem::~ContextMenuItem() notImplemented(); } -void* ContextMenuItem::nativeMenuItem() const -{ - notImplemented(); - return 0; -} - ContextMenuItemType ContextMenuItem::type() const { notImplemented(); @@ -98,5 +94,5 @@ void ContextMenuItem::setSubMenu(ContextMenu*) { notImplemented(); } - +#endif } diff --git a/Source/WebCore/platform/efl/FileSystemEfl.cpp b/Source/WebCore/platform/efl/FileSystemEfl.cpp index cb117bc..01c6c67 100644 --- a/Source/WebCore/platform/efl/FileSystemEfl.cpp +++ b/Source/WebCore/platform/efl/FileSystemEfl.cpp @@ -67,7 +67,7 @@ CString fileSystemRepresentation(const String& path) #endif } -CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle) +String openTemporaryFile(const String& prefix, PlatformFileHandle& handle) { char buffer[PATH_MAX]; const char* tmpDir = getenv("TMPDIR"); @@ -75,18 +75,18 @@ CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle) if (!tmpDir) tmpDir = "/tmp"; - if (snprintf(buffer, PATH_MAX, "%s/%sXXXXXX", tmpDir, prefix) >= PATH_MAX) + if (snprintf(buffer, PATH_MAX, "%s/%sXXXXXX", tmpDir, prefix.utf8().data()) >= PATH_MAX) goto end; handle = mkstemp(buffer); if (handle < 0) goto end; - return CString(buffer); + return String::fromUTF8(buffer); end: handle = invalidPlatformFileHandle; - return CString(); + return String(); } bool unloadModule(PlatformModule module) diff --git a/Source/WebCore/platform/efl/GeolocationServiceEfl.cpp b/Source/WebCore/platform/efl/GeolocationServiceEfl.cpp new file mode 100644 index 0000000..0c0e744 --- /dev/null +++ b/Source/WebCore/platform/efl/GeolocationServiceEfl.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2008 Holger Hans Peter Freyther + * Copyright (C) 2011 Samsung Electronics + * + * 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 "GeolocationServiceEfl.h" + +#if ENABLE(GEOLOCATION) +#include "NotImplemented.h" +#include "PositionOptions.h" +#include <wtf/text/CString.h> + +namespace WebCore { + +GeolocationService::FactoryFunction* GeolocationService::s_factoryFunction = &GeolocationServiceEfl::create; + +GeolocationService* GeolocationServiceEfl::create(GeolocationServiceClient* client) +{ + return new GeolocationServiceEfl(client); +} + +GeolocationServiceEfl::GeolocationServiceEfl(GeolocationServiceClient* client) + : GeolocationService(client) +{ +} + +GeolocationServiceEfl::~GeolocationServiceEfl() +{ + notImplemented(); +} + +bool GeolocationServiceEfl::startUpdating(PositionOptions* options) +{ + notImplemented(); + return false; +} + +void GeolocationServiceEfl::stopUpdating() +{ + notImplemented(); +} + +void GeolocationServiceEfl::suspend() +{ + notImplemented(); +} + +void GeolocationServiceEfl::resume() +{ + notImplemented(); +} + +Geoposition* GeolocationServiceEfl::lastPosition() const +{ + return m_lastPosition.get(); +} + +PositionError* GeolocationServiceEfl::lastError() const +{ + return m_lastError.get(); +} + +} +#endif // ENABLE(GEOLOCATION) diff --git a/Source/WebCore/platform/efl/GeolocationServiceEfl.h b/Source/WebCore/platform/efl/GeolocationServiceEfl.h new file mode 100644 index 0000000..e7ac66c --- /dev/null +++ b/Source/WebCore/platform/efl/GeolocationServiceEfl.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2008 Holger Hans Peter Freyther + * Copyright (C) 2011 Samsung Electronics + * + * 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 GeolocationServiceEfl_h +#define GeolocationServiceEfl_h + +#if ENABLE(GEOLOCATION) +#include "GeolocationService.h" +#include "Geoposition.h" +#include "PositionError.h" +#include "RefPtr.h" + +namespace WebCore { + +class GeolocationServiceEfl : public GeolocationService { +public: + static GeolocationService* create(GeolocationServiceClient*); + ~GeolocationServiceEfl(); + + virtual bool startUpdating(PositionOptions*); + virtual void stopUpdating(); + + virtual void suspend(); + virtual void resume(); + + virtual Geoposition* lastPosition() const; + virtual PositionError* lastError() const; + +private: + GeolocationServiceEfl(GeolocationServiceClient*); + + RefPtr<Geoposition> m_lastPosition; + RefPtr<PositionError> m_lastError; + +}; + +} +#endif // ENABLE(GEOLOCATION) +#endif diff --git a/Source/WebCore/platform/efl/LocalizedStringsEfl.cpp b/Source/WebCore/platform/efl/LocalizedStringsEfl.cpp index 7e852f4..36a9f01 100644 --- a/Source/WebCore/platform/efl/LocalizedStringsEfl.cpp +++ b/Source/WebCore/platform/efl/LocalizedStringsEfl.cpp @@ -241,7 +241,7 @@ String contextMenuItemTagSearchWeb() return String::fromUTF8("Search the Web"); } -String contextMenuItemTagLookUpInDictionary() +String contextMenuItemTagLookUpInDictionary(const String&) { return String::fromUTF8("Look Up in Dictionary"); } diff --git a/Source/WebCore/platform/efl/PlatformKeyboardEventEfl.cpp b/Source/WebCore/platform/efl/PlatformKeyboardEventEfl.cpp index 2888b22..10121df 100644 --- a/Source/WebCore/platform/efl/PlatformKeyboardEventEfl.cpp +++ b/Source/WebCore/platform/efl/PlatformKeyboardEventEfl.cpp @@ -188,15 +188,15 @@ static int windowsKeyCodeForEvasKeyName(String& keyName) return 0; } -PlatformKeyboardEvent::PlatformKeyboardEvent(const Evas_Event_Key_Down* ev) +PlatformKeyboardEvent::PlatformKeyboardEvent(const Evas_Event_Key_Down* event) : m_type(KeyDown) - , m_text(String::fromUTF8(ev->string)) - , m_shiftKey(evas_key_modifier_is_set(ev->modifiers, "Shift")) - , m_ctrlKey(evas_key_modifier_is_set(ev->modifiers, "Control")) - , m_altKey(evas_key_modifier_is_set(ev->modifiers, "Alt")) - , m_metaKey(evas_key_modifier_is_set(ev->modifiers, "Meta")) + , m_text(String::fromUTF8(event->string)) + , m_shiftKey(evas_key_modifier_is_set(event->modifiers, "Shift")) + , m_ctrlKey(evas_key_modifier_is_set(event->modifiers, "Control")) + , m_altKey(evas_key_modifier_is_set(event->modifiers, "Alt")) + , m_metaKey(evas_key_modifier_is_set(event->modifiers, "Meta")) { - String keyName = String(ev->key); + String keyName = String(event->key); m_keyIdentifier = keyIdentifierForEvasKeyName(keyName); m_windowsVirtualKeyCode = windowsKeyCodeForEvasKeyName(keyName); @@ -205,15 +205,15 @@ PlatformKeyboardEvent::PlatformKeyboardEvent(const Evas_Event_Key_Down* ev) m_autoRepeat = false; } -PlatformKeyboardEvent::PlatformKeyboardEvent(const Evas_Event_Key_Up* ev) +PlatformKeyboardEvent::PlatformKeyboardEvent(const Evas_Event_Key_Up* event) : m_type(KeyUp) - , m_text(String::fromUTF8(ev->string)) - , m_shiftKey(evas_key_modifier_is_set(ev->modifiers, "Shift")) - , m_ctrlKey(evas_key_modifier_is_set(ev->modifiers, "Control")) - , m_altKey(evas_key_modifier_is_set(ev->modifiers, "Alt")) - , m_metaKey(evas_key_modifier_is_set(ev->modifiers, "Meta")) + , m_text(String::fromUTF8(event->string)) + , m_shiftKey(evas_key_modifier_is_set(event->modifiers, "Shift")) + , m_ctrlKey(evas_key_modifier_is_set(event->modifiers, "Control")) + , m_altKey(evas_key_modifier_is_set(event->modifiers, "Alt")) + , m_metaKey(evas_key_modifier_is_set(event->modifiers, "Meta")) { - String keyName = String(ev->key); + String keyName = String(event->key); m_keyIdentifier = keyIdentifierForEvasKeyName(keyName); m_windowsVirtualKeyCode = windowsKeyCodeForEvasKeyName(keyName); diff --git a/Source/WebCore/platform/efl/PlatformMouseEventEfl.cpp b/Source/WebCore/platform/efl/PlatformMouseEventEfl.cpp index 53de522..172b493 100644 --- a/Source/WebCore/platform/efl/PlatformMouseEventEfl.cpp +++ b/Source/WebCore/platform/efl/PlatformMouseEventEfl.cpp @@ -47,44 +47,44 @@ void PlatformMouseEvent::setClickCount(unsigned int flags) m_clickCount = 1; } -PlatformMouseEvent::PlatformMouseEvent(const Evas_Event_Mouse_Down* ev, IntPoint pos) - : m_position(IntPoint(ev->canvas.x - pos.x(), ev->canvas.y - pos.y())) - , m_globalPosition(IntPoint(ev->canvas.x, ev->canvas.y)) - , m_button(MouseButton(ev->button - 1)) +PlatformMouseEvent::PlatformMouseEvent(const Evas_Event_Mouse_Down* event, IntPoint position) + : m_position(IntPoint(event->canvas.x - position.x(), event->canvas.y - position.y())) + , m_globalPosition(IntPoint(event->canvas.x, event->canvas.y)) + , m_button(MouseButton(event->button - 1)) , m_eventType(MouseEventPressed) - , m_shiftKey(evas_key_modifier_is_set(ev->modifiers, "Shift")) - , m_ctrlKey(evas_key_modifier_is_set(ev->modifiers, "Control")) - , m_altKey(evas_key_modifier_is_set(ev->modifiers, "Alt")) - , m_metaKey(evas_key_modifier_is_set(ev->modifiers, "Meta")) + , m_shiftKey(evas_key_modifier_is_set(event->modifiers, "Shift")) + , m_ctrlKey(evas_key_modifier_is_set(event->modifiers, "Control")) + , m_altKey(evas_key_modifier_is_set(event->modifiers, "Alt")) + , m_metaKey(evas_key_modifier_is_set(event->modifiers, "Meta")) , m_timestamp(currentTime()) { - setClickCount(ev->flags); + setClickCount(event->flags); } -PlatformMouseEvent::PlatformMouseEvent(const Evas_Event_Mouse_Up* ev, IntPoint pos) - : m_position(IntPoint(ev->canvas.x - pos.x(), ev->canvas.y - pos.y())) - , m_globalPosition(IntPoint(ev->canvas.x, ev->canvas.y)) - , m_button(MouseButton(ev->button - 1)) +PlatformMouseEvent::PlatformMouseEvent(const Evas_Event_Mouse_Up* event, IntPoint position) + : m_position(IntPoint(event->canvas.x - position.x(), event->canvas.y - position.y())) + , m_globalPosition(IntPoint(event->canvas.x, event->canvas.y)) + , m_button(MouseButton(event->button - 1)) , m_eventType(MouseEventReleased) - , m_shiftKey(evas_key_modifier_is_set(ev->modifiers, "Shift")) - , m_ctrlKey(evas_key_modifier_is_set(ev->modifiers, "Control")) - , m_altKey(evas_key_modifier_is_set(ev->modifiers, "Alt")) - , m_metaKey(evas_key_modifier_is_set(ev->modifiers, "Meta")) + , m_shiftKey(evas_key_modifier_is_set(event->modifiers, "Shift")) + , m_ctrlKey(evas_key_modifier_is_set(event->modifiers, "Control")) + , m_altKey(evas_key_modifier_is_set(event->modifiers, "Alt")) + , m_metaKey(evas_key_modifier_is_set(event->modifiers, "Meta")) , m_timestamp(currentTime()) { - setClickCount(ev->flags); + setClickCount(event->flags); } -PlatformMouseEvent::PlatformMouseEvent(const Evas_Event_Mouse_Move* ev, IntPoint pos) - : m_position(IntPoint(ev->cur.canvas.x - pos.x(), ev->cur.canvas.y - pos.y())) - , m_globalPosition(IntPoint(ev->cur.canvas.x, ev->cur.canvas.y)) - , m_button(MouseButton(ev->buttons - 1)) +PlatformMouseEvent::PlatformMouseEvent(const Evas_Event_Mouse_Move* event, IntPoint position) + : m_position(IntPoint(event->cur.canvas.x - position.x(), event->cur.canvas.y - position.y())) + , m_globalPosition(IntPoint(event->cur.canvas.x, event->cur.canvas.y)) + , m_button(MouseButton(event->buttons - 1)) , m_eventType(MouseEventMoved) , m_clickCount(0) - , m_shiftKey(evas_key_modifier_is_set(ev->modifiers, "Shift")) - , m_ctrlKey(evas_key_modifier_is_set(ev->modifiers, "Control")) - , m_altKey(evas_key_modifier_is_set(ev->modifiers, "Alt")) - , m_metaKey(evas_key_modifier_is_set(ev->modifiers, "Meta")) + , m_shiftKey(evas_key_modifier_is_set(event->modifiers, "Shift")) + , m_ctrlKey(evas_key_modifier_is_set(event->modifiers, "Control")) + , m_altKey(evas_key_modifier_is_set(event->modifiers, "Alt")) + , m_metaKey(evas_key_modifier_is_set(event->modifiers, "Meta")) , m_timestamp(currentTime()) { } diff --git a/Source/WebCore/platform/efl/RenderThemeEfl.cpp b/Source/WebCore/platform/efl/RenderThemeEfl.cpp index 3e8a646..439e377 100644 --- a/Source/WebCore/platform/efl/RenderThemeEfl.cpp +++ b/Source/WebCore/platform/efl/RenderThemeEfl.cpp @@ -38,11 +38,21 @@ #include "RenderObject.h" #include "RenderProgress.h" #include "RenderSlider.h" +#include "UserAgentStyleSheets.h" #include <wtf/text/CString.h> #include <Ecore_Evas.h> #include <Edje.h> + +#if ENABLE(VIDEO) +#include "HTMLMediaElement.h" +#include "HTMLNames.h" +#endif + namespace WebCore { +#if ENABLE(VIDEO) +using namespace HTMLNames; +#endif // TODO: change from object count to ecore_evas size (bytes) // TODO: as objects are webpage/user defined and they can be very large. @@ -273,7 +283,7 @@ bool RenderThemeEfl::paintThemePart(RenderObject* object, FormType type, const P applyEdjeStateFromForm(entry->o, controlStatesForRenderer(object)); - cairo = info.context->platformContext(); + cairo = info.context->platformContext()->cr(); ASSERT(cairo); // Currently, only sliders needs this message; if other widget ever needs special @@ -592,6 +602,10 @@ const char* RenderThemeEfl::edjeGroupFromFormType(FormType type) const W("search/cancel_button"), W("slider/vertical"), W("slider/horizontal"), +#if ENABLE(VIDEO) + W("mediacontrol/playpause_button"), + W("mediacontrol/mute_button"), +#endif #undef W 0 }; @@ -1044,10 +1058,32 @@ bool RenderThemeEfl::paintProgressBar(RenderObject* object, const PaintInfo& inf #endif #if ENABLE(VIDEO) +bool RenderThemeEfl::emitMediaButtonSignal(FormType formType, MediaControlElementType mediaElementType, const IntRect& rect) +{ + ThemePartCacheEntry* entry; + + entry = cacheThemePartGet(formType, rect.size()); + ASSERT(entry); + if (!entry) + return false; + + if (mediaElementType == MediaPlayButton) + edje_object_signal_emit(entry->o, "play", ""); + else if (mediaElementType == MediaPauseButton) + edje_object_signal_emit(entry->o, "pause", ""); + else if (mediaElementType == MediaMuteButton) + edje_object_signal_emit(entry->o, "mute", ""); + else if (mediaElementType == MediaUnMuteButton) + edje_object_signal_emit(entry->o, "sound", ""); + else + return false; + + return true; +} + String RenderThemeEfl::extraMediaControlsStyleSheet() { - notImplemented(); - return String(); + return String(mediaControlsEflUserAgentStyleSheet, sizeof(mediaControlsEflUserAgentStyleSheet)); } String RenderThemeEfl::formatMediaControlsCurrentTime(float currentTime, float duration) const @@ -1064,14 +1100,29 @@ bool RenderThemeEfl::paintMediaFullscreenButton(RenderObject* object, const Pain bool RenderThemeEfl::paintMediaMuteButton(RenderObject* object, const PaintInfo& info, const IntRect& rect) { - notImplemented(); - return false; + Node* mediaNode = object->node() ? object->node()->shadowAncestorNode() : 0; + if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag))) + return false; + + HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode); + + if (!emitMediaButtonSignal(MediaMuteUnMuteButton, mediaElement->muted() ? MediaMuteButton : MediaUnMuteButton, rect)) + return false; + + return paintThemePart(object, MediaMuteUnMuteButton, info, rect); } bool RenderThemeEfl::paintMediaPlayButton(RenderObject* object, const PaintInfo& info, const IntRect& rect) { - notImplemented(); - return false; + Node* node = object->node(); + if (!node) + return false; + + MediaControlPlayButtonElement* button = static_cast<MediaControlPlayButtonElement*>(node); + if (!emitMediaButtonSignal(MediaPlayPauseButton, button->displayType(), rect)) + return false; + + return paintThemePart(object, MediaPlayPauseButton, info, rect); } bool RenderThemeEfl::paintMediaSeekBackButton(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 9970096..fe8e2d2 100644 --- a/Source/WebCore/platform/efl/RenderThemeEfl.h +++ b/Source/WebCore/platform/efl/RenderThemeEfl.h @@ -30,6 +30,9 @@ #ifndef RenderThemeEfl_h #define RenderThemeEfl_h +#if ENABLE(VIDEO) +#include "MediaControlElements.h" +#endif #include "RenderTheme.h" #include <cairo.h> @@ -55,6 +58,10 @@ enum FormType { // KEEP IN SYNC WITH edjeGroupFromFormType() SearchFieldCancelButton, SliderVertical, SliderHorizontal, +#if ENABLE(VIDEO) + MediaPlayPauseButton, + MediaMuteUnMuteButton, +#endif FormTypeLast }; @@ -182,6 +189,10 @@ private: void applyEdjeStateFromForm(Evas_Object*, ControlStates); bool paintThemePart(RenderObject*, FormType, const PaintInfo&, const IntRect&); +#if ENABLE(VIDEO) + bool emitMediaButtonSignal(FormType, MediaControlElementType, const IntRect&); +#endif + Page* m_page; Color m_activeSelectionBackgroundColor; Color m_activeSelectionForegroundColor; diff --git a/Source/WebCore/platform/efl/ScrollbarEfl.cpp b/Source/WebCore/platform/efl/ScrollbarEfl.cpp index e71d1e3..162c2a1 100644 --- a/Source/WebCore/platform/efl/ScrollbarEfl.cpp +++ b/Source/WebCore/platform/efl/ScrollbarEfl.cpp @@ -64,50 +64,50 @@ ScrollbarEfl::~ScrollbarEfl() setEvasObject(0); } -static void scrollbarEflEdjeMessage(void* data, Evas_Object* o, Edje_Message_Type type, int id, void* msg) +static void scrollbarEflEdjeMessage(void* data, Evas_Object* object, Edje_Message_Type messageType, int id, void* message) { ScrollbarEfl* that = static_cast<ScrollbarEfl*>(data); - Edje_Message_Float* m; - int v; + Edje_Message_Float* messageFloat; + int value; if (!id) { EINA_LOG_ERR("Unknown message id '%d' from scroll bar theme.", id); return; } - if (type != EDJE_MESSAGE_FLOAT) { + if (messageType != EDJE_MESSAGE_FLOAT) { EINA_LOG_ERR("Message id '%d' of incorrect type from scroll bar theme. " "Expected '%d', got '%d'.", - id, EDJE_MESSAGE_FLOAT, type); + id, EDJE_MESSAGE_FLOAT, messageType); return; } - m = static_cast<Edje_Message_Float*>(msg); - v = m->val * (that->totalSize() - that->visibleSize()); - that->scrollableArea()->scrollToOffsetWithoutAnimation(that->orientation(), v); + messageFloat = static_cast<Edje_Message_Float*>(message); + value = messageFloat->val * (that->totalSize() - that->visibleSize()); + that->scrollableArea()->scrollToOffsetWithoutAnimation(that->orientation(), value); } void ScrollbarEfl::setParent(ScrollView* view) { - Evas_Object* o = evasObject(); + Evas_Object* object = evasObject(); Evas_Coord w, h; Widget::setParent(view); - if (!o) { + if (!object) { if (!view) return; - o = edje_object_add(view->evas()); - if (!o) { + object = edje_object_add(view->evas()); + if (!object) { EINA_LOG_ERR("Could not create edje object for view=%p (evas=%p)", view, view->evas()); return; } - edje_object_message_handler_set(o, scrollbarEflEdjeMessage, this); - setEvasObject(o); + edje_object_message_handler_set(object, scrollbarEflEdjeMessage, this); + setEvasObject(object); } else if (!view) { - evas_object_hide(o); + evas_object_hide(object); return; } @@ -117,23 +117,23 @@ void ScrollbarEfl::setParent(ScrollView* view) if (theme.isEmpty()) { EINA_LOG_ERR("Could not load theme '%s': no theme path set.", group); - evas_object_hide(o); + evas_object_hide(object); return; } - if (!edje_object_file_set(o, theme.utf8().data(), group)) { - Edje_Load_Error err = edje_object_load_error_get(o); - const char* errmsg = edje_load_error_str(err); + if (!edje_object_file_set(object, theme.utf8().data(), group)) { + Edje_Load_Error err = edje_object_load_error_get(object); + const char* errmessage = edje_load_error_str(err); EINA_LOG_ERR("Could not load theme '%s' from file '%s': #%d '%s'", - group, theme.utf8().data(), err, errmsg); + group, theme.utf8().data(), err, errmessage); return; } - setPlatformWidget(o); - evas_object_smart_member_add(o, view->evasObject()); - evas_object_show(o); + setPlatformWidget(object); + evas_object_smart_member_add(object, view->evasObject()); + evas_object_show(object); - edje_object_size_min_get(o, &w, &h); + edje_object_size_min_get(object, &w, &h); IntRect rect = frameRect(); rect.setSize(IntSize(w, h)); @@ -168,21 +168,21 @@ void ScrollbarEfl::updateThumbPositionAndProportion() m_lastTotalSize = tSize; m_lastVisibleSize = vSize; - Edje_Message_Float_Set* msg = static_cast<Edje_Message_Float_Set*> + Edje_Message_Float_Set* message = static_cast<Edje_Message_Float_Set*> (alloca(sizeof(Edje_Message_Float_Set) + sizeof(float))); - msg->count = 2; + message->count = 2; if (tSize - vSize > 0) - msg->val[0] = pos / (float)(tSize - vSize); + message->val[0] = pos / static_cast<float>(tSize - vSize); else - msg->val[0] = 0.0; + message->val[0] = 0.0; if (tSize > 0) - msg->val[1] = vSize / (float)tSize; + message->val[1] = vSize / static_cast<float>(tSize); else - msg->val[1] = 0.0; + message->val[1] = 0.0; - edje_object_message_send(platformWidget(), EDJE_MESSAGE_FLOAT_SET, 0, msg); + edje_object_message_send(platformWidget(), EDJE_MESSAGE_FLOAT_SET, 0, message); } void ScrollbarEfl::setFrameRect(const IntRect& rect) @@ -193,10 +193,10 @@ void ScrollbarEfl::setFrameRect(const IntRect& rect) void ScrollbarEfl::frameRectsChanged() { - Evas_Object* o = platformWidget(); + Evas_Object* object = platformWidget(); Evas_Coord x, y; - if (!parent() || !o) + if (!parent() || !object) return; IntRect rect = frameRect(); @@ -206,11 +206,11 @@ void ScrollbarEfl::frameRectsChanged() rect.setLocation(parent()->contentsToWindow(rect.location())); evas_object_geometry_get(root()->evasObject(), &x, &y, 0, 0); - evas_object_move(o, x + rect.x(), y + rect.y()); - evas_object_resize(o, rect.width(), rect.height()); + evas_object_move(object, x + rect.x(), y + rect.y()); + evas_object_resize(object, rect.width(), rect.height()); } -void ScrollbarEfl::paint(GraphicsContext* context, const IntRect& rect) +void ScrollbarEfl::paint(GraphicsContext* graphicsContext, const IntRect& damageRect) { } diff --git a/Source/WebCore/platform/efl/ScrollbarEfl.h b/Source/WebCore/platform/efl/ScrollbarEfl.h index 09dc64f..1f67d2f 100644 --- a/Source/WebCore/platform/efl/ScrollbarEfl.h +++ b/Source/WebCore/platform/efl/ScrollbarEfl.h @@ -49,7 +49,7 @@ public: virtual void frameRectsChanged(); - virtual void paint(GraphicsContext* context, const IntRect& damageRect); + virtual void paint(GraphicsContext*, const IntRect&); protected: ScrollbarEfl(ScrollableArea*, ScrollbarOrientation, ScrollbarControlSize); @@ -58,7 +58,7 @@ protected: virtual void updateThumbPosition(); virtual void updateThumbProportion(); - virtual void setParent(ScrollView* view); + virtual void setParent(ScrollView*); private: int m_lastPos; diff --git a/Source/WebCore/platform/efl/WidgetEfl.cpp b/Source/WebCore/platform/efl/WidgetEfl.cpp index 640e6e3..45d4792 100644 --- a/Source/WebCore/platform/efl/WidgetEfl.cpp +++ b/Source/WebCore/platform/efl/WidgetEfl.cpp @@ -183,10 +183,10 @@ void Widget::setFrameRect(const IntRect& rect) void Widget::frameRectsChanged() { - Evas_Object* o = evasObject(); + Evas_Object* object = evasObject(); Evas_Coord x, y; - if (!parent() || !o) + if (!parent() || !object) return; IntRect rect = frameRect(); @@ -196,8 +196,8 @@ void Widget::frameRectsChanged() rect.setLocation(parent()->contentsToWindow(rect.location())); evas_object_geometry_get(root()->evasObject(), &x, &y, 0, 0); - evas_object_move(o, x + rect.x(), y + rect.y()); - evas_object_resize(o, rect.width(), rect.height()); + evas_object_move(object, x + rect.x(), y + rect.y()); + evas_object_resize(object, rect.width(), rect.height()); } void Widget::setFocus(bool focused) @@ -332,14 +332,14 @@ Ecore_Evas* Widget::ecoreEvas() const return static_cast<Ecore_Evas*>(evas_data_attach_get(evas())); } -void Widget::setEvasObject(Evas_Object *o) +void Widget::setEvasObject(Evas_Object *object) { // FIXME: study platformWidget() and use it // FIXME: right now platformWidget() requires implementing too much - if (m_data->m_evasObject == o) + if (m_data->m_evasObject == object) return; - m_data->m_evasObject = o; - if (!o) { + m_data->m_evasObject = object; + if (!object) { m_data->m_evas = 0; #ifdef HAVE_ECORE_X m_data->m_isUsingEcoreX = false; @@ -347,7 +347,7 @@ void Widget::setEvasObject(Evas_Object *o) return; } - m_data->m_evas = evas_object_evas_get(o); + m_data->m_evas = evas_object_evas_get(object); #ifdef HAVE_ECORE_X const char *engine = ecore_evas_engine_name_get(ecoreEvas()); diff --git a/Source/WebCore/platform/graphics/BitmapImage.h b/Source/WebCore/platform/graphics/BitmapImage.h index 14a3094..c8cf0ab 100644 --- a/Source/WebCore/platform/graphics/BitmapImage.h +++ b/Source/WebCore/platform/graphics/BitmapImage.h @@ -165,7 +165,7 @@ protected: enum RepetitionCountStatus { Unknown, // We haven't checked the source's repetition count. Uncertain, // We have a repetition count, but it might be wrong (some GIFs have a count after the image data, and will report "loop once" until all data has been decoded). - Certain, // The repetition count is known to be correct. + Certain // The repetition count is known to be correct. }; BitmapImage(NativeImagePtr, ImageObserver* = 0); diff --git a/Source/WebCore/platform/graphics/Color.cpp b/Source/WebCore/platform/graphics/Color.cpp index a1c5cd7..7dea765 100644 --- a/Source/WebCore/platform/graphics/Color.cpp +++ b/Source/WebCore/platform/graphics/Color.cpp @@ -27,13 +27,12 @@ #include "Color.h" #include "HashTools.h" -#include "PlatformString.h" -#include <math.h> #include <wtf/Assertions.h> +#include <wtf/HexNumber.h> #include <wtf/MathExtras.h> +#include <wtf/text/StringBuilder.h> using namespace std; -using namespace WTF; namespace WebCore { @@ -180,14 +179,6 @@ Color::Color(const char* name) } } -static inline void appendHexNumber(UChar* destination, uint8_t number) -{ - static const char hexDigits[17] = "0123456789abcdef"; - - destination[0] = hexDigits[number >> 4]; - destination[1] = hexDigits[number & 0xF]; -} - String Color::serialized() const { DEFINE_STATIC_LOCAL(const String, commaSpace, (", ")); @@ -195,13 +186,13 @@ String Color::serialized() const DEFINE_STATIC_LOCAL(const String, zeroPointZero, ("0.0")); if (!hasAlpha()) { - UChar* characters; - String result = String::createUninitialized(7, characters); - characters[0] = '#'; - appendHexNumber(characters + 1, red()); - appendHexNumber(characters + 3, green()); - appendHexNumber(characters + 5, blue()); - return result; + StringBuilder builder; + builder.reserveCapacity(7); + builder.append('#'); + appendByteAsHex(red(), builder, Lowercase); + appendByteAsHex(green(), builder, Lowercase); + appendByteAsHex(blue(), builder, Lowercase); + return builder.toString(); } Vector<UChar> result; diff --git a/Source/WebCore/platform/graphics/ContextShadow.h b/Source/WebCore/platform/graphics/ContextShadow.h index c0571f0..850d489 100644 --- a/Source/WebCore/platform/graphics/ContextShadow.h +++ b/Source/WebCore/platform/graphics/ContextShadow.h @@ -32,7 +32,7 @@ #include "Color.h" #include "FloatRect.h" #include "IntRect.h" -#include "RefCounted.h" +#include <wtf/RefCounted.h> #if PLATFORM(CAIRO) typedef struct _cairo cairo_t; diff --git a/Source/WebCore/platform/graphics/Font.cpp b/Source/WebCore/platform/graphics/Font.cpp index ee85e45..72e3e3b 100644 --- a/Source/WebCore/platform/graphics/Font.cpp +++ b/Source/WebCore/platform/graphics/Font.cpp @@ -177,7 +177,7 @@ float Font::width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFo // If the complex text implementation cannot return fallback fonts, avoid // returning them for simple text as well. static bool returnFallbackFonts = canReturnFallbackFontsForComplexText(); - return floatWidthForSimpleText(run, 0, returnFallbackFonts ? fallbackFonts : 0, codePathToUse == SimpleWithGlyphOverflow ? glyphOverflow : 0); + return floatWidthForSimpleText(run, 0, returnFallbackFonts ? fallbackFonts : 0, codePathToUse == SimpleWithGlyphOverflow || (glyphOverflow && glyphOverflow->computeBounds) ? glyphOverflow : 0); } return floatWidthForComplexText(run, fallbackFonts, glyphOverflow); diff --git a/Source/WebCore/platform/graphics/Font.h b/Source/WebCore/platform/graphics/Font.h index ce03aed..554f8a0 100644 --- a/Source/WebCore/platform/graphics/Font.h +++ b/Source/WebCore/platform/graphics/Font.h @@ -61,6 +61,7 @@ struct GlyphOverflow { , right(0) , top(0) , bottom(0) + , computeBounds(false) { } @@ -68,8 +69,10 @@ struct GlyphOverflow { int right; int top; int bottom; + bool computeBounds; }; + class Font { public: Font(); @@ -138,8 +141,6 @@ public: const FontData* fontDataAt(unsigned) const; GlyphData glyphDataForCharacter(UChar32, bool mirror, FontDataVariant = AutoVariant) const; bool primaryFontHasGlyphForCharacter(UChar32) const; - // Used for complex text, and does not utilize the glyph map cache. - const FontData* fontDataForCharacters(const UChar*, int length) const; static bool isCJKIdeograph(UChar32); static bool isCJKIdeographOrSymbol(UChar32); @@ -255,12 +256,6 @@ inline const FontData* Font::fontDataAt(unsigned index) const return m_fontList->fontDataAt(this, index); } -inline const FontData* Font::fontDataForCharacters(const UChar* characters, int length) const -{ - ASSERT(m_fontList); - return m_fontList->fontDataForCharacters(this, characters, length); -} - inline bool Font::isFixedPitch() const { ASSERT(m_fontList); diff --git a/Source/WebCore/platform/graphics/FontCache.cpp b/Source/WebCore/platform/graphics/FontCache.cpp index 5b508be..8c5edfe 100644 --- a/Source/WebCore/platform/graphics/FontCache.cpp +++ b/Source/WebCore/platform/graphics/FontCache.cpp @@ -57,7 +57,8 @@ struct FontPlatformDataCacheKey { WTF_MAKE_FAST_ALLOCATED; public: FontPlatformDataCacheKey(const AtomicString& family = AtomicString(), unsigned size = 0, unsigned weight = 0, bool italic = false, - bool isPrinterFont = false, FontRenderingMode renderingMode = NormalRenderingMode, FontOrientation orientation = Horizontal, FontWidthVariant widthVariant = RegularWidth) + bool isPrinterFont = false, FontRenderingMode renderingMode = NormalRenderingMode, FontOrientation orientation = Horizontal, + TextOrientation textOrientation = TextOrientationVerticalRight, FontWidthVariant widthVariant = RegularWidth) : m_size(size) , m_weight(weight) , m_family(family) @@ -65,6 +66,7 @@ public: , m_printerFont(isPrinterFont) , m_renderingMode(renderingMode) , m_orientation(orientation) + , m_textOrientation(textOrientation) , m_widthVariant(widthVariant) { } @@ -76,7 +78,7 @@ public: { return equalIgnoringCase(m_family, other.m_family) && m_size == other.m_size && m_weight == other.m_weight && m_italic == other.m_italic && m_printerFont == other.m_printerFont && - m_renderingMode == other.m_renderingMode && m_orientation == other.m_orientation && m_widthVariant == other.m_widthVariant; + m_renderingMode == other.m_renderingMode && m_orientation == other.m_orientation && m_textOrientation == other.m_textOrientation && m_widthVariant == other.m_widthVariant; } unsigned m_size; @@ -86,6 +88,7 @@ public: bool m_printerFont; FontRenderingMode m_renderingMode; FontOrientation m_orientation; + TextOrientation m_textOrientation; FontWidthVariant m_widthVariant; private: @@ -99,9 +102,9 @@ inline unsigned computeHash(const FontPlatformDataCacheKey& fontKey) fontKey.m_size, fontKey.m_weight, fontKey.m_widthVariant, - static_cast<unsigned>(fontKey.m_orientation) << 3 | static_cast<unsigned>(fontKey.m_italic) << 2 | static_cast<unsigned>(fontKey.m_printerFont) << 1 | static_cast<unsigned>(fontKey.m_renderingMode) + static_cast<unsigned>(fontKey.m_textOrientation) << 4 | static_cast<unsigned>(fontKey.m_orientation) << 3 | static_cast<unsigned>(fontKey.m_italic) << 2 | static_cast<unsigned>(fontKey.m_printerFont) << 1 | static_cast<unsigned>(fontKey.m_renderingMode) }; - return WTF::StringHasher::createBlobHash<sizeof(hashCodes)>(hashCodes); + return StringHasher::hashMemory<sizeof(hashCodes)>(hashCodes); } struct FontPlatformDataCacheKeyHash { @@ -198,7 +201,8 @@ FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& fo } FontPlatformDataCacheKey key(familyName, fontDescription.computedPixelSize(), fontDescription.weight(), fontDescription.italic(), - fontDescription.usePrinterFont(), fontDescription.renderingMode(), fontDescription.orientation(), fontDescription.widthVariant()); + fontDescription.usePrinterFont(), fontDescription.renderingMode(), fontDescription.orientation(), + fontDescription.textOrientation(), fontDescription.widthVariant()); FontPlatformData* result = 0; bool foundResult; FontPlatformDataCache::iterator it = gFontPlatformDataCache->find(key); diff --git a/Source/WebCore/platform/graphics/FontDescription.h b/Source/WebCore/platform/graphics/FontDescription.h index 283d297..5b05f14 100644 --- a/Source/WebCore/platform/graphics/FontDescription.h +++ b/Source/WebCore/platform/graphics/FontDescription.h @@ -31,6 +31,7 @@ #include "FontSmoothingMode.h" #include "FontTraitsMask.h" #include "FontWidthVariant.h" +#include "TextOrientation.h" #include "TextRenderingMode.h" namespace WebCore { @@ -58,6 +59,7 @@ public: : m_specifiedSize(0) , m_computedSize(0) , m_orientation(Horizontal) + , m_textOrientation(TextOrientationVerticalRight) , m_widthVariant(RegularWidth) , m_italic(false) , m_smallCaps(false) @@ -99,6 +101,7 @@ public: FontTraitsMask traitsMask() const; bool isSpecifiedFont() const { return m_isSpecifiedFont; } FontOrientation orientation() const { return m_orientation; } + TextOrientation textOrientation() const { return m_textOrientation; } FontWidthVariant widthVariant() const { return m_widthVariant; } void setFamily(const FontFamily& family) { m_familyList = family; } @@ -120,6 +123,7 @@ public: void setTextRenderingMode(TextRenderingMode rendering) { m_textRendering = rendering; } void setIsSpecifiedFont(bool isSpecifiedFont) { m_isSpecifiedFont = isSpecifiedFont; } void setOrientation(FontOrientation orientation) { m_orientation = orientation; } + void setTextOrientation(TextOrientation textOrientation) { m_textOrientation = textOrientation; } void setWidthVariant(FontWidthVariant widthVariant) { m_widthVariant = widthVariant; } private: @@ -129,8 +133,9 @@ private: // rounding, minimum font sizes, and zooming. float m_computedSize; // Computed size adjusted for the minimum font size and the zoom factor. - FontOrientation m_orientation; - + FontOrientation m_orientation; // Whether the font is rendering on a horizontal line or a vertical line. + TextOrientation m_textOrientation; // Only used by vertical text. Determines the default orientation for non-ideograph glyphs. + FontWidthVariant m_widthVariant; bool m_italic : 1; @@ -169,6 +174,7 @@ inline bool FontDescription::operator==(const FontDescription& other) const && m_textRendering == other.m_textRendering && m_isSpecifiedFont == other.m_isSpecifiedFont && m_orientation == other.m_orientation + && m_textOrientation == other.m_textOrientation && m_widthVariant == other.m_widthVariant; } diff --git a/Source/WebCore/platform/graphics/FontFallbackList.cpp b/Source/WebCore/platform/graphics/FontFallbackList.cpp index 649c117..7df58d9 100644 --- a/Source/WebCore/platform/graphics/FontFallbackList.cpp +++ b/Source/WebCore/platform/graphics/FontFallbackList.cpp @@ -111,23 +111,6 @@ const FontData* FontFallbackList::fontDataAt(const Font* font, unsigned realized return result; } -const FontData* FontFallbackList::fontDataForCharacters(const Font* font, const UChar* characters, int length) const -{ - // This method is only called when the primary font does not contain the characters we need. - // Begin our search at position 1. - unsigned realizedFontIndex = 1; - const FontData* fontData = fontDataAt(font, realizedFontIndex); - while (fontData && !fontData->containsCharacters(characters, length)) - fontData = fontDataAt(font, ++realizedFontIndex); - - if (!fontData) { - ASSERT(fontCache()->generation() == m_generation); - fontData = fontCache()->getFontDataForCharacters(*font, characters, length); - } - - return fontData; -} - void FontFallbackList::setPlatformFont(const FontPlatformData& platformData) { m_familyIndex = cAllFamiliesScanned; diff --git a/Source/WebCore/platform/graphics/FontFallbackList.h b/Source/WebCore/platform/graphics/FontFallbackList.h index a10f5af..e18477c 100644 --- a/Source/WebCore/platform/graphics/FontFallbackList.h +++ b/Source/WebCore/platform/graphics/FontFallbackList.h @@ -65,8 +65,7 @@ private: const FontData* primaryFontData(const Font* f) const { return fontDataAt(f, 0); } const FontData* fontDataAt(const Font*, unsigned index) const; - const FontData* fontDataForCharacters(const Font*, const UChar*, int length) const; - + void setPlatformFont(const FontPlatformData&); void releaseFontData(); diff --git a/Source/WebCore/platform/graphics/FontFastPath.cpp b/Source/WebCore/platform/graphics/FontFastPath.cpp index e62df61..b741ca0 100644 --- a/Source/WebCore/platform/graphics/FontFastPath.cpp +++ b/Source/WebCore/platform/graphics/FontFastPath.cpp @@ -77,17 +77,57 @@ GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, FontDataVariant va page = node->page(); if (page) { GlyphData data = page->glyphDataForCharacter(c); + if (data.fontData && (data.fontData->platformData().orientation() == Horizontal || data.fontData->isTextOrientationFallback())) + return data; + if (data.fontData) { - if (data.fontData->platformData().orientation() == Vertical && data.fontData->orientation() == Horizontal && Font::isCJKIdeographOrSymbol(c)) { - const SimpleFontData* ideographFontData = data.fontData->brokenIdeographFontData(); - GlyphPageTreeNode* ideographNode = GlyphPageTreeNode::getRootChild(ideographFontData, pageNumber); - const GlyphPage* ideographPage = ideographNode->page(); - if (ideographPage) { - GlyphData data = ideographPage->glyphDataForCharacter(c); - if (data.fontData) - return data; + if (isCJKIdeographOrSymbol(c)) { + if (!data.fontData->hasVerticalGlyphs()) { + // Use the broken ideograph font data. The broken ideograph font will use the horizontal width of glyphs + // to make sure you get a square (even for broken glyphs like symbols used for punctuation). + const SimpleFontData* brokenIdeographFontData = data.fontData->brokenIdeographFontData(); + GlyphPageTreeNode* brokenIdeographNode = GlyphPageTreeNode::getRootChild(brokenIdeographFontData, pageNumber); + const GlyphPage* brokenIdeographPage = brokenIdeographNode->page(); + if (brokenIdeographPage) { + GlyphData brokenIdeographData = brokenIdeographPage->glyphDataForCharacter(c); + if (brokenIdeographData.fontData) + return brokenIdeographData; + } + + // Shouldn't be possible to even reach this point. + ASSERT_NOT_REACHED(); + } + } else { + if (m_fontDescription.textOrientation() == TextOrientationVerticalRight) { + const SimpleFontData* verticalRightFontData = data.fontData->verticalRightOrientationFontData(); + GlyphPageTreeNode* verticalRightNode = GlyphPageTreeNode::getRootChild(verticalRightFontData, pageNumber); + const GlyphPage* verticalRightPage = verticalRightNode->page(); + if (verticalRightPage) { + GlyphData verticalRightData = verticalRightPage->glyphDataForCharacter(c); + // If the glyphs are distinct, we will make the assumption that the font has a vertical-right glyph baked + // into it. + if (data.glyph != verticalRightData.glyph) + return data; + // The glyphs are identical, meaning that we should just use the horizontal glyph. + if (verticalRightData.fontData) + return verticalRightData; + } + } else if (m_fontDescription.textOrientation() == TextOrientationUpright) { + const SimpleFontData* uprightFontData = data.fontData->uprightOrientationFontData(); + GlyphPageTreeNode* uprightNode = GlyphPageTreeNode::getRootChild(uprightFontData, pageNumber); + const GlyphPage* uprightPage = uprightNode->page(); + if (uprightPage) { + GlyphData uprightData = uprightPage->glyphDataForCharacter(c); + // If the glyphs are the same, then we know we can just use the horizontal glyph rotated vertically to be upright. + if (data.glyph == uprightData.glyph) + return data; + // The glyphs are distinct, meaning that the font has a vertical-right glyph baked into it. We can't use that + // glyph, so we fall back to the upright data and use the horizontal glyph. + if (uprightData.fontData) + return uprightData; + } } - + // Shouldn't be possible to even reach this point. ASSERT_NOT_REACHED(); } @@ -364,7 +404,7 @@ void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuf inline static float offsetToMiddleOfGlyph(const SimpleFontData* fontData, Glyph glyph) { - if (fontData->orientation() == Horizontal) { + if (fontData->platformData().orientation() == Horizontal) { FloatRect bounds = fontData->boundsForGlyph(glyph); return bounds.x() + bounds.width() / 2; } @@ -412,8 +452,8 @@ float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer it.advance(run.length(), glyphBuffer); if (glyphOverflow) { - glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-it.minGlyphBoundingBoxY()) - fontMetrics().ascent()); - glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(it.maxGlyphBoundingBoxY()) - fontMetrics().descent()); + glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-it.minGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().ascent())); + glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(it.maxGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().descent())); glyphOverflow->left = ceilf(it.firstGlyphOverflow()); glyphOverflow->right = ceilf(it.lastGlyphOverflow()); } diff --git a/Source/WebCore/platform/graphics/FontPlatformData.cpp b/Source/WebCore/platform/graphics/FontPlatformData.cpp new file mode 100644 index 0000000..5a61cdf --- /dev/null +++ b/Source/WebCore/platform/graphics/FontPlatformData.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2011 Brent Fulgham + * + * 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 "FontPlatformData.h" + +#include "PlatformString.h" +#include <wtf/HashMap.h> +#include <wtf/RetainPtr.h> +#include <wtf/Vector.h> +#include <wtf/text/StringHash.h> + +using namespace std; + +namespace WebCore { + +FontPlatformData::FontPlatformData(const FontPlatformData& source) + : m_syntheticBold(source.m_syntheticBold) + , m_syntheticOblique(source.m_syntheticOblique) + , m_orientation(source.m_orientation) + , m_textOrientation(source.m_textOrientation) + , m_size(source.m_size) + , m_widthVariant(source.m_widthVariant) + , m_isColorBitmapFont(source.m_isColorBitmapFont) +{ + platformDataInit(source); +} + +const FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other) +{ + // Check for self-assignment. + if (this == &other) + return *this; + + m_syntheticBold = other.m_syntheticBold; + m_syntheticOblique = other.m_syntheticOblique; + m_orientation = other.m_orientation; + m_textOrientation = other.m_textOrientation; + m_size = other.m_size; + m_widthVariant = other.m_widthVariant; + m_isColorBitmapFont = other.m_isColorBitmapFont; + + return platformDataAssign(other); +} + +} diff --git a/Source/WebCore/platform/graphics/FontPlatformData.h b/Source/WebCore/platform/graphics/FontPlatformData.h new file mode 100644 index 0000000..5981c16 --- /dev/null +++ b/Source/WebCore/platform/graphics/FontPlatformData.h @@ -0,0 +1,361 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2007 Holger Hans Peter Freyther + * Copyright (C) 2007 Pioneer Research Center USA, Inc. + * Copyright (C) 2010, 2011 Brent Fulgham <bfulgham@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * 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. + * + */ + +// FIXME: This is temporary until all ports switch to using this file. +#if PLATFORM(CHROMIUM) && !OS(DARWIN) +#include "chromium/FontPlatformData.h" +#elif PLATFORM(QT) +#include "qt/FontPlatformData.h" +#elif PLATFORM(WIN) && OS(WINCE) +#include "wince/FontPlatformData.h" +#elif PLATFORM(WX) +#include "wx/FontPlatformData.h" +#elif (PLATFORM(EFL) || PLATFORM(GTK)) && USE(FREETYPE) +#include "freetype/FontPlatformData.h" +#elif (PLATFORM(EFL) || PLATFORM(GTK)) && USE(PANGO) +#include "pango/FontPlatformData.h" +#elif PLATFORM(ANDROID) +#include "android/FontPlatformData.h" +#else + +#ifndef FontPlatformData_h +#define FontPlatformData_h + +#include "FontOrientation.h" +#include "FontWidthVariant.h" +#include "GlyphBuffer.h" +#include "TextOrientation.h" + +#if PLATFORM(WIN) +#include "RefCountedGDIHandle.h" +#endif + +#if PLATFORM(CAIRO) +#include "HashFunctions.h" +#include <cairo.h> +#endif + +#if OS(DARWIN) +#ifdef __OBJC__ +@class NSFont; +#else +class NSFont; +#endif + +typedef struct CGFont* CGFontRef; +#ifndef BUILDING_ON_TIGER +typedef const struct __CTFont* CTFontRef; +#endif + +#include <CoreFoundation/CFBase.h> +#include <objc/objc-auto.h> +#endif + +#include <wtf/Forward.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RetainPtr.h> +#include <wtf/text/StringImpl.h> + +#if PLATFORM(CHROMIUM) && OS(DARWIN) +#include "CrossProcessFontLoading.h" +#endif + +#if PLATFORM(WIN) +typedef struct HFONT__* HFONT; +#endif + +#if PLATFORM(CG) +typedef struct CGFont* CGFontRef; +#if OS(DARWIN) +#ifndef BUILDING_ON_TIGER +typedef const struct __CTFont* CTFontRef; +typedef UInt32 ATSUFontID; +typedef UInt32 ATSFontRef; +#endif +#endif +#endif + +namespace WebCore { + +class FontDescription; + +#if OS(DARWIN) && !defined(BUILDING_ON_TIGER) +inline CTFontRef toCTFontRef(NSFont *nsFont) { return reinterpret_cast<CTFontRef>(nsFont); } +#endif + +class FontPlatformData { +public: + FontPlatformData(WTF::HashTableDeletedValueType) + : m_syntheticBold(false) + , m_syntheticOblique(false) + , m_orientation(Horizontal) + , m_textOrientation(TextOrientationVerticalRight) + , m_size(0) + , m_widthVariant(RegularWidth) +#if PLATFORM(WIN) + , m_font(WTF::HashTableDeletedValue) +#elif OS(DARWIN) + , m_font(hashTableDeletedFontValue()) +#endif +#if PLATFORM(CG) && (defined(BUILDING_ON_TIGER) || PLATFORM(WIN)) + , m_cgFont(0) +#elif PLATFORM(CAIRO) + , m_scaledFont(hashTableDeletedFontValue()) +#endif + , m_isColorBitmapFont(false) +#if PLATFORM(WIN) + , m_useGDI(false) +#endif + { + } + + FontPlatformData() + : m_syntheticBold(false) + , m_syntheticOblique(false) + , m_orientation(Horizontal) + , m_textOrientation(TextOrientationVerticalRight) + , m_size(0) + , m_widthVariant(RegularWidth) +#if OS(DARWIN) + , m_font(0) +#endif +#if PLATFORM(CG) && (defined(BUILDING_ON_TIGER) || PLATFORM(WIN)) + , m_cgFont(0) +#elif PLATFORM(CAIRO) + , m_scaledFont(0) +#endif + , m_isColorBitmapFont(false) +#if PLATFORM(WIN) + , m_useGDI(false) +#endif + { + } + + FontPlatformData(const FontPlatformData&); + FontPlatformData(const FontDescription&, const AtomicString& family); + FontPlatformData(float size, bool syntheticBold, bool syntheticOblique, FontOrientation orientation = Horizontal, + TextOrientation textOrientation = TextOrientationVerticalRight, FontWidthVariant widthVariant = RegularWidth) + : m_syntheticBold(syntheticBold) + , m_syntheticOblique(syntheticOblique) + , m_orientation(orientation) + , m_textOrientation(textOrientation) + , m_size(size) + , m_widthVariant(widthVariant) +#if OS(DARWIN) + , m_font(0) +#endif +#if PLATFORM(CG) && (defined(BUILDING_ON_TIGER) || PLATFORM(WIN)) + , m_cgFont(0) +#elif PLATFORM(CAIRO) + , m_scaledFont(0) +#endif + , m_isColorBitmapFont(false) +#if PLATFORM(WIN) + , m_useGDI(false) +#endif + { + } + +#if OS(DARWIN) + FontPlatformData(NSFont*, float size, bool syntheticBold = false, bool syntheticOblique = false, FontOrientation = Horizontal, + TextOrientation = TextOrientationVerticalRight, FontWidthVariant = RegularWidth); + FontPlatformData(CGFontRef cgFont, float size, bool syntheticBold, bool syntheticOblique, FontOrientation orientation, + TextOrientation textOrientation, FontWidthVariant widthVariant) + : m_syntheticBold(syntheticBold) + , m_syntheticOblique(syntheticOblique) + , m_orientation(orientation) + , m_textOrientation(textOrientation) + , m_size(size) + , m_widthVariant(widthVariant) + , m_font(0) + , m_cgFont(cgFont) + , m_isColorBitmapFont(false) + { + } +#endif +#if PLATFORM(WIN) + FontPlatformData(HFONT, float size, bool syntheticBold, bool syntheticOblique, bool useGDI); +#if PLATFORM(CG) + FontPlatformData(HFONT, CGFontRef, float size, bool syntheticBold, bool syntheticOblique, bool useGDI); +#endif +#endif +#if PLATFORM(CAIRO) + FontPlatformData(cairo_font_face_t*, float size, bool bold, bool italic); +#endif + + ~FontPlatformData(); + +#if PLATFORM(WIN) + HFONT hfont() const { return m_font ? m_font->handle() : 0; } + bool useGDI() const { return m_useGDI; } +#elif OS(DARWIN) + NSFont* font() const { return m_font; } + void setFont(NSFont*); +#endif + +#if PLATFORM(CG) +#if OS(DARWIN) +#ifndef BUILDING_ON_TIGER + CGFontRef cgFont() const { return m_cgFont.get(); } +#else + CGFontRef cgFont() const { return m_cgFont; } +#endif + CTFontRef ctFont() const; + + bool roundsGlyphAdvances() const; + bool allowsLigatures() const; +#else + CGFontRef cgFont() const { return m_cgFont.get(); } +#endif +#endif + + bool isFixedPitch() const; + float size() const { return m_size; } + void setSize(float size) { m_size = size; } + bool syntheticBold() const { return m_syntheticBold; } + bool syntheticOblique() const { return m_syntheticOblique; } + bool isColorBitmapFont() const { return m_isColorBitmapFont; } + FontOrientation orientation() const { return m_orientation; } + TextOrientation textOrientation() const { return m_textOrientation; } + FontWidthVariant widthVariant() const { return m_widthVariant; } + + void setOrientation(FontOrientation orientation) { m_orientation = orientation; } + +#if PLATFORM(CAIRO) + cairo_scaled_font_t* scaledFont() const { return m_scaledFont; } +#endif + + unsigned hash() const + { +#if PLATFORM(WIN) && !PLATFORM(CAIRO) + return m_font ? m_font->hash() : 0; +#elif OS(DARWIN) + ASSERT(m_font || !m_cgFont); + 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) + return PtrHash<cairo_scaled_font_t*>::hash(m_scaledFont); +#endif + } + + const FontPlatformData& operator=(const FontPlatformData&); + + bool operator==(const FontPlatformData& other) const + { + return platformIsEqual(other) + && m_size == other.m_size + && m_syntheticBold == other.m_syntheticBold + && m_syntheticOblique == other.m_syntheticOblique + && m_isColorBitmapFont == other.m_isColorBitmapFont + && m_orientation == other.m_orientation + && m_textOrientation == other.m_textOrientation + && m_widthVariant == other.m_widthVariant; + } + + bool isHashTableDeletedValue() const + { +#if PLATFORM(WIN) && !PLATFORM(CAIRO) + return m_font.isHashTableDeletedValue(); +#elif OS(DARWIN) + return m_font == hashTableDeletedFontValue(); +#elif PLATFORM(CAIRO) + return m_scaledFont == hashTableDeletedFontValue(); +#endif + } + + +#ifndef NDEBUG + String description() const; +#endif + +private: + bool platformIsEqual(const FontPlatformData&) const; + void platformDataInit(const FontPlatformData&); + const FontPlatformData& platformDataAssign(const FontPlatformData&); +#if OS(DARWIN) + // Load various data about the font specified by |nsFont| with the size fontSize into the following output paramters: + // Note: Callers should always take into account that for the Chromium port, |outNSFont| isn't necessarily the same + // font as |nsFont|. This because the sandbox may block loading of the original font. + // * outNSFont - The font that was actually loaded, for the Chromium port this may be different than nsFont. + // The caller is responsible for calling CFRelease() on this parameter when done with it. + // * cgFont - CGFontRef representing the input font at the specified point size. + void loadFont(NSFont*, float fontSize, NSFont*& outNSFont, CGFontRef&); + static NSFont* hashTableDeletedFontValue() { return reinterpret_cast<NSFont *>(-1); } +#elif PLATFORM(WIN) + void platformDataInit(HFONT, float size, HDC, WCHAR* faceName); +#endif + +#if PLATFORM(CAIRO) + static cairo_scaled_font_t* hashTableDeletedFontValue() { return reinterpret_cast<cairo_scaled_font_t*>(-1); } +#endif + +public: + bool m_syntheticBold; + bool m_syntheticOblique; + FontOrientation m_orientation; + TextOrientation m_textOrientation; + float m_size; + FontWidthVariant m_widthVariant; + +private: +#if OS(DARWIN) + NSFont* m_font; +#elif PLATFORM(WIN) + RefPtr<RefCountedGDIHandle<HFONT> > m_font; +#endif + +#if PLATFORM(CG) +#if PLATFORM(WIN) + RetainPtr<CGFontRef> m_cgFont; +#else +#ifndef BUILDING_ON_TIGER + RetainPtr<CGFontRef> m_cgFont; +#else + CGFontRef m_cgFont; // It is not necessary to refcount this, since either an NSFont owns it or some CachedFont has it referenced. +#endif + mutable RetainPtr<CTFontRef> m_CTFont; +#endif +#endif + +#if PLATFORM(CAIRO) + cairo_scaled_font_t* m_scaledFont; +#endif + +#if PLATFORM(CHROMIUM) && OS(DARWIN) + RefPtr<MemoryActivatedFont> m_inMemoryFont; +#endif + + bool m_isColorBitmapFont; + +#if PLATFORM(WIN) + bool m_useGDI; +#endif +}; + +} // namespace WebCore + +#endif // FontPlatformData_h + +#endif diff --git a/Source/WebCore/platform/graphics/GraphicsContext.h b/Source/WebCore/platform/graphics/GraphicsContext.h index 5eafa16..c555a5f 100644 --- a/Source/WebCore/platform/graphics/GraphicsContext.h +++ b/Source/WebCore/platform/graphics/GraphicsContext.h @@ -42,8 +42,9 @@ typedef struct CGContext PlatformGraphicsContext; #elif PLATFORM(CAIRO) namespace WebCore { class ContextShadow; +class PlatformContextCairo; } -typedef struct _cairo PlatformGraphicsContext; +typedef WebCore::PlatformContextCairo PlatformGraphicsContext; #elif PLATFORM(OPENVG) namespace WebCore { class SurfaceOpenVG; @@ -279,6 +280,9 @@ namespace WebCore { void setIsCALayerContext(bool); bool isCALayerContext() const; + + void setIsAcceleratedContext(bool); + bool isAcceleratedContext() const; #endif #if PLATFORM(ANDROID) @@ -522,6 +526,7 @@ namespace WebCore { #endif #if PLATFORM(CAIRO) + GraphicsContext(cairo_t*); void pushImageMask(cairo_surface_t*, const FloatRect&); #endif diff --git a/Source/WebCore/platform/graphics/GraphicsContext3D.h b/Source/WebCore/platform/graphics/GraphicsContext3D.h index a9db650..351b445 100644 --- a/Source/WebCore/platform/graphics/GraphicsContext3D.h +++ b/Source/WebCore/platform/graphics/GraphicsContext3D.h @@ -51,8 +51,8 @@ @class CALayer; @class WebGLLayer; #else -typedef void* CALayer; -typedef void* WebGLLayer; +class CALayer; +class WebGLLayer; #endif #elif PLATFORM(QT) QT_BEGIN_NAMESPACE @@ -420,6 +420,7 @@ public: , antialias(true) , premultipliedAlpha(true) , canRecoverFromContextLoss(true) + , preserveDrawingBuffer(false) { } @@ -429,6 +430,7 @@ public: bool antialias; bool premultipliedAlpha; bool canRecoverFromContextLoss; + bool preserveDrawingBuffer; }; enum RenderStyle { @@ -449,8 +451,8 @@ public: #if PLATFORM(MAC) PlatformGraphicsContext3D platformGraphicsContext3D() const { return m_contextObj; } - Platform3DObject platformTexture() const { return m_texture; } - CALayer* platformLayer() const { return static_cast<CALayer*>(m_webGLLayer.get()); } + Platform3DObject platformTexture() const { return m_compositorTexture; } + CALayer* platformLayer() const { return reinterpret_cast<CALayer*>(m_webGLLayer.get()); } #elif PLATFORM(CHROMIUM) PlatformGraphicsContext3D platformGraphicsContext3D() const; Platform3DObject platformTexture() const; @@ -461,7 +463,7 @@ public: PlatformGraphicsContext3D platformGraphicsContext3D(); Platform3DObject platformTexture() const; #if USE(ACCELERATED_COMPOSITING) - PlatformLayer* platformLayer() const { return 0; } + PlatformLayer* platformLayer() const; #endif #else PlatformGraphicsContext3D platformGraphicsContext3D() const { return NullPlatformGraphicsContext3D; } @@ -756,10 +758,14 @@ public: int canvasWidth, int canvasHeight, CGContextRef context); #endif + void markContextChanged(); + void markLayerComposited(); + bool layerComposited() const; + void paintRenderingResultsToCanvas(CanvasRenderingContext* context); + PassRefPtr<ImageData> paintRenderingResultsToImageData(); #if PLATFORM(QT) - void paint(QPainter* painter, const QRect& rect) const; bool paintsIntoCanvasBuffer() const { return true; } #elif PLATFORM(CHROMIUM) bool paintsIntoCanvasBuffer() const; @@ -859,6 +865,10 @@ public: // could not be honored based on the capabilities of the OpenGL // implementation. void validateAttributes(); + + // Read rendering results into a pixel array with the same format as the + // backbuffer. + void readRenderingResults(unsigned char* pixels, int pixelsSize); #endif int m_currentWidth, m_currentHeight; @@ -881,12 +891,16 @@ public: CGLContextObj m_contextObj; RetainPtr<WebGLLayer> m_webGLLayer; - GC3Duint m_texture; + GC3Duint m_texture, m_compositorTexture; GC3Duint m_fbo; GC3Duint m_depthStencilBuffer; + bool m_layerComposited; + GC3Duint m_internalColorFormat; - // For tracking which FBO is bound + // For tracking which FBO/texture is bound GC3Duint m_boundFBO; + GC3Denum m_activeTexture; + GC3Duint m_boundTexture0; // For multisampling GC3Duint m_multisampleFBO; diff --git a/Source/WebCore/platform/graphics/GraphicsLayer.h b/Source/WebCore/platform/graphics/GraphicsLayer.h index e3a62b6..4f234d4 100644 --- a/Source/WebCore/platform/graphics/GraphicsLayer.h +++ b/Source/WebCore/platform/graphics/GraphicsLayer.h @@ -46,12 +46,11 @@ #if PLATFORM(MAC) #ifdef __OBJC__ -@class WebLayer; @class CALayer; -typedef CALayer PlatformLayer; #else -typedef void* PlatformLayer; +class CALayer; #endif +typedef CALayer PlatformLayer; #elif PLATFORM(WIN) typedef struct _CACFLayer PlatformLayer; #elif PLATFORM(QT) diff --git a/Source/WebCore/platform/graphics/ImageBuffer.h b/Source/WebCore/platform/graphics/ImageBuffer.h index 48878da..860f574 100644 --- a/Source/WebCore/platform/graphics/ImageBuffer.h +++ b/Source/WebCore/platform/graphics/ImageBuffer.h @@ -132,6 +132,10 @@ namespace WebCore { ImageBuffer(const IntSize&, ColorSpace colorSpace, RenderingMode renderingMode, bool& success); }; +#if PLATFORM(CG) || USE(SKIA) + String ImageDataToDataURL(const ImageData& input, const String& mimeType, const double* quality); +#endif + } // namespace WebCore #endif // ImageBuffer_h diff --git a/Source/WebCore/platform/graphics/MediaPlayer.cpp b/Source/WebCore/platform/graphics/MediaPlayer.cpp index 70576a5..03004b6 100644 --- a/Source/WebCore/platform/graphics/MediaPlayer.cpp +++ b/Source/WebCore/platform/graphics/MediaPlayer.cpp @@ -47,6 +47,9 @@ #if PLATFORM(MAC) #include "MediaPlayerPrivateQTKit.h" +#if USE(AVFOUNDATION) +#include "MediaPlayerPrivateAVFoundationObjC.h" +#endif #define PlatformMediaEngineClassName MediaPlayerPrivateQTKit #elif OS(WINCE) && !PLATFORM(QT) #include "MediaPlayerPrivateWinCE.h" @@ -82,7 +85,7 @@ public: virtual void load(const String&) { } virtual void cancelLoad() { } - + virtual void prepareToPlay() { } virtual void play() { } virtual void pause() { } @@ -189,11 +192,15 @@ static Vector<MediaPlayerFactory*>& installedMediaEngines() MediaPlayerPrivateGStreamer::registerMediaEngine(addMediaEngine); #endif +#if USE(AVFOUNDATION) && PLATFORM(MAC) + MediaPlayerPrivateAVFoundationObjC::registerMediaEngine(addMediaEngine); +#endif + #if !PLATFORM(GTK) && !PLATFORM(EFL) && !(PLATFORM(QT) && USE(GSTREAMER)) PlatformMediaEngineClassName::registerMediaEngine(addMediaEngine); #endif } - + return installedEngines; } @@ -241,7 +248,7 @@ static MediaPlayerFactory* bestMediaEngineForTypeAndCodecs(const String& type, c if (!codecs.isEmpty()) return 0; } - + MediaPlayerFactory* engine = 0; MediaPlayer::SupportsType supported = MediaPlayer::IsNotSupported; unsigned count = engines.size(); @@ -292,6 +299,7 @@ MediaPlayer::MediaPlayer(MediaPlayerClient* client) , m_muted(false) , m_preservesPitch(true) , m_privateBrowsing(false) + , m_shouldPrepareToRender(false) #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) , m_playerProxy(0) #endif @@ -351,7 +359,7 @@ void MediaPlayer::loadWithNextMediaEngine(MediaPlayerFactory* current) engine = nextMediaEngine(current); else engine = bestMediaEngineForTypeAndCodecs(m_contentMIMEType, m_contentTypeCodecs, current); - + // Don't delete and recreate the player unless it comes from a different engine. if (!engine) { m_currentMediaEngine = engine; @@ -368,6 +376,8 @@ void MediaPlayer::loadWithNextMediaEngine(MediaPlayerFactory* current) m_private->setPrivateBrowsingMode(m_privateBrowsing); m_private->setPreload(m_preload); m_private->setPreservesPitch(preservesPitch()); + if (m_shouldPrepareToRender) + m_private->prepareForRendering(); } if (m_private) @@ -383,17 +393,18 @@ bool MediaPlayer::hasAvailableVideoFrame() const { return m_private->hasAvailableVideoFrame(); } - + void MediaPlayer::prepareForRendering() { - return m_private->prepareForRendering(); + m_shouldPrepareToRender = true; + m_private->prepareForRendering(); } - + bool MediaPlayer::canLoadPoster() const { return m_private->canLoadPoster(); } - + void MediaPlayer::setPoster(const String& url) { m_private->setPoster(url); @@ -408,7 +419,7 @@ void MediaPlayer::prepareToPlay() { m_private->prepareToPlay(); } - + void MediaPlayer::play() { m_private->play(); @@ -478,7 +489,7 @@ bool MediaPlayer::inMediaDocument() { Frame* frame = m_frameView ? m_frameView->frame() : 0; Document* document = frame ? frame->document() : 0; - + return document && document->isMediaDocument(); } diff --git a/Source/WebCore/platform/graphics/MediaPlayer.h b/Source/WebCore/platform/graphics/MediaPlayer.h index f41af01..ff304ea 100644 --- a/Source/WebCore/platform/graphics/MediaPlayer.h +++ b/Source/WebCore/platform/graphics/MediaPlayer.h @@ -46,8 +46,10 @@ #endif #ifdef __OBJC__ +@class AVPlayer; @class QTMovie; #else +class AVPlayer; class QTMovie; #endif class QTMovieGWorld; @@ -71,6 +73,7 @@ struct PlatformMedia { GStreamerGWorldType, ChromiumMediaPlayerType, QtMediaPlayerType, + AVFoundationMediaPlayerType, } type; union { @@ -80,6 +83,7 @@ struct PlatformMedia { GStreamerGWorld* gstreamerGWorld; MediaPlayerPrivateInterface* chromiumMediaPlayer; MediaPlayerPrivateInterface* qtMediaPlayer; + AVPlayer* avfMediaPlayer; } media; }; @@ -115,10 +119,10 @@ public: // time has jumped, eg. not as a result of normal playback virtual void mediaPlayerTimeChanged(MediaPlayer*) { } - + // the media file duration has changed, or is now known virtual void mediaPlayerDurationChanged(MediaPlayer*) { } - + // the playback rate has changed virtual void mediaPlayerRateChanged(MediaPlayer*) { } @@ -183,44 +187,44 @@ public: void setMediaElementType(MediaElementType type) { m_mediaElementType = type; } MediaElementType mediaElementType() { return m_mediaElementType; } #endif - + void setFrameView(FrameView* frameView) { m_frameView = frameView; } FrameView* frameView() { return m_frameView; } bool inMediaDocument(); - + IntSize size() const { return m_size; } void setSize(const IntSize& size); - + void load(const String& url, const ContentType&); void cancelLoad(); - + bool visible() const; void setVisible(bool); - + void prepareToPlay(); void play(); void pause(); - + bool paused() const; bool seeking() const; - + float duration() const; float currentTime() const; void seek(float time); float startTime() const; - + float rate() const; void setRate(float); bool preservesPitch() const; void setPreservesPitch(bool); - + PassRefPtr<TimeRanges> buffered(); float maxTimeSeekable(); unsigned bytesLoaded(); - + float volume() const; void setVolume(float); @@ -235,13 +239,13 @@ public: void paint(GraphicsContext*, const IntRect&); void paintCurrentFrameInContext(GraphicsContext*, const IntRect&); - + enum NetworkState { Empty, Idle, Loading, Loaded, FormatError, NetworkError, DecodeError }; NetworkState networkState(); enum ReadyState { HaveNothing, HaveMetadata, HaveCurrentData, HaveFutureData, HaveEnoughData }; ReadyState readyState(); - + enum MovieLoadType { Unknown, Download, StoredStream, LiveStream }; MovieLoadType movieLoadType() const; @@ -320,6 +324,7 @@ private: bool m_muted; bool m_preservesPitch; bool m_privateBrowsing; + bool m_shouldPrepareToRender; #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) WebMediaPlayerProxy* m_playerProxy; // not owned or used, passed to m_private #endif diff --git a/Source/WebCore/platform/graphics/Path.cpp b/Source/WebCore/platform/graphics/Path.cpp index 55760b1..f7aedbe 100644 --- a/Source/WebCore/platform/graphics/Path.cpp +++ b/Source/WebCore/platform/graphics/Path.cpp @@ -83,14 +83,14 @@ static void pathLengthApplierFunction(void* info, const PathElement* element) } } -float Path::length() +float Path::length() const { PathTraversalState traversalState(PathTraversalState::TraversalTotalLength); apply(&traversalState, pathLengthApplierFunction); return traversalState.m_totalLength; } -FloatPoint Path::pointAtLength(float length, bool& ok) +FloatPoint Path::pointAtLength(float length, bool& ok) const { PathTraversalState traversalState(PathTraversalState::TraversalPointAtLength); traversalState.m_desiredLength = length; @@ -99,10 +99,10 @@ FloatPoint Path::pointAtLength(float length, bool& ok) return traversalState.m_current; } -float Path::normalAngleAtLength(float length, bool& ok) +float Path::normalAngleAtLength(float length, bool& ok) const { PathTraversalState traversalState(PathTraversalState::TraversalNormalAngleAtLength); - traversalState.m_desiredLength = length; + traversalState.m_desiredLength = length ? length : std::numeric_limits<float>::epsilon(); apply(&traversalState, pathLengthApplierFunction); ok = traversalState.m_success; return traversalState.m_normalAngle; diff --git a/Source/WebCore/platform/graphics/Path.h b/Source/WebCore/platform/graphics/Path.h index 31f2cd6..c2ca576 100644 --- a/Source/WebCore/platform/graphics/Path.h +++ b/Source/WebCore/platform/graphics/Path.h @@ -112,11 +112,11 @@ namespace WebCore { bool contains(const FloatPoint&, WindRule rule = RULE_NONZERO) const; bool strokeContains(StrokeStyleApplier*, const FloatPoint&) const; FloatRect boundingRect() const; - FloatRect strokeBoundingRect(StrokeStyleApplier* = 0); + FloatRect strokeBoundingRect(StrokeStyleApplier* = 0) const; - float length(); - FloatPoint pointAtLength(float length, bool& ok); - float normalAngleAtLength(float length, bool& ok); + float length() const; + FloatPoint pointAtLength(float length, bool& ok) const; + float normalAngleAtLength(float length, bool& ok) const; void clear(); bool isEmpty() const; diff --git a/Source/WebCore/platform/graphics/SimpleFontData.cpp b/Source/WebCore/platform/graphics/SimpleFontData.cpp index aaab666..82f770d 100644 --- a/Source/WebCore/platform/graphics/SimpleFontData.cpp +++ b/Source/WebCore/platform/graphics/SimpleFontData.cpp @@ -47,15 +47,16 @@ using namespace std; namespace WebCore { -SimpleFontData::SimpleFontData(const FontPlatformData& platformData, bool isCustomFont, bool isLoading) +SimpleFontData::SimpleFontData(const FontPlatformData& platformData, bool isCustomFont, bool isLoading, bool isTextOrientationFallback) : m_maxCharWidth(-1) , m_avgCharWidth(-1) - , m_orientation(platformData.orientation()) , m_platformData(platformData) , m_treatAsFixedPitch(false) , m_isCustomFont(isCustomFont) , m_isLoading(isLoading) - , m_isBrokenIdeographFont(false) + , m_isTextOrientationFallback(isTextOrientationFallback) + , m_isBrokenIdeographFallback(false) + , m_hasVerticalGlyphs(false) { platformInit(); platformGlyphInit(); @@ -64,13 +65,14 @@ SimpleFontData::SimpleFontData(const FontPlatformData& platformData, bool isCust #if ENABLE(SVG_FONTS) SimpleFontData::SimpleFontData(PassOwnPtr<SVGFontData> svgFontData, int size, bool syntheticBold, bool syntheticItalic) - : m_orientation(Horizontal) - , m_platformData(FontPlatformData(size, syntheticBold, syntheticItalic)) + : m_platformData(FontPlatformData(size, syntheticBold, syntheticItalic)) , m_treatAsFixedPitch(false) , m_svgFontData(svgFontData) , m_isCustomFont(true) , m_isLoading(false) - , m_isBrokenIdeographFont(false) + , m_isTextOrientationFallback(false) + , m_isBrokenIdeographFallback(false) + , m_hasVerticalGlyphs(false) { SVGFontFaceElement* svgFontFaceElement = m_svgFontData->svgFontFaceElement(); unsigned unitsPerEm = svgFontFaceElement->unitsPerEm(); @@ -202,14 +204,34 @@ bool SimpleFontData::isSegmented() const return false; } +SimpleFontData* SimpleFontData::verticalRightOrientationFontData() const +{ + if (!m_derivedFontData) + m_derivedFontData = DerivedFontData::create(isCustomFont()); + if (!m_derivedFontData->verticalRightOrientation) { + FontPlatformData verticalRightPlatformData(m_platformData); + verticalRightPlatformData.setOrientation(Horizontal); + m_derivedFontData->verticalRightOrientation = new SimpleFontData(verticalRightPlatformData, isCustomFont(), false, true); + } + return m_derivedFontData->verticalRightOrientation.get(); +} + +SimpleFontData* SimpleFontData::uprightOrientationFontData() const +{ + if (!m_derivedFontData) + m_derivedFontData = DerivedFontData::create(isCustomFont()); + if (!m_derivedFontData->uprightOrientation) + m_derivedFontData->uprightOrientation = new SimpleFontData(m_platformData, isCustomFont(), false, true); + return m_derivedFontData->uprightOrientation.get(); +} + SimpleFontData* SimpleFontData::brokenIdeographFontData() const { if (!m_derivedFontData) m_derivedFontData = DerivedFontData::create(isCustomFont()); if (!m_derivedFontData->brokenIdeograph) { m_derivedFontData->brokenIdeograph = new SimpleFontData(m_platformData, isCustomFont(), false); - m_derivedFontData->brokenIdeograph->m_orientation = Vertical; - m_derivedFontData->brokenIdeograph->m_isBrokenIdeographFont = true; + m_derivedFontData->brokenIdeograph->m_isBrokenIdeographFallback = true; } return m_derivedFontData->brokenIdeograph.get(); } @@ -242,6 +264,10 @@ SimpleFontData::DerivedFontData::~DerivedFontData() GlyphPageTreeNode::pruneTreeCustomFontData(emphasisMark.get()); if (brokenIdeograph) GlyphPageTreeNode::pruneTreeCustomFontData(brokenIdeograph.get()); + if (verticalRightOrientation) + GlyphPageTreeNode::pruneTreeCustomFontData(verticalRightOrientation.get()); + if (uprightOrientation) + GlyphPageTreeNode::pruneTreeCustomFontData(uprightOrientation.get()); } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/SimpleFontData.h b/Source/WebCore/platform/graphics/SimpleFontData.h index 93d33bb..dfb4be3 100644 --- a/Source/WebCore/platform/graphics/SimpleFontData.h +++ b/Source/WebCore/platform/graphics/SimpleFontData.h @@ -71,7 +71,7 @@ enum Pitch { UnknownPitch, FixedPitch, VariablePitch }; class SimpleFontData : public FontData { public: - SimpleFontData(const FontPlatformData&, bool isCustomFont = false, bool isLoading = false); + SimpleFontData(const FontPlatformData&, bool isCustomFont = false, bool isLoading = false, bool isTextOrientationFallback = false); #if ENABLE(SVG_FONTS) SimpleFontData(PassOwnPtr<SVGFontData>, int size, bool syntheticBold, bool syntheticItalic); #endif @@ -97,11 +97,13 @@ public: return const_cast<SimpleFontData*>(this); } + SimpleFontData* verticalRightOrientationFontData() const; + SimpleFontData* uprightOrientationFontData() const; SimpleFontData* brokenIdeographFontData() const; - - // FIXME: Use the actual metrics for fonts with vertical tables instead of just hard-coding. If the font is horizontally oriented or - // a broken ideographic font, then just hard-code to split ascent/descent down the middle. Otherwise we should actually use the metrics - // from the font itself. + + bool hasVerticalGlyphs() const { return m_hasVerticalGlyphs; } + bool isTextOrientationFallback() const { return m_isTextOrientationFallback; } + const FontMetrics& fontMetrics() const { return m_fontMetrics; } float maxCharWidth() const { return m_maxCharWidth; } float avgCharWidth() const { return m_avgCharWidth; } @@ -137,8 +139,6 @@ public: virtual bool isLoading() const { return m_isLoading; } virtual bool isSegmented() const; - bool isBrokenIdeographFont() const { return m_isBrokenIdeographFont; } - const GlyphData& missingGlyphData() const { return m_missingGlyphData; } #ifndef NDEBUG @@ -152,7 +152,7 @@ public: #endif #if PLATFORM(MAC) || USE(CORE_TEXT) - CFDictionaryRef getCFStringAttributes(TypesettingFeatures) const; + CFDictionaryRef getCFStringAttributes(TypesettingFeatures, FontOrientation) const; #endif #if USE(ATSUI) @@ -183,8 +183,6 @@ public: wxFont* getWxFont() const { return m_platformData.font(); } #endif - FontOrientation orientation() const { return m_orientation; } - private: void platformInit(); void platformGlyphInit(); @@ -209,9 +207,6 @@ private: float m_maxCharWidth; float m_avgCharWidth; - FontOrientation m_orientation; // This is our supported orientation according to the tables in the font. FontPlatformData will just always have the desired orientation. - // This value represents what we actually support. - FontPlatformData m_platformData; mutable OwnPtr<GlyphMetricsMap<FloatRect> > m_glyphToBoundsMap; @@ -225,8 +220,11 @@ private: bool m_isCustomFont; // Whether or not we are custom font loaded via @font-face bool m_isLoading; // Whether or not this custom font is still in the act of loading. - bool m_isBrokenIdeographFont; - + + bool m_isTextOrientationFallback; + bool m_isBrokenIdeographFallback; + bool m_hasVerticalGlyphs; + Glyph m_spaceGlyph; float m_spaceWidth; @@ -242,6 +240,8 @@ private: OwnPtr<SimpleFontData> smallCaps; OwnPtr<SimpleFontData> emphasisMark; OwnPtr<SimpleFontData> brokenIdeograph; + OwnPtr<SimpleFontData> verticalRightOrientation; + OwnPtr<SimpleFontData> uprightOrientation; private: DerivedFontData(bool custom) diff --git a/Source/WebCore/platform/graphics/TextRun.h b/Source/WebCore/platform/graphics/TextRun.h index 4e0980b..ec763b9 100644 --- a/Source/WebCore/platform/graphics/TextRun.h +++ b/Source/WebCore/platform/graphics/TextRun.h @@ -33,17 +33,21 @@ class RenderSVGResource; class TextRun { public: - enum TrailingExpansionBehavior { - AllowTrailingExpansion, - ForbidTrailingExpansion + enum ExpansionBehaviorFlags { + ForbidTrailingExpansion = 0 << 0, + AllowTrailingExpansion = 1 << 0, + ForbidLeadingExpansion = 0 << 1, + AllowLeadingExpansion = 1 << 1, }; - TextRun(const UChar* c, int len, bool allowTabs = false, float xpos = 0, float expansion = 0, TrailingExpansionBehavior trailingExpansionBehavior = AllowTrailingExpansion, bool rtl = false, bool directionalOverride = false) + typedef unsigned ExpansionBehavior; + + TextRun(const UChar* c, int len, bool allowTabs = false, float xpos = 0, float expansion = 0, ExpansionBehavior expansionBehavior = AllowTrailingExpansion | ForbidLeadingExpansion, bool rtl = false, bool directionalOverride = false) : m_characters(c) , m_len(len) , m_xpos(xpos) , m_expansion(expansion) - , m_trailingExpansionBehavior(trailingExpansionBehavior) + , m_expansionBehavior(expansionBehavior) #if ENABLE(SVG) , m_horizontalGlyphStretch(1) #endif @@ -58,12 +62,12 @@ public: { } - TextRun(const String& s, bool allowTabs = false, float xpos = 0, float expansion = 0, TrailingExpansionBehavior trailingExpansionBehavior = AllowTrailingExpansion, bool rtl = false, bool directionalOverride = false) + TextRun(const String& s, bool allowTabs = false, float xpos = 0, float expansion = 0, ExpansionBehavior expansionBehavior = AllowTrailingExpansion | ForbidLeadingExpansion, bool rtl = false, bool directionalOverride = false) : m_characters(s.characters()) , m_len(s.length()) , m_xpos(xpos) , m_expansion(expansion) - , m_trailingExpansionBehavior(trailingExpansionBehavior) + , m_expansionBehavior(expansionBehavior) #if ENABLE(SVG) , m_horizontalGlyphStretch(1) #endif @@ -94,7 +98,8 @@ public: bool allowTabs() const { return m_allowTabs; } float xPos() const { return m_xpos; } float expansion() const { return m_expansion; } - bool allowsTrailingExpansion() const { return m_trailingExpansionBehavior == AllowTrailingExpansion; } + bool allowsLeadingExpansion() const { return m_expansionBehavior & AllowLeadingExpansion; } + bool allowsTrailingExpansion() const { return m_expansionBehavior & AllowTrailingExpansion; } bool rtl() const { return m_rtl; } bool ltr() const { return !m_rtl; } bool directionalOverride() const { return m_directionalOverride; } @@ -121,7 +126,7 @@ private: // the text line is not the same as left start of the containing block. float m_xpos; float m_expansion; - TrailingExpansionBehavior m_trailingExpansionBehavior; + ExpansionBehavior m_expansionBehavior; #if ENABLE(SVG) float m_horizontalGlyphStretch; #endif diff --git a/Source/WebCore/platform/graphics/Tile.h b/Source/WebCore/platform/graphics/Tile.h index c623ec9..02076d2 100644 --- a/Source/WebCore/platform/graphics/Tile.h +++ b/Source/WebCore/platform/graphics/Tile.h @@ -49,7 +49,7 @@ public: bool isDirty() const; void invalidate(const IntRect&); - void updateBackBuffer(); + Vector<IntRect> updateBackBuffer(); void swapBackBufferToFront(); bool isReadyToPaint() const; void paint(GraphicsContext*, const IntRect&); diff --git a/Source/WebCore/platform/graphics/TiledBackingStore.cpp b/Source/WebCore/platform/graphics/TiledBackingStore.cpp index 4d69334..ac7e9c6 100644 --- a/Source/WebCore/platform/graphics/TiledBackingStore.cpp +++ b/Source/WebCore/platform/graphics/TiledBackingStore.cpp @@ -102,8 +102,6 @@ void TiledBackingStore::updateTileBuffers() if (!it->second->isDirty()) continue; dirtyTiles.append(it->second); - // FIXME: should not request system repaint for the full tile. - paintedArea.append(mapToContents(it->second->rect())); } if (dirtyTiles.isEmpty()) { @@ -115,11 +113,11 @@ void TiledBackingStore::updateTileBuffers() // one by one and then swapped to front in one go. This would minimize the time spent // blocking on tile updates. unsigned size = dirtyTiles.size(); - for (unsigned n = 0; n < size; ++n) - dirtyTiles[n]->updateBackBuffer(); - - for (unsigned n = 0; n < size; ++n) + for (unsigned n = 0; n < size; ++n) { + Vector<IntRect> paintedRects = dirtyTiles[n]->updateBackBuffer(); + paintedArea.append(paintedRects); dirtyTiles[n]->swapBackBufferToFront(); + } m_client->tiledBackingStorePaintEnd(paintedArea); } diff --git a/Source/WebCore/platform/graphics/WOFFFileFormat.cpp b/Source/WebCore/platform/graphics/WOFFFileFormat.cpp index b1400ba..80a6dcb 100644 --- a/Source/WebCore/platform/graphics/WOFFFileFormat.cpp +++ b/Source/WebCore/platform/graphics/WOFFFileFormat.cpp @@ -248,7 +248,7 @@ bool convertWOFFToSfnt(SharedBuffer* woff, Vector<char>& sfnt) return sfnt.size() == totalSfntSize; } + +} // namespace WebCore #endif // !ENABLE(OPENTYPE_SANITIZER) - -} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/WidthIterator.cpp b/Source/WebCore/platform/graphics/WidthIterator.cpp index 27b0627..750a4ac 100644 --- a/Source/WebCore/platform/graphics/WidthIterator.cpp +++ b/Source/WebCore/platform/graphics/WidthIterator.cpp @@ -47,7 +47,7 @@ WidthIterator::WidthIterator(const Font* font, const TextRun& run, HashSet<const , m_end(run.length()) , m_currentCharacter(0) , m_runWidthSoFar(0) - , m_isAfterExpansion(true) + , m_isAfterExpansion(!run.allowsLeadingExpansion()) , m_fallbackFonts(fallbackFonts) , m_accountForGlyphBounds(accountForGlyphBounds) , m_maxGlyphBoundingBoxY(numeric_limits<float>::min()) @@ -62,7 +62,7 @@ WidthIterator::WidthIterator(const Font* font, const TextRun& run, HashSet<const if (!m_expansion) m_expansionPerOpportunity = 0; else { - bool isAfterExpansion = true; + bool isAfterExpansion = m_isAfterExpansion; unsigned expansionOpportunityCount = Font::expansionOpportunityCount(m_run.characters(), m_end, m_run.ltr() ? LTR : RTL, isAfterExpansion); if (isAfterExpansion && !m_run.allowsTrailingExpansion()) expansionOpportunityCount--; @@ -164,18 +164,24 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer) bool treatAsSpace = Font::treatAsSpace(c); if (treatAsSpace || (expandAroundIdeographs && Font::isCJKIdeographOrSymbol(c))) { // Distribute the run's total expansion evenly over all expansion opportunities in the run. - if (m_expansion && (m_run.allowsTrailingExpansion() || (m_run.ltr() && currentCharacter + clusterLength < static_cast<size_t>(m_run.length())) - || (m_run.rtl() && currentCharacter))) { + if (m_expansion) { if (!treatAsSpace && !m_isAfterExpansion) { // Take the expansion opportunity before this ideograph. m_expansion -= m_expansionPerOpportunity; m_runWidthSoFar += m_expansionPerOpportunity; - if (glyphBuffer) - glyphBuffer->expandLastAdvance(m_expansionPerOpportunity); + if (glyphBuffer) { + if (glyphBuffer->isEmpty()) + glyphBuffer->add(fontData->spaceGlyph(), fontData, m_expansionPerOpportunity); + else + glyphBuffer->expandLastAdvance(m_expansionPerOpportunity); + } + } + if (m_run.allowsTrailingExpansion() || (m_run.ltr() && currentCharacter + clusterLength < static_cast<size_t>(m_run.length())) + || (m_run.rtl() && currentCharacter)) { + m_expansion -= m_expansionPerOpportunity; + width += m_expansionPerOpportunity; + m_isAfterExpansion = true; } - m_expansion -= m_expansionPerOpportunity; - width += m_expansionPerOpportunity; - m_isAfterExpansion = true; } else m_isAfterExpansion = false; diff --git a/Source/WebCore/platform/graphics/android/FontCustomPlatformData.cpp b/Source/WebCore/platform/graphics/android/FontCustomPlatformData.cpp index 7190f32..72fac68 100644 --- a/Source/WebCore/platform/graphics/android/FontCustomPlatformData.cpp +++ b/Source/WebCore/platform/graphics/android/FontCustomPlatformData.cpp @@ -45,8 +45,7 @@ FontCustomPlatformData::~FontCustomPlatformData() // the unref is enough to release the font data... } -FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, - FontOrientation, FontWidthVariant, FontRenderingMode) +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, TextOrientation, FontWidthVariant, FontRenderingMode) { // turn bold/italic into fakeBold/fakeItalic if (m_typeface != NULL) { diff --git a/Source/WebCore/platform/graphics/android/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/android/FontCustomPlatformData.h index f74abc5..47e5e71 100644 --- a/Source/WebCore/platform/graphics/android/FontCustomPlatformData.h +++ b/Source/WebCore/platform/graphics/android/FontCustomPlatformData.h @@ -29,6 +29,7 @@ #include "FontOrientation.h" #include "FontRenderingMode.h" #include "FontWidthVariant.h" +#include "TextOrientation.h" #include <wtf/Forward.h> #include <wtf/Noncopyable.h> @@ -47,7 +48,7 @@ public: SkTypeface* typeface() const { return m_typeface; } - FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontWidthVariant, FontRenderingMode); + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation, TextOrientation, FontWidthVariant, FontRenderingMode); static bool supportsFormat(const String&); private: diff --git a/Source/WebCore/platform/graphics/android/FontPlatformData.h b/Source/WebCore/platform/graphics/android/FontPlatformData.h index 498db47..3313aca 100644 --- a/Source/WebCore/platform/graphics/android/FontPlatformData.h +++ b/Source/WebCore/platform/graphics/android/FontPlatformData.h @@ -65,6 +65,7 @@ public: } FontOrientation orientation() const { return Horizontal; } // FIXME: Implement. + void setOrientation(FontOrientation) { } // FIXME: Implement. FontPlatformData& operator=(const FontPlatformData&); bool operator==(const FontPlatformData& a) const; diff --git a/Source/WebCore/platform/graphics/android/PathAndroid.cpp b/Source/WebCore/platform/graphics/android/PathAndroid.cpp index ad345bb..436da59 100644 --- a/Source/WebCore/platform/graphics/android/PathAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/PathAndroid.cpp @@ -285,7 +285,7 @@ void Path::transform(const AffineTransform& xform) /////////////////////////////////////////////////////////////////////////////// -FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) +FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) const { GraphicsContext* scratch = scratchContext(); scratch->save(); diff --git a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp new file mode 100644 index 0000000..eb96532 --- /dev/null +++ b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp @@ -0,0 +1,731 @@ +/* + * 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" + +#if ENABLE(VIDEO) && USE(AVFOUNDATION) + +#include "MediaPlayerPrivateAVFoundation.h" + +#include "ApplicationCacheHost.h" +#include "DocumentLoader.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "GraphicsLayer.h" +#include "KURL.h" +#include "Logging.h" +#include "SoftLinking.h" +#include "TimeRanges.h" +#include <CoreMedia/CoreMedia.h> +#include <wtf/UnusedParam.h> + +using namespace std; + +namespace WebCore { + +static const float invalidTime = -1.0f; + +MediaPlayerPrivateAVFoundation::MediaPlayerPrivateAVFoundation(MediaPlayer* player) + : m_player(player) + , m_queuedNotifications() + , m_queueMutex() + , m_mainThreadCallPending(false) + , m_networkState(MediaPlayer::Empty) + , m_readyState(MediaPlayer::HaveNothing) + , m_preload(MediaPlayer::Auto) + , m_scaleFactor(1, 1) + , m_cachedMaxTimeLoaded(0) + , m_cachedMaxTimeSeekable(0) + , m_cachedDuration(invalidTime) + , m_reportedDuration(invalidTime) + , m_seekTo(invalidTime) + , m_requestedRate(1) + , m_delayCallbacks(false) + , m_havePreparedToPlay(false) + , m_assetIsPlayable(false) + , m_visible(false) + , m_videoFrameHasDrawn(false) + , m_loadingMetadata(false) + , m_delayingLoad(false) + , m_isAllowedToRender(false) + , m_cachedHasAudio(false) + , m_cachedHasVideo(false) + , m_cachedHasCaptions(false) + , m_ignoreLoadStateChanges(false) +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::MediaPlayerPrivateAVFoundation(%p)", this); +} + +MediaPlayerPrivateAVFoundation::~MediaPlayerPrivateAVFoundation() +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::~MediaPlayerPrivateAVFoundation(%p)", this); + cancelCallOnMainThread(mainThreadCallback, this); +} + +MediaPlayerPrivateAVFoundation::MediaRenderingMode MediaPlayerPrivateAVFoundation::currentRenderingMode() const +{ +#if USE(ACCELERATED_COMPOSITING) + if (platformLayer()) + return MediaRenderingToLayer; +#endif + + if (hasContextRenderer()) + return MediaRenderingToContext; + + return MediaRenderingNone; +} + +MediaPlayerPrivateAVFoundation::MediaRenderingMode MediaPlayerPrivateAVFoundation::preferredRenderingMode() const +{ + if (!m_player->visible() || !m_player->frameView() || assetStatus() == MediaPlayerAVAssetStatusUnknown) + return MediaRenderingNone; + +#if USE(ACCELERATED_COMPOSITING) + if (supportsAcceleratedRendering() && m_player->mediaPlayerClient()->mediaPlayerRenderingCanBeAccelerated(m_player)) + return MediaRenderingToLayer; +#endif + + return MediaRenderingToContext; +} + +void MediaPlayerPrivateAVFoundation::setUpVideoRendering() +{ + if (!isReadyForVideoSetup()) + return; + + MediaRenderingMode currentMode = currentRenderingMode(); + MediaRenderingMode preferredMode = preferredRenderingMode(); + if (currentMode == preferredMode && currentMode != MediaRenderingNone) + return; + + LOG(Media, "MediaPlayerPrivateAVFoundation::setUpVideoRendering(%p) - current mode = %d, preferred mode = %d", + this, static_cast<int>(currentMode), static_cast<int>(preferredMode)); + + if (currentMode != MediaRenderingNone) + tearDownVideoRendering(); + + switch (preferredMode) { + case MediaRenderingNone: + case MediaRenderingToContext: + createContextVideoRenderer(); + break; + +#if USE(ACCELERATED_COMPOSITING) + case MediaRenderingToLayer: + createVideoLayer(); + break; +#endif + } + +#if USE(ACCELERATED_COMPOSITING) + // If using a movie layer, inform the client so the compositing tree is updated. + if (currentMode == MediaRenderingToLayer || preferredMode == MediaRenderingToLayer) { + LOG(Media, "MediaPlayerPrivateAVFoundation::setUpVideoRendering(%p) - calling mediaPlayerRenderingModeChanged()", this); + m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player); + } +#endif +} + +void MediaPlayerPrivateAVFoundation::tearDownVideoRendering() +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::tearDownVideoRendering(%p)", this); + + destroyContextVideoRenderer(); + +#if USE(ACCELERATED_COMPOSITING) + if (platformLayer()) + destroyVideoLayer(); +#endif +} + +bool MediaPlayerPrivateAVFoundation::hasSetUpVideoRendering() const +{ + return hasLayerRenderer() || hasContextRenderer(); +} + +void MediaPlayerPrivateAVFoundation::resumeLoad() +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::resumeLoad(%p)", this); + + ASSERT(m_delayingLoad); + m_delayingLoad = false; + + if (m_assetURL.length()) + prepareToPlay(); +} + +void MediaPlayerPrivateAVFoundation::load(const String& url) +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::load(%p)", this); + + if (m_networkState != MediaPlayer::Loading) { + m_networkState = MediaPlayer::Loading; + m_player->networkStateChanged(); + } + if (m_readyState != MediaPlayer::HaveNothing) { + m_readyState = MediaPlayer::HaveNothing; + m_player->readyStateChanged(); + } + + m_videoFrameHasDrawn = false; + m_assetURL = url; + + // Don't do any more work if the url is empty. + if (!url.length()) + return; + + if (m_preload == MediaPlayer::None) { + LOG(Media, "MediaPlayerPrivateAVFoundation::load(%p) - preload==none so returning", this); + m_delayingLoad = true; + return; + } + + prepareToPlay(); +} + +void MediaPlayerPrivateAVFoundation::playabilityKnown() +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::playabilityKnown(%p)", this); + + updateStates(); + if (m_assetIsPlayable) + return; + + // Nothing more to do if we already have all of the item's metadata. + if (assetStatus() > MediaPlayerAVAssetStatusLoading) { + LOG(Media, "MediaPlayerPrivateAVFoundation::playabilityKnown(%p) - all metadata loaded", this); + return; + } + + // At this point we are supposed to load metadata. It is OK to ask the asset to load the same + // information multiple times, because if it has already been loaded the completion handler + // will just be called synchronously. + m_loadingMetadata = true; + beginLoadingMetadata(); +} + +void MediaPlayerPrivateAVFoundation::prepareToPlay() +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::prepareToPlay(%p)", this); + + m_preload = MediaPlayer::Auto; + if (m_havePreparedToPlay) + return; + m_havePreparedToPlay = true; + + m_delayingLoad = false; +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + Frame* frame = m_player->frameView() ? m_player->frameView()->frame() : 0; + ApplicationCacheHost* cacheHost = frame ? frame->loader()->documentLoader()->applicationCacheHost() : 0; + ApplicationCacheResource* resource = 0; + if (cacheHost && cacheHost->shouldLoadResourceFromApplicationCache(ResourceRequest(m_assetURL), resource) && resource) + createAVPlayerForCacheResource(resource); + else +#endif + createAVPlayerForURL(m_assetURL); + checkPlayability(); +} + +void MediaPlayerPrivateAVFoundation::paint(GraphicsContext*, const IntRect&) +{ + // This is the base class, only need to remember that a frame has been drawn. + m_videoFrameHasDrawn = true; +} + +float MediaPlayerPrivateAVFoundation::duration() const +{ + if (!metaDataAvailable()) + return 0; + + if (m_cachedDuration == invalidTime) { + m_cachedDuration = platformDuration(); + LOG(Media, "MediaPlayerPrivateAVFMac::duration(%p) - caching %f", this, m_cachedDuration); + } + + return m_cachedDuration; +} + +void MediaPlayerPrivateAVFoundation::seek(float time) +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::seek(%p) - seeking to %f", this, time); + if (!metaDataAvailable()) + return; + + if (time > duration()) + time = duration(); + + m_seekTo = time; + + seekToTime(time); +} + +void MediaPlayerPrivateAVFoundation::setRate(float rate) +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::setRate(%p) - seting to %f", this, rate); + m_requestedRate = rate; +} + +bool MediaPlayerPrivateAVFoundation::paused() const +{ + if (!metaDataAvailable()) + return true; + + return rate() == 0; +} + +bool MediaPlayerPrivateAVFoundation::seeking() const +{ + if (!metaDataAvailable()) + return false; + + return m_seekTo != invalidTime; +} + +IntSize MediaPlayerPrivateAVFoundation::naturalSize() const +{ + if (!metaDataAvailable()) + return IntSize(); + + // In spite of the name of this method, return the natural size transformed by the + // initial movie scale because the spec says intrinsic size is: + // + // ... the dimensions of the resource in CSS pixels after taking into account the resource's + // dimensions, aspect ratio, clean aperture, resolution, and so forth, as defined for the + // format used by the resource + + return m_cachedNaturalSize; +} + +void MediaPlayerPrivateAVFoundation::setNaturalSize(IntSize size) +{ + IntSize oldSize = m_cachedNaturalSize; + m_cachedNaturalSize = size; + if (oldSize != m_cachedNaturalSize) + m_player->sizeChanged(); +} + +PassRefPtr<TimeRanges> MediaPlayerPrivateAVFoundation::buffered() const +{ + if (!m_cachedLoadedTimeRanges) + m_cachedLoadedTimeRanges = platformBufferedTimeRanges(); + + return m_cachedLoadedTimeRanges->copy(); +} + +float MediaPlayerPrivateAVFoundation::maxTimeSeekable() const +{ + if (!metaDataAvailable()) + return 0; + + if (!m_cachedMaxTimeSeekable) + m_cachedMaxTimeSeekable = platformMaxTimeSeekable(); + + LOG(Media, "MediaPlayerPrivateAVFoundation::maxTimeSeekable(%p) - returning %f", this, m_cachedMaxTimeSeekable); + return m_cachedMaxTimeSeekable; +} + +float MediaPlayerPrivateAVFoundation::maxTimeLoaded() const +{ + if (!metaDataAvailable()) + return 0; + + if (!m_cachedMaxTimeLoaded) + m_cachedMaxTimeLoaded = platformMaxTimeLoaded(); + + return m_cachedMaxTimeLoaded; +} + +unsigned MediaPlayerPrivateAVFoundation::bytesLoaded() const +{ + float dur = duration(); + if (!dur) + return 0; + unsigned loaded = totalBytes() * maxTimeLoaded() / dur; + LOG(Media, "MediaPlayerPrivateAVFoundation::bytesLoaded(%p) - returning %i", this, loaded); + return loaded; +} + +bool MediaPlayerPrivateAVFoundation::isReadyForVideoSetup() const +{ + return m_isAllowedToRender && m_readyState >= MediaPlayer::HaveMetadata && m_player->visible(); +} + +void MediaPlayerPrivateAVFoundation::prepareForRendering() +{ + if (m_isAllowedToRender) + return; + m_isAllowedToRender = true; + + setUpVideoRendering(); + + if (currentRenderingMode() == MediaRenderingToLayer || preferredRenderingMode() == MediaRenderingToLayer) + m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player); +} + +bool MediaPlayerPrivateAVFoundation::supportsFullscreen() const +{ +#if ENABLE(FULLSCREEN_API) + return true; +#else + // FIXME: WebVideoFullscreenController assumes a QTKit/QuickTime media engine + return false; +#endif +} + +void MediaPlayerPrivateAVFoundation::updateStates() +{ + MediaPlayer::NetworkState oldNetworkState = m_networkState; + MediaPlayer::ReadyState oldReadyState = m_readyState; + + LOG(Media, "MediaPlayerPrivateAVFoundation::updateStates(%p) - entering with networkState = %i, readyState = %i", + this, static_cast<int>(m_networkState), static_cast<int>(m_readyState)); + + if (m_loadingMetadata) + m_networkState = MediaPlayer::Loading; + else { + // -loadValuesAsynchronouslyForKeys:completionHandler: has invoked its handler; test status of keys and determine state. + AVAssetStatus avAssetStatus = assetStatus(); + ItemStatus itemStatus = playerItemStatus(); + + m_assetIsPlayable = (avAssetStatus == MediaPlayerAVAssetStatusPlayable); + if (m_readyState < MediaPlayer::HaveMetadata && avAssetStatus > MediaPlayerAVAssetStatusLoading) { + if (m_assetIsPlayable) { + if (itemStatus == MediaPlayerAVPlayerItemStatusUnknown) { + if (avAssetStatus == MediaPlayerAVAssetStatusFailed || m_preload > MediaPlayer::MetaData) { + // We may have a playable asset that doesn't support inspection prior to playback; go ahead + // and create the AVPlayerItem now. When the AVPlayerItem becomes ready to play, we will + // have access to its metadata. Or we may have been asked to become ready to play immediately. + m_networkState = MediaPlayer::Loading; + prepareToPlay(); + } else + m_networkState = MediaPlayer::Idle; + } + if (avAssetStatus == MediaPlayerAVAssetStatusLoaded) + m_readyState = MediaPlayer::HaveMetadata; + } else { + // FIX ME: fetch the error associated with the @"playable" key to distinguish between format + // and network errors. + m_networkState = MediaPlayer::FormatError; + } + } + + if (avAssetStatus >= MediaPlayerAVAssetStatusLoaded && itemStatus > MediaPlayerAVPlayerItemStatusUnknown) { + if (seeking()) + m_readyState = m_readyState >= MediaPlayer::HaveMetadata ? MediaPlayer::HaveMetadata : MediaPlayer::HaveNothing; + else { + float maxLoaded = maxTimeLoaded(); + switch (itemStatus) { + case MediaPlayerAVPlayerItemStatusUnknown: + break; + case MediaPlayerAVPlayerItemStatusFailed: + m_networkState = MediaPlayer::DecodeError; + break; + case MediaPlayerAVPlayerItemStatusPlaybackLikelyToKeepUp: + m_readyState = MediaPlayer::HaveEnoughData; + break; + case MediaPlayerAVPlayerItemStatusReadyToPlay: + case MediaPlayerAVPlayerItemStatusPlaybackBufferEmpty: + case MediaPlayerAVPlayerItemStatusPlaybackBufferFull: + if (maxLoaded > currentTime()) + m_readyState = MediaPlayer::HaveFutureData; + else + m_readyState = MediaPlayer::HaveCurrentData; + break; + } + + if (itemStatus >= MediaPlayerAVPlayerItemStatusReadyToPlay) + m_networkState = (maxLoaded == duration()) ? MediaPlayer::Loaded : MediaPlayer::Loading; + } + } + } + + if (isReadyForVideoSetup() && currentRenderingMode() != preferredRenderingMode()) + setUpVideoRendering(); + + if (m_networkState != oldNetworkState) + m_player->networkStateChanged(); + + if (m_readyState != oldReadyState) + m_player->readyStateChanged(); + + LOG(Media, "MediaPlayerPrivateAVFoundation::updateStates(%p) - exiting with networkState = %i, readyState = %i", + this, static_cast<int>(m_networkState), static_cast<int>(m_readyState)); +} + +void MediaPlayerPrivateAVFoundation::setSize(const IntSize&) +{ +} + +void MediaPlayerPrivateAVFoundation::setVisible(bool visible) +{ + if (m_visible == visible) + return; + + m_visible = visible; + if (visible) + setUpVideoRendering(); + else + tearDownVideoRendering(); +} + +bool MediaPlayerPrivateAVFoundation::hasAvailableVideoFrame() const +{ + if (currentRenderingMode() == MediaRenderingToLayer) + return videoLayerIsReadyToDisplay(); + + // When using the software renderer we hope someone will signal that a frame is available so we might as well + // wait until we know that a frame has been drawn. + return m_videoFrameHasDrawn; +} + +void MediaPlayerPrivateAVFoundation::acceleratedRenderingStateChanged() +{ + // Set up or change the rendering path if necessary. + setUpVideoRendering(); +} + +void MediaPlayerPrivateAVFoundation::metadataLoaded() +{ + m_loadingMetadata = false; + updateStates(); +} + +void MediaPlayerPrivateAVFoundation::loadStateChanged() +{ + if (m_ignoreLoadStateChanges) + return; + updateStates(); +} + +void MediaPlayerPrivateAVFoundation::rateChanged() +{ + updateStates(); + m_player->rateChanged(); +} + +void MediaPlayerPrivateAVFoundation::loadedTimeRangesChanged() +{ + m_cachedLoadedTimeRanges = 0; + m_cachedMaxTimeLoaded = 0; + updateStates(); + + // For some media files, reported duration is estimated and updated as media is loaded + // so report duration changed when the estimate is upated. + float dur = duration(); + if (dur != m_reportedDuration) { + if (m_reportedDuration != invalidTime) + m_player->durationChanged(); + m_reportedDuration = dur; + } +} + +void MediaPlayerPrivateAVFoundation::seekableTimeRangesChanged() +{ + m_cachedMaxTimeSeekable = 0; +} + +void MediaPlayerPrivateAVFoundation::timeChanged(double time) +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::timeChanged(%p) - time = %f", this, time); + + if (m_seekTo == invalidTime) + return; + + // AVFoundation may call our observer more than once during a seek, and we can't currently tell + // if we will be able to seek to an exact time, so assume that we are done seeking if we are + // "close enough" to the seek time. + const double smallSeekDelta = 1.0 / 100; + + float currentRate = rate(); + if ((currentRate > 0 && time >= m_seekTo) || (currentRate < 0 && time <= m_seekTo) || (abs(m_seekTo - time) <= smallSeekDelta)) { + m_seekTo = invalidTime; + updateStates(); + m_player->timeChanged(); + } +} + +void MediaPlayerPrivateAVFoundation::didEnd() +{ + // Hang onto the current time and use it as duration from now on since we are definitely at + // the end of the movie. Do this because the initial duration is sometimes an estimate. + float now = currentTime(); + if (now > 0) + m_cachedDuration = now; + + updateStates(); + m_player->timeChanged(); +} + +void MediaPlayerPrivateAVFoundation::repaint() +{ + m_videoFrameHasDrawn = true; + m_player->repaint(); +} + +MediaPlayer::MovieLoadType MediaPlayerPrivateAVFoundation::movieLoadType() const +{ + if (!metaDataAvailable() || assetStatus() == MediaPlayerAVAssetStatusUnknown) + return MediaPlayer::Unknown; + + if (isinf(duration())) + return MediaPlayer::LiveStream; + + return MediaPlayer::Download; +} + +void MediaPlayerPrivateAVFoundation::setPreload(MediaPlayer::Preload preload) +{ + m_preload = preload; + if (m_delayingLoad && m_preload != MediaPlayer::None) + resumeLoad(); +} + +void MediaPlayerPrivateAVFoundation::setDelayCallbacks(bool delay) +{ + MutexLocker lock(m_queueMutex); + if (delay) + ++m_delayCallbacks; + else { + ASSERT(m_delayCallbacks); + --m_delayCallbacks; + } +} + +void MediaPlayerPrivateAVFoundation::mainThreadCallback(void* context) +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::mainThreadCallback(%p)", context); + MediaPlayerPrivateAVFoundation* player = static_cast<MediaPlayerPrivateAVFoundation*>(context); + player->clearMainThreadPendingFlag(); + player->dispatchNotification(); +} + +void MediaPlayerPrivateAVFoundation::clearMainThreadPendingFlag() +{ + MutexLocker lock(m_queueMutex); + m_mainThreadCallPending = false; +} + +void MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(Notification::Type type, double time) +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(%p) - notification %d", this, static_cast<int>(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)); + + bool delayDispatch = m_delayCallbacks || !isMainThread(); + if (delayDispatch && !m_mainThreadCallPending) { + m_mainThreadCallPending = true; + callOnMainThread(mainThreadCallback, this); + } + + m_queueMutex.unlock(); + + if (delayDispatch) { + LOG(Media, "MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(%p) - early return", this); + return; + } + + dispatchNotification(); +} + +void MediaPlayerPrivateAVFoundation::dispatchNotification() +{ + ASSERT(isMainThread()); + + Notification notification = Notification(); + { + MutexLocker lock(m_queueMutex); + + if (m_queuedNotifications.isEmpty()) + return; + + if (!m_delayCallbacks) { + // Only dispatch one notification callback per invocation because they can cause recursion. + notification = m_queuedNotifications.first(); + m_queuedNotifications.remove(0); + } + + if (!m_queuedNotifications.isEmpty() && !m_mainThreadCallPending) + callOnMainThread(mainThreadCallback, this); + + if (!notification.isValid()) + return; + } + + LOG(Media, "MediaPlayerPrivateAVFoundation::dispatchNotification(%p) - dispatching %d", this, static_cast<int>(notification.type())); + + switch (notification.type()) { + case Notification::ItemDidPlayToEndTime: + didEnd(); + break; + case Notification::ItemTracksChanged: + tracksChanged(); + break; + case Notification::ItemStatusChanged: + loadStateChanged(); + break; + case Notification::ItemSeekableTimeRangesChanged: + seekableTimeRangesChanged(); + loadStateChanged(); + break; + case Notification::ItemLoadedTimeRangesChanged: + loadedTimeRangesChanged(); + loadStateChanged(); + break; + case Notification::ItemPresentationSizeChanged: + sizeChanged(); + break; + case Notification::ItemIsPlaybackLikelyToKeepUpChanged: + loadStateChanged(); + break; + case Notification::ItemIsPlaybackBufferEmptyChanged: + loadStateChanged(); + break; + case Notification::ItemIsPlaybackBufferFullChanged: + loadStateChanged(); + break; + case Notification::PlayerRateChanged: + rateChanged(); + break; + case Notification::PlayerTimeChanged: + timeChanged(notification.time()); + break; + case Notification::AssetMetadataLoaded: + metadataLoaded(); + break; + case Notification::AssetPlayabilityKnown: + playabilityKnown(); + break; + case Notification::None: + ASSERT_NOT_REACHED(); + break; + } +} + +} // namespace WebCore + +#endif diff --git a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h new file mode 100644 index 0000000..a768ab4 --- /dev/null +++ b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h @@ -0,0 +1,262 @@ +/* + * 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. + */ + +#ifndef MediaPlayerPrivateAVFoundation_h +#define MediaPlayerPrivateAVFoundation_h + +#if ENABLE(VIDEO) && USE(AVFOUNDATION) + +#include "FloatSize.h" +#include "MediaPlayerPrivate.h" +#include "Timer.h" +#include <wtf/RetainPtr.h> + +namespace WebCore { + +class ApplicationCacheResource; + +class MediaPlayerPrivateAVFoundation : public MediaPlayerPrivateInterface { +public: + + virtual void repaint(); + virtual void metadataLoaded(); + virtual void loadStateChanged(); + virtual void playabilityKnown(); + virtual void rateChanged(); + virtual void loadedTimeRangesChanged(); + virtual void seekableTimeRangesChanged(); + virtual void timeChanged(double); + virtual void didEnd(); + + class Notification { + public: + enum Type { + None, + ItemDidPlayToEndTime, + ItemTracksChanged, + ItemStatusChanged, + ItemSeekableTimeRangesChanged, + ItemLoadedTimeRangesChanged, + ItemPresentationSizeChanged, + ItemIsPlaybackLikelyToKeepUpChanged, + ItemIsPlaybackBufferEmptyChanged, + ItemIsPlaybackBufferFullChanged, + AssetMetadataLoaded, + AssetPlayabilityKnown, + PlayerRateChanged, + PlayerTimeChanged + }; + + Notification() + : m_type(None) + , m_time(0) + { + } + + Notification(Type type, double time) + : m_type(type) + , m_time(time) + { + } + + Type type() { return m_type; } + bool isValid() { return m_type != None; } + double time() { return m_time; } + + private: + Type m_type; + double m_time; + }; + + void scheduleMainThreadNotification(Notification::Type, double time = 0); + void dispatchNotification(); + void clearMainThreadPendingFlag(); + +protected: + MediaPlayerPrivateAVFoundation(MediaPlayer*); + virtual ~MediaPlayerPrivateAVFoundation(); + + // MediaPlayerPrivatePrivateInterface overrides. + virtual void load(const String& url); + virtual void cancelLoad() = 0; + + virtual void prepareToPlay(); + virtual PlatformMedia platformMedia() const = 0; + + virtual void play() = 0; + virtual void pause() = 0; + + virtual IntSize naturalSize() const; + virtual bool hasVideo() const { return m_cachedHasVideo; } + virtual bool hasAudio() const { return m_cachedHasAudio; } + virtual void setVisible(bool); + virtual float duration() const; + virtual float currentTime() const = 0; + virtual void seek(float); + virtual bool seeking() const; + virtual void setRate(float); + virtual bool paused() const; + virtual void setVolume(float) = 0; + virtual bool hasClosedCaptions() const { return m_cachedHasCaptions; } + virtual void setClosedCaptionsVisible(bool) = 0; + virtual MediaPlayer::NetworkState networkState() const { return m_networkState; } + virtual MediaPlayer::ReadyState readyState() const { return m_readyState; } + virtual float maxTimeSeekable() const; + virtual PassRefPtr<TimeRanges> buffered() const; + virtual unsigned bytesLoaded() const; + virtual void setSize(const IntSize&); + virtual void paint(GraphicsContext*, const IntRect&); + virtual void paintCurrentFrameInContext(GraphicsContext*, const IntRect&) = 0; + virtual void setPreload(MediaPlayer::Preload); + virtual bool hasAvailableVideoFrame() const; +#if USE(ACCELERATED_COMPOSITING) + virtual PlatformLayer* platformLayer() const { return 0; } + virtual bool supportsAcceleratedRendering() const = 0; + virtual void acceleratedRenderingStateChanged(); +#endif + virtual bool hasSingleSecurityOrigin() const { return true; } + virtual MediaPlayer::MovieLoadType movieLoadType() const; + virtual void prepareForRendering(); + virtual float mediaTimeForTimeValue(float) const = 0; + + virtual bool supportsFullscreen() const; + + // Required interfaces for concrete derived classes. + virtual void createAVPlayerForURL(const String& url) = 0; +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + virtual void createAVPlayerForCacheResource(ApplicationCacheResource*) = 0; +#endif + + enum ItemStatus { + MediaPlayerAVPlayerItemStatusUnknown, + MediaPlayerAVPlayerItemStatusFailed, + MediaPlayerAVPlayerItemStatusReadyToPlay, + MediaPlayerAVPlayerItemStatusPlaybackBufferEmpty, + MediaPlayerAVPlayerItemStatusPlaybackBufferFull, + MediaPlayerAVPlayerItemStatusPlaybackLikelyToKeepUp, + }; + virtual ItemStatus playerItemStatus() const = 0; + + enum AVAssetStatus { + MediaPlayerAVAssetStatusUnknown, + MediaPlayerAVAssetStatusLoading, + MediaPlayerAVAssetStatusFailed, + MediaPlayerAVAssetStatusCancelled, + MediaPlayerAVAssetStatusLoaded, + MediaPlayerAVAssetStatusPlayable, + }; + virtual AVAssetStatus assetStatus() const = 0; + + virtual void checkPlayability() = 0; + virtual float rate() const = 0; + virtual void seekToTime(float time) = 0; + virtual unsigned totalBytes() const = 0; + virtual PassRefPtr<TimeRanges> platformBufferedTimeRanges() const = 0; + virtual float platformMaxTimeSeekable() const = 0; + virtual float platformMaxTimeLoaded() const = 0; + virtual float platformDuration() const = 0; + + virtual void beginLoadingMetadata() = 0; + virtual void tracksChanged() = 0; + virtual void sizeChanged() = 0; + + virtual void createContextVideoRenderer() = 0; + virtual void destroyContextVideoRenderer() = 0; + + virtual void createVideoLayer() = 0; + virtual void destroyVideoLayer() = 0; + virtual bool videoLayerIsReadyToDisplay() const = 0; + + virtual bool hasContextRenderer() const = 0; + virtual bool hasLayerRenderer() const = 0; + +protected: + void resumeLoad(); + void updateStates(); + + void setHasVideo(bool b) { m_cachedHasVideo = b; }; + void setHasAudio(bool b) { m_cachedHasAudio = b; } + void setHasClosedCaptions(bool b) { m_cachedHasCaptions = b; } + void setDelayCallbacks(bool); + void setIgnoreLoadStateChanges(bool delay) { m_ignoreLoadStateChanges = delay; } + void setNaturalSize(IntSize); + + enum MediaRenderingMode { MediaRenderingNone, MediaRenderingToContext, MediaRenderingToLayer }; + MediaRenderingMode currentRenderingMode() const; + MediaRenderingMode preferredRenderingMode() const; + + bool metaDataAvailable() const { return m_readyState >= MediaPlayer::HaveMetadata; } + float requestedRate() const { return m_requestedRate; } + float maxTimeLoaded() const; + bool isReadyForVideoSetup() const; + virtual void setUpVideoRendering(); + virtual void tearDownVideoRendering(); + bool hasSetUpVideoRendering() const; + + static void mainThreadCallback(void*); + +private: + + MediaPlayer* m_player; + + Vector<Notification> m_queuedNotifications; + Mutex m_queueMutex; + bool m_mainThreadCallPending; + + mutable RefPtr<TimeRanges> m_cachedLoadedTimeRanges; + + MediaPlayer::NetworkState m_networkState; + MediaPlayer::ReadyState m_readyState; + + String m_assetURL; + MediaPlayer::Preload m_preload; + FloatSize m_scaleFactor; + + IntSize m_cachedNaturalSize; + mutable float m_cachedMaxTimeLoaded; + mutable float m_cachedMaxTimeSeekable; + mutable float m_cachedDuration; + float m_reportedDuration; + + float m_seekTo; + float m_requestedRate; + int m_delayCallbacks; + bool m_havePreparedToPlay; + bool m_assetIsPlayable; + bool m_visible; + bool m_videoFrameHasDrawn; + bool m_loadingMetadata; + bool m_delayingLoad; + bool m_isAllowedToRender; + bool m_cachedHasAudio; + bool m_cachedHasVideo; + bool m_cachedHasCaptions; + bool m_ignoreLoadStateChanges; +}; + +} + +#endif +#endif diff --git a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.h b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.h new file mode 100644 index 0000000..cc00c15 --- /dev/null +++ b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.h @@ -0,0 +1,131 @@ +/* + * 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. + */ + +#ifndef MediaPlayerPrivateAVFoundationObjC_h +#define MediaPlayerPrivateAVFoundationObjC_h + +#if ENABLE(VIDEO) && USE(AVFOUNDATION) + +#include "MediaPlayerPrivateAVFoundation.h" + +#ifdef __OBJC__ +@class AVAsset; +@class AVPlayer; +@class AVPlayerItem; +@class AVPlayerLayer; +@class AVAssetImageGenerator; +@class WebCoreAVFMovieObserver; +#else +class AVAsset; +class AVPlayer; +class AVPlayerItem; +class AVPlayerLayer; +class AVAssetImageGenerator; +class WebCoreAVFMovieObserver; +typedef struct objc_object *id; +#endif + +namespace WebCore { + +class ApplicationCacheResource; + +class MediaPlayerPrivateAVFoundationObjC : public MediaPlayerPrivateAVFoundation { +public: + + static void registerMediaEngine(MediaEngineRegistrar); + + void setAsset(id); + virtual void tracksChanged(); + +private: + MediaPlayerPrivateAVFoundationObjC(MediaPlayer*); + ~MediaPlayerPrivateAVFoundationObjC(); + + // engine support + static MediaPlayerPrivateInterface* create(MediaPlayer* player); + static void getSupportedTypes(HashSet<String>& types); + static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs); + static bool isAvailable(); + + virtual void cancelLoad(); + + virtual PlatformMedia platformMedia() const; + + virtual void play(); + virtual void pause(); + virtual float currentTime() const; + virtual void setVolume(float); + virtual void setClosedCaptionsVisible(bool); + virtual void paint(GraphicsContext*, const IntRect&); + virtual void paintCurrentFrameInContext(GraphicsContext*, const IntRect&); + virtual PlatformLayer* platformLayer() const; + virtual bool supportsAcceleratedRendering() const { return true; } + virtual float mediaTimeForTimeValue(float) const; + + virtual void createAVPlayer(); + virtual void createAVPlayerForURL(const String& url); +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + virtual void createAVPlayerForCacheResource(ApplicationCacheResource*); +#endif + virtual MediaPlayerPrivateAVFoundation::ItemStatus playerItemStatus() const; + virtual MediaPlayerPrivateAVFoundation::AVAssetStatus assetStatus() const; + + virtual void checkPlayability(); + virtual float rate() const; + virtual void seekToTime(float time); + virtual unsigned totalBytes() const; + virtual PassRefPtr<TimeRanges> platformBufferedTimeRanges() const; + virtual float platformMaxTimeSeekable() const; + virtual float platformDuration() const; + virtual float platformMaxTimeLoaded() const; + virtual void beginLoadingMetadata(); + virtual void sizeChanged(); + + virtual void createContextVideoRenderer(); + virtual void destroyContextVideoRenderer(); + + virtual void createVideoLayer(); + virtual void destroyVideoLayer(); + virtual bool videoLayerIsReadyToDisplay() const; + + virtual bool hasContextRenderer() const; + virtual bool hasLayerRenderer() const; + + RetainPtr<CGImageRef> createImageForTimeInRect(float, const IntRect&); + + MediaPlayer* m_player; + RetainPtr<AVAsset> m_avAsset; + RetainPtr<AVPlayer> m_avPlayer; + RetainPtr<AVPlayerItem> m_avPlayerItem; + RetainPtr<AVPlayerLayer> m_videoLayer; + RetainPtr<WebCoreAVFMovieObserver> m_objcObserver; + RetainPtr<AVAssetImageGenerator> m_imageGenerator; + id m_timeObserver; +}; + +} + +#endif +#endif diff --git a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm new file mode 100644 index 0000000..55eb433 --- /dev/null +++ b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm @@ -0,0 +1,811 @@ +/* + * 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. + */ + +#import "config.h" + +#if ENABLE(VIDEO) && USE(AVFOUNDATION) + +#import "MediaPlayerPrivateAVFoundationObjC.h" + +#import "ApplicationCacheResource.h" +#import "BlockExceptions.h" +#import "FloatConversion.h" +#import "FrameView.h" +#import "FloatConversion.h" +#import "GraphicsContext.h" +#import "KURL.h" +#import "Logging.h" +#import "SoftLinking.h" +#import "TimeRanges.h" +#import "WebCoreSystemInterface.h" +#import <objc/objc-runtime.h> +#import <wtf/UnusedParam.h> + +#import <CoreMedia/CoreMedia.h> +#import <AVFoundation/AVFoundation.h> + +SOFT_LINK_FRAMEWORK(AVFoundation) +SOFT_LINK_FRAMEWORK(CoreMedia) + +SOFT_LINK(CoreMedia, CMTimeCompare, int32_t, (CMTime time1, CMTime time2), (time1, time2)) +SOFT_LINK(CoreMedia, CMTimeMakeWithSeconds, CMTime, (Float64 seconds, int32_t preferredTimeScale), (seconds, preferredTimeScale)) +SOFT_LINK(CoreMedia, CMTimeGetSeconds, Float64, (CMTime time), (time)) +SOFT_LINK(CoreMedia, CMTimeRangeGetEnd, CMTime, (CMTimeRange range), (range)) + +SOFT_LINK_CLASS(AVFoundation, AVPlayer) +SOFT_LINK_CLASS(AVFoundation, AVPlayerItem) +SOFT_LINK_CLASS(AVFoundation, AVPlayerLayer) +SOFT_LINK_CLASS(AVFoundation, AVURLAsset) +SOFT_LINK_CLASS(AVFoundation, AVAssetImageGenerator) + +SOFT_LINK_POINTER(AVFoundation, AVMediaCharacteristicVisual, NSString *) +SOFT_LINK_POINTER(AVFoundation, AVMediaCharacteristicAudible, NSString *) +SOFT_LINK_POINTER(AVFoundation, AVMediaTypeClosedCaption, NSString *) +SOFT_LINK_POINTER(AVFoundation, AVPlayerItemDidPlayToEndTimeNotification, NSString *) +SOFT_LINK_POINTER(AVFoundation, AVAssetImageGeneratorApertureModeCleanAperture, NSString *) + +SOFT_LINK_CONSTANT(CoreMedia, kCMTimeZero, CMTime) + +#define AVPlayer getAVPlayerClass() +#define AVPlayerItem getAVPlayerItemClass() +#define AVPlayerLayer getAVPlayerLayerClass() +#define AVURLAsset getAVURLAssetClass() +#define AVAssetImageGenerator getAVAssetImageGeneratorClass() + +#define AVMediaCharacteristicVisual getAVMediaCharacteristicVisual() +#define AVMediaCharacteristicAudible getAVMediaCharacteristicAudible() +#define AVMediaTypeClosedCaption getAVMediaTypeClosedCaption() +#define AVPlayerItemDidPlayToEndTimeNotification getAVPlayerItemDidPlayToEndTimeNotification() +#define AVAssetImageGeneratorApertureModeCleanAperture getAVAssetImageGeneratorApertureModeCleanAperture() + +#define kCMTimeZero getkCMTimeZero() + +using namespace WebCore; +using namespace std; + +enum MediaPlayerAVFoundationObservationContext { + MediaPlayerAVFoundationObservationContextPlayerItem, + MediaPlayerAVFoundationObservationContextPlayer +}; + +@interface WebCoreAVFMovieObserver : NSObject +{ + MediaPlayerPrivateAVFoundationObjC* m_callback; + int m_delayCallbacks; +} +-(id)initWithCallback:(MediaPlayerPrivateAVFoundationObjC*)callback; +-(void)disconnect; +-(void)playableKnown; +-(void)metadataLoaded; +-(void)timeChanged:(double)time; +-(void)didEnd:(NSNotification *)notification; +-(void)observeValueForKeyPath:keyPath ofObject:(id)object change:(NSDictionary *)change context:(MediaPlayerAVFoundationObservationContext)context; +@end + +namespace WebCore { + +static NSArray *assetMetadataKeyNames(); +static NSArray *itemKVOProperties(); + +#if !LOG_DISABLED +static const char *boolString(bool val) +{ + return val ? "true" : "false"; +} +#endif + +static const float invalidTime = -1.0f; + +MediaPlayerPrivateInterface* MediaPlayerPrivateAVFoundationObjC::create(MediaPlayer* player) +{ + return new MediaPlayerPrivateAVFoundationObjC(player); +} + +void MediaPlayerPrivateAVFoundationObjC::registerMediaEngine(MediaEngineRegistrar registrar) +{ + if (isAvailable()) + registrar(create, getSupportedTypes, supportsType, 0, 0, 0); +} + +MediaPlayerPrivateAVFoundationObjC::MediaPlayerPrivateAVFoundationObjC(MediaPlayer* player) + : MediaPlayerPrivateAVFoundation(player) + , m_objcObserver(AdoptNS, [[WebCoreAVFMovieObserver alloc] initWithCallback:this]) + , m_timeObserver(0) +{ +} + +MediaPlayerPrivateAVFoundationObjC::~MediaPlayerPrivateAVFoundationObjC() +{ + cancelLoad(); + [m_objcObserver.get() disconnect]; +} + +void MediaPlayerPrivateAVFoundationObjC::cancelLoad() +{ + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::cancelLoad(%p)", this); + tearDownVideoRendering(); + + [[NSNotificationCenter defaultCenter] removeObserver:m_objcObserver.get()]; + + // Tell our observer to do nothing when our cancellation of pending loading calls its completion handler. + setIgnoreLoadStateChanges(true); + if (m_avAsset) { + [m_avAsset.get() cancelLoading]; + m_avAsset = nil; + } + if (m_avPlayerItem) { + for (NSString *keyName in itemKVOProperties()) + [m_avPlayerItem.get() removeObserver:m_objcObserver.get() forKeyPath:keyName]; + + m_avPlayerItem = nil; + } + if (m_avPlayer) { + if (m_timeObserver) + [m_avPlayer.get() removeTimeObserver:m_timeObserver]; + [m_avPlayer.get() removeObserver:m_objcObserver.get() forKeyPath:@"rate"]; + m_avPlayer = nil; + } + setIgnoreLoadStateChanges(false); +} + +bool MediaPlayerPrivateAVFoundationObjC::hasLayerRenderer() const +{ + return m_videoLayer; +} + +bool MediaPlayerPrivateAVFoundationObjC::hasContextRenderer() const +{ + return m_imageGenerator; +} + +void MediaPlayerPrivateAVFoundationObjC::createContextVideoRenderer() +{ + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createContextVideoRenderer(%p)", this); + + if (!m_avAsset || m_imageGenerator) + return; + + m_imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:m_avAsset.get()]; + + [m_imageGenerator.get() setApertureMode:AVAssetImageGeneratorApertureModeCleanAperture]; + [m_imageGenerator.get() setAppliesPreferredTrackTransform:YES]; + + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createImageGenerator(%p) - returning %p", this, m_imageGenerator.get()); +} + +void MediaPlayerPrivateAVFoundationObjC::destroyContextVideoRenderer() +{ + if (!m_imageGenerator) + return; + + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::destroyContextVideoRenderer(%p) - destroying", this, m_imageGenerator.get()); + + m_imageGenerator = 0; +} + +void MediaPlayerPrivateAVFoundationObjC::createVideoLayer() +{ + if (!m_avPlayer) + return; + + 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()); + } +} + +void MediaPlayerPrivateAVFoundationObjC::destroyVideoLayer() +{ + if (!m_videoLayer) + return; + + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::destroyVideoLayer(%p) - destroying", this, m_videoLayer.get()); + + [m_videoLayer.get() setPlayer:nil]; + + m_videoLayer = 0; +} + +bool MediaPlayerPrivateAVFoundationObjC::videoLayerIsReadyToDisplay() const +{ + return (m_videoLayer && [m_videoLayer.get() isReadyForDisplay]); +} + +void MediaPlayerPrivateAVFoundationObjC::createAVPlayerForURL(const String& url) +{ + setDelayCallbacks(true); + + if (!m_avAsset) { + NSURL *cocoaURL = KURL(ParsedURLString, url); + m_avAsset.adoptNS([[AVURLAsset alloc] initWithURL:cocoaURL options:nil]); + } + + createAVPlayer(); +} + +#if ENABLE(OFFLINE_WEB_APPLICATIONS) +void MediaPlayerPrivateAVFoundationObjC::createAVPlayerForCacheResource(ApplicationCacheResource* resource) +{ + // AVFoundation can't open arbitrary data pointers, so if this ApplicationCacheResource doesn't + // have a valid local path, just open the resource's original URL. + if (resource->path().isEmpty()) { + createAVPlayerForURL(resource->url()); + return; + } + + setDelayCallbacks(true); + + if (!m_avAsset) { + NSURL* localURL = [NSURL fileURLWithPath:resource->path()]; + m_avAsset.adoptNS([[AVURLAsset alloc] initWithURL:localURL options:nil]); + } + + createAVPlayer(); +} +#endif + +void MediaPlayerPrivateAVFoundationObjC::createAVPlayer() +{ + if (!m_avPlayer) { + m_avPlayer.adoptNS([[AVPlayer alloc] init]); + + [m_avPlayer.get() addObserver:m_objcObserver.get() forKeyPath:@"rate" options:nil context:(void *)MediaPlayerAVFoundationObservationContextPlayer]; + + // Add a time observer, ask to be called infrequently because we don't really want periodic callbacks but + // our observer will also be called whenever a seek happens. + const double veryLongInterval = 60*60*60*24*30; + WebCoreAVFMovieObserver *observer = m_objcObserver.get(); + m_timeObserver = [m_avPlayer.get() addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(veryLongInterval, 10) queue:nil usingBlock:^(CMTime time){ + [observer timeChanged:CMTimeGetSeconds(time)]; + }]; + } + + if (!m_avPlayerItem) { + // Create the player item so we can media data. + m_avPlayerItem.adoptNS([[AVPlayerItem alloc] initWithAsset:m_avAsset.get()]); + + [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get()selector:@selector(didEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:m_avPlayerItem.get()]; + + for (NSString *keyName in itemKVOProperties()) + [m_avPlayerItem.get() addObserver:m_objcObserver.get() forKeyPath:keyName options:nil context:(void *)MediaPlayerAVFoundationObservationContextPlayerItem]; + + [m_avPlayer.get() replaceCurrentItemWithPlayerItem:m_avPlayerItem.get()]; + } + + setDelayCallbacks(false); +} + +void MediaPlayerPrivateAVFoundationObjC::checkPlayability() +{ + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::checkPlayability(%p)", this); + + [m_avAsset.get() loadValuesAsynchronouslyForKeys:[NSArray arrayWithObject:@"playable"] completionHandler:^{ + [m_objcObserver.get() playableKnown]; + }]; +} + +void MediaPlayerPrivateAVFoundationObjC::beginLoadingMetadata() +{ + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::playabilityKnown(%p) - requesting metadata loading", this); + [m_avAsset.get() loadValuesAsynchronouslyForKeys:[assetMetadataKeyNames() retain] completionHandler:^{ + [m_objcObserver.get() metadataLoaded]; + }]; +} + +MediaPlayerPrivateAVFoundation::ItemStatus MediaPlayerPrivateAVFoundationObjC::playerItemStatus() const +{ + if (!m_avPlayerItem) + return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusUnknown; + + AVPlayerItemStatus status = [m_avPlayerItem.get() status]; + if (status == AVPlayerItemStatusUnknown) + return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusUnknown; + if (status == AVPlayerItemStatusFailed) + return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusFailed; + if ([m_avPlayerItem.get() isPlaybackLikelyToKeepUp]) + return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackLikelyToKeepUp; + if ([m_avPlayerItem.get() isPlaybackBufferFull]) + return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackBufferFull; + if ([m_avPlayerItem.get() isPlaybackBufferEmpty]) + return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackBufferEmpty; + + return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusReadyToPlay; +} + +PlatformMedia MediaPlayerPrivateAVFoundationObjC::platformMedia() const +{ + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::platformMedia(%p)", this); + PlatformMedia pm; + pm.type = PlatformMedia::AVFoundationMediaPlayerType; + pm.media.avfMediaPlayer = m_avPlayer.get(); + return pm; +} + +PlatformLayer* MediaPlayerPrivateAVFoundationObjC::platformLayer() const +{ + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::platformLayer(%p)", this); + return m_videoLayer.get(); +} + +void MediaPlayerPrivateAVFoundationObjC::play() +{ + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::play(%p)", this); + if (!metaDataAvailable()) + return; + + setDelayCallbacks(true); + [m_avPlayer.get() setRate:requestedRate()]; + setDelayCallbacks(false); +} + +void MediaPlayerPrivateAVFoundationObjC::pause() +{ + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::pause(%p)", this); + if (!metaDataAvailable()) + return; + + setDelayCallbacks(true); + [m_avPlayer.get() setRate:nil]; + setDelayCallbacks(false); +} + +float MediaPlayerPrivateAVFoundationObjC::platformDuration() const +{ + if (!metaDataAvailable() || !m_avPlayerItem) + return 0; + + float duration; + CMTime cmDuration = [m_avPlayerItem.get() duration]; + if (CMTIME_IS_NUMERIC(cmDuration)) + duration = narrowPrecisionToFloat(CMTimeGetSeconds(cmDuration)); + else if (CMTIME_IS_INDEFINITE(cmDuration)) + duration = numeric_limits<float>::infinity(); + else { + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::duration(%p) - invalid duration, returning 0", this); + return 0; + } + + return duration; +} + +float MediaPlayerPrivateAVFoundationObjC::currentTime() const +{ + if (!metaDataAvailable() || !m_avPlayerItem) + return 0; + + CMTime itemTime = [m_avPlayerItem.get() currentTime]; + if (CMTIME_IS_NUMERIC(itemTime)) + return narrowPrecisionToFloat(CMTimeGetSeconds(itemTime)); + + return 0; +} + +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]; + } + + setDelayCallbacks(false); +} + +void MediaPlayerPrivateAVFoundationObjC::setVolume(float volume) +{ + if (!metaDataAvailable()) + return; + + [m_avPlayer.get() setVolume:volume]; +} + +void MediaPlayerPrivateAVFoundationObjC::setClosedCaptionsVisible(bool closedCaptionsVisible) +{ + if (!metaDataAvailable()) + return; + + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::setClosedCaptionsVisible(%p) - setting to %s", this, boolString(closedCaptionsVisible)); + [m_avPlayer.get() setClosedCaptionDisplayEnabled:closedCaptionsVisible]; +} + +float MediaPlayerPrivateAVFoundationObjC::rate() const +{ + if (!metaDataAvailable()) + return 0; + + return [m_avPlayer.get() rate]; +} + +PassRefPtr<TimeRanges> MediaPlayerPrivateAVFoundationObjC::platformBufferedTimeRanges() const +{ + RefPtr<TimeRanges> timeRanges = TimeRanges::create(); + + if (!m_avPlayerItem) + return timeRanges.release(); + + NSArray *loadedRanges = [m_avPlayerItem.get() loadedTimeRanges]; + for (NSValue *thisRangeValue in loadedRanges) { + CMTimeRange timeRange = [thisRangeValue CMTimeRangeValue]; + if (CMTIMERANGE_IS_VALID(timeRange) && !CMTIMERANGE_IS_EMPTY(timeRange)) { + float rangeStart = narrowPrecisionToFloat(CMTimeGetSeconds(timeRange.start)); + float rangeEnd = narrowPrecisionToFloat(CMTimeGetSeconds(CMTimeRangeGetEnd(timeRange))); + timeRanges->add(rangeStart, rangeEnd); + } + } + return timeRanges.release(); +} + +float MediaPlayerPrivateAVFoundationObjC::platformMaxTimeSeekable() const +{ + NSArray *seekableRanges = [m_avPlayerItem.get() seekableTimeRanges]; + if (!seekableRanges) + return 0; + + float maxTimeSeekable = 0; + for (NSValue *thisRangeValue in seekableRanges) { + CMTimeRange timeRange = [thisRangeValue CMTimeRangeValue]; + if (!CMTIMERANGE_IS_VALID(timeRange) || CMTIMERANGE_IS_EMPTY(timeRange)) + continue; + + float endOfRange = narrowPrecisionToFloat(CMTimeGetSeconds(CMTimeRangeGetEnd(timeRange))); + if (maxTimeSeekable < endOfRange) + maxTimeSeekable = endOfRange; + } + return maxTimeSeekable; +} + +float MediaPlayerPrivateAVFoundationObjC::platformMaxTimeLoaded() const +{ + NSArray *loadedRanges = [m_avPlayerItem.get() loadedTimeRanges]; + if (!loadedRanges) + return 0; + + float maxTimeLoaded = 0; + for (NSValue *thisRangeValue in loadedRanges) { + CMTimeRange timeRange = [thisRangeValue CMTimeRangeValue]; + if (!CMTIMERANGE_IS_VALID(timeRange) || CMTIMERANGE_IS_EMPTY(timeRange)) + continue; + + float endOfRange = narrowPrecisionToFloat(CMTimeGetSeconds(CMTimeRangeGetEnd(timeRange))); + if (maxTimeLoaded < endOfRange) + maxTimeLoaded = endOfRange; + } + + return maxTimeLoaded; +} + +unsigned MediaPlayerPrivateAVFoundationObjC::totalBytes() const +{ + if (!metaDataAvailable()) + return 0; + + long long totalMediaSize = 0; + NSArray *tracks = [m_avAsset.get() tracks]; + for (AVAssetTrack *thisTrack in tracks) + totalMediaSize += [thisTrack totalSampleDataLength]; + + return static_cast<unsigned>(totalMediaSize); +} + +void MediaPlayerPrivateAVFoundationObjC::setAsset(id asset) +{ + m_avAsset = asset; +} + +MediaPlayerPrivateAVFoundation::AVAssetStatus MediaPlayerPrivateAVFoundationObjC::assetStatus() const +{ + if (!m_avAsset) + return MediaPlayerAVAssetStatusUnknown; + + for (NSString *keyName in assetMetadataKeyNames()) { + AVKeyValueStatus keyStatus = [m_avAsset.get() statusOfValueForKey:keyName error:nil]; + if (keyStatus < AVKeyValueStatusLoaded) + return MediaPlayerAVAssetStatusLoading;// At least one key is not loaded yet. + + if (keyStatus == AVKeyValueStatusFailed) + return MediaPlayerAVAssetStatusFailed; // At least one key could not be loaded. + if (keyStatus == AVKeyValueStatusCancelled) + return MediaPlayerAVAssetStatusCancelled; // Loading of at least one key was cancelled. + } + + if ([[m_avAsset.get() valueForKey:@"playable"] boolValue]) + return MediaPlayerAVAssetStatusPlayable; + + return MediaPlayerAVAssetStatusLoaded; +} + +void MediaPlayerPrivateAVFoundationObjC::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& rect) +{ + if (!metaDataAvailable() || context->paintingDisabled()) + return; + + paint(context, rect); +} + +void MediaPlayerPrivateAVFoundationObjC::paint(GraphicsContext* context, const IntRect& rect) +{ + if (!metaDataAvailable() || context->paintingDisabled()) + return; + + setDelayCallbacks(true); + BEGIN_BLOCK_OBJC_EXCEPTIONS; + + RetainPtr<CGImageRef> image = createImageForTimeInRect(currentTime(), rect); + if (image) { + context->save(); + context->translate(rect.x(), rect.y() + rect.height()); + context->scale(FloatSize(1.0f, -1.0f)); + context->setImageInterpolationQuality(InterpolationLow); + IntRect paintRect(IntPoint(0, 0), IntSize(rect.width(), rect.height())); + CGContextDrawImage(context->platformContext(), CGRectMake(0, 0, paintRect.width(), paintRect.height()), image.get()); + context->restore(); + image = 0; + } + + END_BLOCK_OBJC_EXCEPTIONS; + setDelayCallbacks(false); + + MediaPlayerPrivateAVFoundation::paint(context, rect); +} + +static HashSet<String> mimeTypeCache() +{ + DEFINE_STATIC_LOCAL(HashSet<String>, cache, ()); + static bool typeListInitialized = false; + + if (typeListInitialized) + return cache; + typeListInitialized = true; + + NSArray *types = [AVURLAsset audiovisualMIMETypes]; + for (NSString *mimeType in types) + cache.add(mimeType); + + return cache; +} + +RetainPtr<CGImageRef> MediaPlayerPrivateAVFoundationObjC::createImageForTimeInRect(float time, const IntRect& rect) +{ + if (!m_imageGenerator) + createContextVideoRenderer(); + ASSERT(m_imageGenerator); + +#if !LOG_DISABLED + double start = WTF::currentTime(); +#endif + + [m_imageGenerator.get() setMaximumSize:CGSize(rect.size())]; + CGImageRef image = [m_imageGenerator.get() copyCGImageAtTime:CMTimeMakeWithSeconds(time, 600) actualTime:nil error:nil]; + +#if !LOG_DISABLED + double duration = WTF::currentTime() - start; + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createImageForTimeInRect(%p) - creating image took %.4f", this, narrowPrecisionToFloat(duration)); +#endif + + return image; +} + +void MediaPlayerPrivateAVFoundationObjC::getSupportedTypes(HashSet<String>& supportedTypes) +{ + supportedTypes = mimeTypeCache(); +} + +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; + + return MediaPlayer::IsNotSupported; +} + +bool MediaPlayerPrivateAVFoundationObjC::isAvailable() +{ + return true; +} + +float MediaPlayerPrivateAVFoundationObjC::mediaTimeForTimeValue(float timeValue) const +{ + if (!metaDataAvailable()) + return timeValue; + + // FIXME - impossible to implement until rdar://8721510 is fixed. + return timeValue; +} + +void MediaPlayerPrivateAVFoundationObjC::tracksChanged() +{ + // This is called whenever the tracks collection changes so cache hasVideo and hasAudio since we get + // asked about those fairly fequently. + setHasVideo([[m_avAsset.get() tracksWithMediaCharacteristic:AVMediaCharacteristicVisual] count]); + setHasAudio([[m_avAsset.get() tracksWithMediaCharacteristic:AVMediaCharacteristicAudible] count]); + setHasClosedCaptions([[m_avAsset.get() tracksWithMediaType:AVMediaTypeClosedCaption] count]); + + sizeChanged(); +} + +void MediaPlayerPrivateAVFoundationObjC::sizeChanged() +{ + NSArray *tracks = [m_avAsset.get() tracks]; + + // Some assets don't report track properties until they are completely ready to play, but we + // want to report a size as early as possible so use presentationSize when an asset has no tracks. + if (![tracks count]) { + setNaturalSize(IntSize([m_avPlayerItem.get() presentationSize])); + return; + } + + // AVAsset's 'naturalSize' property only considers the movie's first video track, so we need to compute + // the union of all visual track rects. + CGRect trackUnionRect = CGRectZero; + for (AVAssetTrack *track in tracks) { + CGSize trackSize = [track naturalSize]; + CGRect trackRect = CGRectMake(0, 0, trackSize.width, trackSize.height); + trackUnionRect = CGRectUnion(trackUnionRect, CGRectApplyAffineTransform(trackRect, [track preferredTransform])); + } + + // The movie is always displayed at 0,0 so move the track rect to the origin before using width and height. + trackUnionRect = CGRectOffset(trackUnionRect, trackUnionRect.origin.x, trackUnionRect.origin.y); + + // Also look at the asset's preferred transform so we account for a movie matrix. + CGSize naturalSize = CGSizeApplyAffineTransform(trackUnionRect.size, [m_avAsset.get() preferredTransform]); + + // Cache the natural size (setNaturalSize will notify the player if it has changed). + setNaturalSize(IntSize(naturalSize)); +} + +NSArray* assetMetadataKeyNames() +{ + static NSArray* keys; + if (!keys) { + keys = [[NSArray alloc] initWithObjects:@"duration", + @"naturalSize", + @"preferredTransform", + @"preferredVolume", + @"preferredRate", + @"playable", + @"tracks", + nil]; + } + return keys; +} + +NSArray* itemKVOProperties() +{ + static NSArray* keys; + if (!keys) { + keys = [[NSArray alloc] initWithObjects:@"presentationSize", + @"status", + @"asset", + @"tracks", + @"seekableTimeRanges", + @"loadedTimeRanges", + @"playbackLikelyToKeepUp", + @"playbackBufferFull", + @"playbackBufferEmpty", + nil]; + } + return keys; +} + +} // namespace WebCore + +@implementation WebCoreAVFMovieObserver + +- (id)initWithCallback:(MediaPlayerPrivateAVFoundationObjC*)callback +{ + m_callback = callback; + return [super init]; +} + +- (void)disconnect +{ + [NSObject cancelPreviousPerformRequestsWithTarget:self]; + m_callback = 0; +} + +- (void)metadataLoaded +{ + if (!m_callback) + return; + + m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::AssetMetadataLoaded); +} + +- (void)playableKnown +{ + if (!m_callback) + return; + + m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::AssetPlayabilityKnown); +} + +- (void)timeChanged:(double)time +{ + if (!m_callback) + return; + + m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::PlayerTimeChanged, time); +} + +- (void)didEnd:(NSNotification *)unusedNotification +{ + UNUSED_PARAM(unusedNotification); + if (!m_callback) + return; + m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemDidPlayToEndTime); +} + +- (void)observeValueForKeyPath:keyPath ofObject:(id)object change:(NSDictionary *)change context:(MediaPlayerAVFoundationObservationContext)context +{ + UNUSED_PARAM(change); + + LOG(Media, "WebCoreAVFMovieObserver:observeValueForKeyPath(%p) - keyPath = %s", self, [keyPath UTF8String]); + + if (!m_callback) + return; + + if (context == MediaPlayerAVFoundationObservationContextPlayerItem) { + // A value changed for an AVPlayerItem + if ([keyPath isEqualToString:@"status"]) + m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemStatusChanged); + else if ([keyPath isEqualToString:@"playbackLikelyToKeepUp"]) + m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemIsPlaybackLikelyToKeepUpChanged); + else if ([keyPath isEqualToString:@"playbackBufferEmpty"]) + m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemIsPlaybackBufferEmptyChanged); + else if ([keyPath isEqualToString:@"playbackBufferFull"]) + m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemIsPlaybackBufferFullChanged); + else if ([keyPath isEqualToString:@"asset"]) + m_callback->setAsset([object asset]); + else if ([keyPath isEqualToString:@"loadedTimeRanges"]) + m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemLoadedTimeRangesChanged); + else if ([keyPath isEqualToString:@"seekableTimeRanges"]) + m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemSeekableTimeRangesChanged); + else if ([keyPath isEqualToString:@"tracks"]) + m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemTracksChanged); + else if ([keyPath isEqualToString:@"presentationSize"]) + m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemPresentationSizeChanged); + + return; + } + + if (context == MediaPlayerAVFoundationObservationContextPlayer) { + // A value changed for an AVPlayer. + if ([keyPath isEqualToString:@"rate"]) + m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::PlayerRateChanged); +} +} + +@end + +#endif diff --git a/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp b/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp index e9663a6..427c7bf 100644 --- a/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp +++ b/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp @@ -550,11 +550,17 @@ void GraphicsLayerCA::setNeedsDisplay() setNeedsDisplayInRect(hugeRect); } -void GraphicsLayerCA::setNeedsDisplayInRect(const FloatRect& rect) +void GraphicsLayerCA::setNeedsDisplayInRect(const FloatRect& r) { if (!drawsContent()) return; + FloatRect rect(r); + FloatRect layerBounds(FloatPoint(), m_size); + rect.intersect(layerBounds); + if (rect.isEmpty()) + return; + const size_t maxDirtyRects = 32; for (size_t i = 0; i < m_dirtyRects.size(); ++i) { @@ -1601,9 +1607,11 @@ bool GraphicsLayerCA::createTransformAnimationsFromKeyframes(const KeyframeValue TransformOperation::OperationType transformOp = isMatrixAnimation ? TransformOperation::MATRIX_3D : functionList[animationIndex]; RefPtr<PlatformCAAnimation> caAnimation; -#if defined(BUILDING_ON_LEOPARD) || defined(BUILDING_ON_SNOW_LEOPARD) +#if defined(BUILDING_ON_LEOPARD) || defined(BUILDING_ON_SNOW_LEOPARD) || PLATFORM(WIN) // CA applies animations in reverse order (<rdar://problem/7095638>) so we need the last one we add (per property) // to be non-additive. + // FIXME: This fix has not been added to QuartzCore on Windows yet (<rdar://problem/9112233>) so we expect the + // reversed animation behavior bool additive = animationIndex < (numAnimations - 1); #else bool additive = animationIndex > 0; diff --git a/Source/WebCore/platform/graphics/ca/PlatformCAAnimation.h b/Source/WebCore/platform/graphics/ca/PlatformCAAnimation.h index a8528fd..8b5a460 100644 --- a/Source/WebCore/platform/graphics/ca/PlatformCAAnimation.h +++ b/Source/WebCore/platform/graphics/ca/PlatformCAAnimation.h @@ -38,11 +38,10 @@ #if PLATFORM(MAC) #ifdef __OBJC__ @class CAPropertyAnimation; -typedef CAPropertyAnimation* PlatformAnimationRef; #else -typedef void* CAPropertyAnimation; // So the m_animation declaration works -typedef void* PlatformAnimationRef; +class CAPropertyAnimation; #endif +typedef CAPropertyAnimation* PlatformAnimationRef; #elif PLATFORM(WIN) typedef struct _CACFAnimation* CACFAnimationRef; typedef CACFAnimationRef PlatformAnimationRef; diff --git a/Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHost.cpp b/Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHost.cpp index f2e1950..75f4a10 100644 --- a/Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHost.cpp +++ b/Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHost.cpp @@ -307,13 +307,14 @@ void CACFLayerTreeHost::contextDidChange() void CACFLayerTreeHost::notifyAnimationsStarted() { + // Send currentTime to the pending animations. This function is called by CACF in a callback + // which occurs after the drawInContext calls. So currentTime is very close to the time + // the animations actually start double currentTime = WTF::currentTime(); - double time = currentTime + lastCommitTime() - CACurrentMediaTime(); - ASSERT(time <= currentTime); HashSet<RefPtr<PlatformCALayer> >::iterator end = m_pendingAnimatedLayers.end(); for (HashSet<RefPtr<PlatformCALayer> >::iterator it = m_pendingAnimatedLayers.begin(); it != end; ++it) - (*it)->animationStarted(time); + (*it)->animationStarted(currentTime); m_pendingAnimatedLayers.clear(); } diff --git a/Source/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp b/Source/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp index b0588d6..0f90ce4 100644 --- a/Source/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp @@ -34,6 +34,7 @@ #include "GraphicsContext.h" #include "OwnPtrCairo.h" #include "Path.h" +#include "PlatformContextCairo.h" #include "Timer.h" #include <cairo.h> @@ -88,7 +89,7 @@ PlatformContext ContextShadow::beginShadowLayer(GraphicsContext* context, const adjustBlurDistance(context); double x1, x2, y1, y2; - cairo_clip_extents(context->platformContext(), &x1, &y1, &x2, &y2); + cairo_clip_extents(context->platformContext()->cr(), &x1, &y1, &x2, &y2); IntRect layerRect = calculateLayerBoundingRect(context, layerArea, IntRect(x1, y1, x2 - x1, y2 - y1)); // Don't paint if we are totally outside the clip region. @@ -120,7 +121,7 @@ void ContextShadow::endShadowLayer(GraphicsContext* context) cairo_surface_mark_dirty(m_layerImage); } - cairo_t* cr = context->platformContext(); + cairo_t* cr = context->platformContext()->cr(); cairo_save(cr); setSourceRGBAFromColor(cr, m_color); cairo_mask_surface(cr, m_layerImage, m_layerOrigin.x(), m_layerOrigin.y()); @@ -198,7 +199,7 @@ void ContextShadow::drawRectShadow(GraphicsContext* context, const IntRect& rect int internalShadowHeight = radiusTwice + max(topLeftRadius.height(), topRightRadius.height()) + max(bottomLeftRadius.height(), bottomRightRadius.height()); - cairo_t* cr = context->platformContext(); + cairo_t* cr = context->platformContext()->cr(); // drawShadowedRect still does not work with rotations. // https://bugs.webkit.org/show_bug.cgi?id=45042 diff --git a/Source/WebCore/platform/graphics/cairo/FontCairo.cpp b/Source/WebCore/platform/graphics/cairo/FontCairo.cpp index 2d79499..58a7fd2 100644 --- a/Source/WebCore/platform/graphics/cairo/FontCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/FontCairo.cpp @@ -36,6 +36,7 @@ #include "GlyphBuffer.h" #include "Gradient.h" #include "GraphicsContext.h" +#include "PlatformContextCairo.h" #include "ImageBuffer.h" #include "Pattern.h" #include "SimpleFontData.h" @@ -64,7 +65,7 @@ static void drawGlyphsToContext(cairo_t* context, const SimpleFontData* font, Gl } } -static void drawGlyphsShadow(GraphicsContext* graphicsContext, cairo_t* context, const FloatPoint& point, const SimpleFontData* font, GlyphBufferGlyph* glyphs, int numGlyphs) +static void drawGlyphsShadow(GraphicsContext* graphicsContext, const FloatPoint& point, const SimpleFontData* font, GlyphBufferGlyph* glyphs, int numGlyphs) { ContextShadow* shadow = graphicsContext->contextShadow(); ASSERT(shadow); @@ -74,6 +75,7 @@ static void drawGlyphsShadow(GraphicsContext* graphicsContext, cairo_t* context, if (!shadow->mustUseContextShadow(graphicsContext)) { // Optimize non-blurry shadows, by just drawing text without the ContextShadow. + cairo_t* context = graphicsContext->platformContext()->cr(); cairo_save(context); cairo_translate(context, shadow->m_offset.width(), shadow->m_offset.height()); setSourceRGBAFromColor(context, shadow->m_color); @@ -106,9 +108,10 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons offset += glyphBuffer.advanceAt(from + i); } - cairo_t* cr = context->platformContext(); - drawGlyphsShadow(context, cr, point, font, glyphs, numGlyphs); + PlatformContextCairo* platformContext = context->platformContext(); + drawGlyphsShadow(context, point, font, glyphs, numGlyphs); + cairo_t* cr = platformContext->cr(); cairo_save(cr); prepareContextForGlyphDrawing(cr, font, point); if (context->textDrawingMode() & TextModeFill) { diff --git a/Source/WebCore/platform/graphics/cairo/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/cairo/FontCustomPlatformData.h index 5807102..f8f3c99 100644 --- a/Source/WebCore/platform/graphics/cairo/FontCustomPlatformData.h +++ b/Source/WebCore/platform/graphics/cairo/FontCustomPlatformData.h @@ -25,6 +25,7 @@ #include "FontOrientation.h" #include "FontRenderingMode.h" #include "FontWidthVariant.h" +#include "TextOrientation.h" #include <wtf/Forward.h> #include <wtf/Noncopyable.h> @@ -41,7 +42,7 @@ struct FontCustomPlatformData { public: FontCustomPlatformData(FT_Face, SharedBuffer*); ~FontCustomPlatformData(); - FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontWidthVariant = RegularWidth, FontRenderingMode = NormalRenderingMode); + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, TextOrientation = TextOrientationVerticalRight, FontWidthVariant = RegularWidth, FontRenderingMode = NormalRenderingMode); static bool supportsFormat(const String&); private: diff --git a/Source/WebCore/platform/graphics/cairo/GradientCairo.cpp b/Source/WebCore/platform/graphics/cairo/GradientCairo.cpp index 4e6ed07..225046a 100644 --- a/Source/WebCore/platform/graphics/cairo/GradientCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/GradientCairo.cpp @@ -29,6 +29,7 @@ #include "CSSParser.h" #include "GraphicsContext.h" +#include "PlatformContextCairo.h" #include <cairo.h> namespace WebCore { @@ -87,7 +88,7 @@ void Gradient::setPlatformGradientSpaceTransform(const AffineTransform& gradient void Gradient::fill(GraphicsContext* context, const FloatRect& rect) { - cairo_t* cr = context->platformContext(); + cairo_t* cr = context->platformContext()->cr(); context->save(); cairo_set_source(cr, platformGradient()); diff --git a/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp index e69a7a5..0fc94df 100644 --- a/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp @@ -47,6 +47,7 @@ #include "NotImplemented.h" #include "Path.h" #include "Pattern.h" +#include "PlatformContextCairo.h" #include "RefPtrCairo.h" #include "SimpleFontData.h" #include <cairo.h> @@ -148,7 +149,7 @@ static inline void drawPathShadow(GraphicsContext* context, PathDrawingStyle dra return; // Calculate the extents of the rendered solid paths. - cairo_t* cairoContext = context->platformContext(); + cairo_t* cairoContext = context->platformContext()->cr(); OwnPtr<cairo_path_t> path(cairo_copy_path(cairoContext)); FloatRect solidFigureExtents; @@ -199,12 +200,18 @@ static void strokeCurrentCairoPath(GraphicsContext* context, cairo_t* cairoCont cairo_new_path(cairoContext); } -void GraphicsContext::platformInit(PlatformGraphicsContext* cr) +GraphicsContext::GraphicsContext(cairo_t* cr) { - m_data = new GraphicsContextPlatformPrivate; - m_data->cr = cairo_reference(cr); - m_data->syncContext(cr); - setPaintingDisabled(!cr); + m_data = new GraphicsContextPlatformPrivate(new PlatformContextCairo(cr)); +} + +void GraphicsContext::platformInit(PlatformContextCairo* platformContext) +{ + m_data = new GraphicsContextPlatformPrivate(platformContext); + if (platformContext) + m_data->syncContext(platformContext->cr()); + else + setPaintingDisabled(true); } void GraphicsContext::platformDestroy() @@ -214,20 +221,20 @@ void GraphicsContext::platformDestroy() AffineTransform GraphicsContext::getCTM() const { - cairo_t* cr = platformContext(); + cairo_t* cr = platformContext()->cr(); cairo_matrix_t m; cairo_get_matrix(cr, &m); return AffineTransform(m.xx, m.yx, m.xy, m.yy, m.x0, m.y0); } -cairo_t* GraphicsContext::platformContext() const +PlatformContextCairo* GraphicsContext::platformContext() const { - return m_data->cr; + return m_data->platformContext; } void GraphicsContext::savePlatformState() { - cairo_save(m_data->cr); + cairo_save(platformContext()->cr()); m_data->save(); m_data->shadowStack.append(m_data->shadow); m_data->maskImageStack.append(ImageMaskInformation()); @@ -235,7 +242,8 @@ void GraphicsContext::savePlatformState() void GraphicsContext::restorePlatformState() { - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); + const ImageMaskInformation& maskInformation = m_data->maskImageStack.last(); if (maskInformation.isValid()) { const FloatRect& maskRect = maskInformation.maskRect(); @@ -251,7 +259,7 @@ void GraphicsContext::restorePlatformState() m_data->shadowStack.removeLast(); } - cairo_restore(m_data->cr); + cairo_restore(cr); m_data->restore(); } @@ -261,7 +269,7 @@ void GraphicsContext::drawRect(const IntRect& rect) if (paintingDisabled()) return; - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); cairo_save(cr); if (fillColor().alpha()) @@ -289,7 +297,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) if (style == NoStroke) return; - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); cairo_save(cr); float width = strokeThickness(); @@ -376,7 +384,7 @@ void GraphicsContext::drawEllipse(const IntRect& rect) if (paintingDisabled()) return; - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); cairo_save(cr); float yRadius = .5 * rect.height(); float xRadius = .5 * rect.width(); @@ -415,7 +423,7 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp float fa = startAngle; float falen = fa + angleSpan; - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); cairo_save(cr); if (w != h) @@ -492,7 +500,7 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points if (npoints <= 1) return; - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); cairo_save(cr); cairo_set_antialias(cr, shouldAntialias ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE); @@ -522,7 +530,7 @@ void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* poin if (numPoints <= 1) return; - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); cairo_new_path(cr); cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr); @@ -542,7 +550,7 @@ void GraphicsContext::fillPath(const Path& path) if (paintingDisabled()) return; - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); setPathOnCairoContext(cr, path.platformPath()->context()); fillCurrentCairoPath(this, cr); } @@ -552,7 +560,7 @@ void GraphicsContext::strokePath(const Path& path) if (paintingDisabled()) return; - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); setPathOnCairoContext(cr, path.platformPath()->context()); strokeCurrentCairoPath(this, cr); } @@ -562,7 +570,7 @@ void GraphicsContext::fillRect(const FloatRect& rect) if (paintingDisabled()) return; - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); cairo_save(cr); cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); fillCurrentCairoPath(this, cr); @@ -578,7 +586,7 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorS m_data->shadow.drawRectShadow(this, enclosingIntRect(rect)); if (color.alpha()) - fillRectSourceOver(m_data->cr, rect, color); + fillRectSourceOver(platformContext()->cr(), rect, color); } void GraphicsContext::clip(const FloatRect& rect) @@ -586,7 +594,7 @@ void GraphicsContext::clip(const FloatRect& rect) if (paintingDisabled()) return; - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr); cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING); @@ -600,7 +608,7 @@ void GraphicsContext::clipPath(const Path& path, WindRule clipRule) if (paintingDisabled()) return; - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); setPathOnCairoContext(cr, path.platformPath()->context()); cairo_set_fill_rule(cr, clipRule == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); cairo_clip(cr); @@ -638,7 +646,7 @@ void GraphicsContext::drawFocusRing(const Path& path, int width, int /* offset * adjustFocusRingColor(ringColor); adjustFocusRingLineWidth(width); - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); cairo_save(cr); appendWebCorePathToCairoContext(cr, path); setSourceRGBAFromColor(cr, ringColor); @@ -655,7 +663,7 @@ void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int unsigned rectCount = rects.size(); - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); cairo_save(cr); cairo_push_group(cr); cairo_new_path(cr); @@ -732,7 +740,7 @@ void GraphicsContext::drawLineForTextChecking(const FloatPoint& origin, float wi if (paintingDisabled()) return; - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); cairo_save(cr); switch (style) { @@ -762,7 +770,7 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) FloatRect result; double x = frect.x(); double y = frect.y(); - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); cairo_user_to_device(cr, &x, &y); x = round(x); y = round(y); @@ -799,7 +807,7 @@ void GraphicsContext::translate(float x, float y) if (paintingDisabled()) return; - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); cairo_translate(cr, x, y); m_data->translate(x, y); } @@ -821,7 +829,7 @@ void GraphicsContext::setPlatformStrokeThickness(float strokeThickness) if (paintingDisabled()) return; - cairo_set_line_width(m_data->cr, strokeThickness); + cairo_set_line_width(platformContext()->cr(), strokeThickness); } void GraphicsContext::setPlatformStrokeStyle(StrokeStyle strokeStyle) @@ -835,16 +843,16 @@ void GraphicsContext::setPlatformStrokeStyle(StrokeStyle strokeStyle) switch (strokeStyle) { case NoStroke: // FIXME: is it the right way to emulate NoStroke? - cairo_set_line_width(m_data->cr, 0); + cairo_set_line_width(platformContext()->cr(), 0); break; case SolidStroke: - cairo_set_dash(m_data->cr, 0, 0, 0); + cairo_set_dash(platformContext()->cr(), 0, 0, 0); break; case DottedStroke: - cairo_set_dash(m_data->cr, dotPattern, 2, 0); + cairo_set_dash(platformContext()->cr(), dotPattern, 2, 0); break; case DashedStroke: - cairo_set_dash(m_data->cr, dashPattern, 2, 0); + cairo_set_dash(platformContext()->cr(), dashPattern, 2, 0); break; } } @@ -859,7 +867,7 @@ void GraphicsContext::concatCTM(const AffineTransform& transform) if (paintingDisabled()) return; - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); const cairo_matrix_t matrix = cairo_matrix_t(transform); cairo_transform(cr, &matrix); m_data->concatCTM(transform); @@ -870,7 +878,7 @@ void GraphicsContext::setCTM(const AffineTransform& transform) if (paintingDisabled()) return; - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); const cairo_matrix_t matrix = cairo_matrix_t(transform); cairo_set_matrix(cr, &matrix); m_data->setCTM(transform); @@ -881,7 +889,7 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness if (paintingDisabled()) return; - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); clip(rect); Path p; @@ -928,7 +936,7 @@ void GraphicsContext::beginTransparencyLayer(float opacity) if (paintingDisabled()) return; - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); cairo_push_group(cr); m_data->layers.append(opacity); m_data->beginTransparencyLayer(); @@ -939,7 +947,7 @@ void GraphicsContext::endTransparencyLayer() if (paintingDisabled()) return; - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); cairo_pop_group_to_source(cr); cairo_paint_with_alpha(cr, m_data->layers.last()); @@ -952,7 +960,7 @@ void GraphicsContext::clearRect(const FloatRect& rect) if (paintingDisabled()) return; - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); cairo_save(cr); cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); @@ -966,7 +974,7 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float width) if (paintingDisabled()) return; - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); cairo_save(cr); cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); cairo_set_line_width(cr, width); @@ -991,12 +999,12 @@ void GraphicsContext::setLineCap(LineCap lineCap) cairoCap = CAIRO_LINE_CAP_SQUARE; break; } - cairo_set_line_cap(m_data->cr, cairoCap); + cairo_set_line_cap(platformContext()->cr(), cairoCap); } void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset) { - cairo_set_dash(m_data->cr, dashes.data(), dashes.size(), dashOffset); + cairo_set_dash(platformContext()->cr(), dashes.data(), dashes.size(), dashOffset); } void GraphicsContext::setLineJoin(LineJoin lineJoin) @@ -1016,7 +1024,7 @@ void GraphicsContext::setLineJoin(LineJoin lineJoin) cairoJoin = CAIRO_LINE_JOIN_BEVEL; break; } - cairo_set_line_join(m_data->cr, cairoJoin); + cairo_set_line_join(platformContext()->cr(), cairoJoin); } void GraphicsContext::setMiterLimit(float miter) @@ -1024,7 +1032,7 @@ void GraphicsContext::setMiterLimit(float miter) if (paintingDisabled()) return; - cairo_set_miter_limit(m_data->cr, miter); + cairo_set_miter_limit(platformContext()->cr(), miter); } void GraphicsContext::setAlpha(float alpha) @@ -1042,7 +1050,7 @@ void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op) if (paintingDisabled()) return; - cairo_set_operator(m_data->cr, toCairoOperator(op)); + cairo_set_operator(platformContext()->cr(), toCairoOperator(op)); } void GraphicsContext::clip(const Path& path) @@ -1050,7 +1058,7 @@ void GraphicsContext::clip(const Path& path) if (paintingDisabled()) return; - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); OwnPtr<cairo_path_t> p(cairo_copy_path(path.platformPath()->context())); cairo_append_path(cr, p.get()); cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr); @@ -1070,7 +1078,7 @@ void GraphicsContext::clipOut(const Path& path) if (paintingDisabled()) return; - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); double x1, y1, x2, y2; cairo_clip_extents(cr, &x1, &y1, &x2, &y2); cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1); @@ -1087,7 +1095,7 @@ void GraphicsContext::rotate(float radians) if (paintingDisabled()) return; - cairo_rotate(m_data->cr, radians); + cairo_rotate(platformContext()->cr(), radians); m_data->rotate(radians); } @@ -1096,7 +1104,7 @@ void GraphicsContext::scale(const FloatSize& size) if (paintingDisabled()) return; - cairo_scale(m_data->cr, size.width(), size.height()); + cairo_scale(platformContext()->cr(), size.width(), size.height()); m_data->scale(size); } @@ -1105,7 +1113,7 @@ void GraphicsContext::clipOut(const IntRect& r) if (paintingDisabled()) return; - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); double x1, y1, x2, y2; cairo_clip_extents(cr, &x1, &y1, &x2, &y2); cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1); @@ -1132,7 +1140,7 @@ void GraphicsContext::fillRoundedRect(const IntRect& r, const IntSize& topLeft, if (hasShadow()) m_data->shadow.drawRectShadow(this, r, topLeft, topRight, bottomLeft, bottomRight); - cairo_t* cr = m_data->cr; + cairo_t* cr = platformContext()->cr(); cairo_save(cr); Path path; path.addRoundedRect(r, topLeft, topRight, bottomLeft, bottomRight); @@ -1170,7 +1178,7 @@ void GraphicsContext::setPlatformShouldAntialias(bool enable) // When true, use the default Cairo backend antialias mode (usually this // enables standard 'grayscale' antialiasing); false to explicitly disable // antialiasing. This is the same strategy as used in drawConvexPolygon(). - cairo_set_antialias(m_data->cr, enable ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE); + cairo_set_antialias(platformContext()->cr(), enable ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE); } void GraphicsContext::setImageInterpolationQuality(InterpolationQuality) @@ -1196,7 +1204,7 @@ void GraphicsContext::pushImageMask(cairo_surface_t* surface, const FloatRect& r // 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 = m_data->cr; + cairo_t* cr = platformContext()->cr(); cairo_surface_t* currentTarget = cairo_get_target(cr); cairo_surface_flush(currentTarget); diff --git a/Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h b/Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h index 924f69a..2bc290b 100644 --- a/Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h +++ b/Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h @@ -31,6 +31,7 @@ #include "GraphicsContext.h" #include "ContextShadow.h" +#include "PlatformContextCairo.h" #include "RefPtrCairo.h" #include <cairo.h> #include <math.h> @@ -67,8 +68,8 @@ private: class GraphicsContextPlatformPrivate { public: - GraphicsContextPlatformPrivate() - : cr(0) + GraphicsContextPlatformPrivate(PlatformContextCairo* newPlatformContext) + : platformContext(newPlatformContext) #if PLATFORM(GTK) , expose(0) #elif PLATFORM(WIN) @@ -82,7 +83,6 @@ public: ~GraphicsContextPlatformPrivate() { - cairo_destroy(cr); } #if PLATFORM(WIN) @@ -99,7 +99,7 @@ public: void setCTM(const AffineTransform&); void beginTransparencyLayer() { m_transparencyCount++; } void endTransparencyLayer() { m_transparencyCount--; } - void syncContext(PlatformGraphicsContext* cr); + void syncContext(cairo_t* cr); #else // On everything else, we do nothing. void save() {} @@ -114,12 +114,11 @@ public: void setCTM(const AffineTransform&) {} void beginTransparencyLayer() {} void endTransparencyLayer() {} - void syncContext(PlatformGraphicsContext* cr) {} + void syncContext(cairo_t* cr) {} #endif - cairo_t* cr; + PlatformContextCairo* platformContext; Vector<float> layers; - ContextShadow shadow; Vector<ContextShadow> shadowStack; Vector<ImageMaskInformation> maskImageStack; @@ -133,6 +132,23 @@ public: #endif }; +// This is a specialized private section for the Cairo GraphicsContext, which knows how +// to clean up the heap allocated PlatformContextCairo that we must use for the top-level +// GraphicsContext. +class GraphicsContextPlatformPrivateToplevel : public GraphicsContextPlatformPrivate { +public: + GraphicsContextPlatformPrivateToplevel(PlatformContextCairo* platformContext) + : GraphicsContextPlatformPrivate(platformContext) + { + } + + ~GraphicsContextPlatformPrivateToplevel() + { + delete platformContext; + } +}; + + } // namespace WebCore #endif // GraphicsContextPlatformPrivateCairo_h diff --git a/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp index 9ee8a94..1d5d492 100644 --- a/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp @@ -37,7 +37,9 @@ #include "MIMETypeRegistry.h" #include "NotImplemented.h" #include "Pattern.h" +#include "PlatformContextCairo.h" #include "PlatformString.h" +#include "RefPtrCairo.h" #include <cairo.h> #include <wtf/Vector.h> @@ -66,6 +68,7 @@ namespace WebCore { ImageBufferData::ImageBufferData(const IntSize& size) : m_surface(0) + , m_platformContext(0) { } @@ -80,9 +83,9 @@ ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode, bool& s if (cairo_surface_status(m_data.m_surface) != CAIRO_STATUS_SUCCESS) return; // create will notice we didn't set m_initialized and fail. - cairo_t* cr = cairo_create(m_data.m_surface); - m_context.set(new GraphicsContext(cr)); - cairo_destroy(cr); // The context is now owned by the GraphicsContext. + RefPtr<cairo_t> cr = adoptRef(cairo_create(m_data.m_surface)); + m_data.m_platformContext.setCr(cr.get()); + m_context.set(new GraphicsContext(&m_data.m_platformContext)); success = true; } @@ -301,7 +304,7 @@ static cairo_status_t writeFunction(void* closure, const unsigned char* data, un String ImageBuffer::toDataURL(const String& mimeType, const double*) const { - cairo_surface_t* image = cairo_get_target(context()->platformContext()); + cairo_surface_t* image = cairo_get_target(context()->platformContext()->cr()); if (!image) return "data:,"; diff --git a/Source/WebCore/platform/graphics/cairo/ImageBufferData.h b/Source/WebCore/platform/graphics/cairo/ImageBufferData.h index 49f15df..42867d1 100644 --- a/Source/WebCore/platform/graphics/cairo/ImageBufferData.h +++ b/Source/WebCore/platform/graphics/cairo/ImageBufferData.h @@ -26,7 +26,9 @@ #ifndef ImageBufferData_h #define ImageBufferData_h -#include "cairo.h" +#include "PlatformContextCairo.h" + +typedef struct _cairo_surface cairo_surface_t; namespace WebCore { @@ -37,6 +39,7 @@ public: ImageBufferData(const IntSize&); cairo_surface_t* m_surface; + PlatformContextCairo m_platformContext; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/cairo/ImageCairo.cpp b/Source/WebCore/platform/graphics/cairo/ImageCairo.cpp index e51d65a..d3a52ce 100644 --- a/Source/WebCore/platform/graphics/cairo/ImageCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/ImageCairo.cpp @@ -36,6 +36,7 @@ #include "ContextShadow.h" #include "FloatRect.h" #include "GraphicsContext.h" +#include "PlatformContextCairo.h" #include "ImageBuffer.h" #include "ImageObserver.h" #include "RefPtrCairo.h" @@ -114,7 +115,7 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo IntSize selfSize = size(); - cairo_t* cr = context->platformContext(); + cairo_t* cr = context->platformContext()->cr(); context->save(); // Set the compositing operation. @@ -169,8 +170,7 @@ void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, con if (!image) // If it's too early we won't have an image yet. return; - cairo_t* cr = context->platformContext(); - + cairo_t* cr = context->platformContext()->cr(); drawPatternToCairoContext(cr, image, size(), tileRect, patternTransform, phase, toCairoOperator(op), destRect); if (imageObserver()) diff --git a/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.cpp b/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.cpp index 94f6809..1594e7b 100644 --- a/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.cpp @@ -20,7 +20,7 @@ #include "config.h" #include "OwnPtrCairo.h" -#if defined(USE_FREETYPE) +#if USE(FREETYPE) #include <cairo-ft.h> #include <fontconfig/fcfreetype.h> #endif @@ -29,7 +29,7 @@ namespace WTF { -#if defined(USE_FREETYPE) +#if USE(FREETYPE) template <> void deleteOwnedPtr<FcObjectSet>(FcObjectSet* ptr) { if (ptr) diff --git a/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.h b/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.h index 035d80e..e1dd370 100644 --- a/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.h +++ b/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.h @@ -22,7 +22,7 @@ #include "OwnPtr.h" -#if defined(USE_FREETYPE) +#if USE(FREETYPE) typedef struct _FcObjectSet FcObjectSet; typedef struct _FcFontSet FcFontSet; #endif @@ -31,7 +31,7 @@ typedef struct cairo_path cairo_path_t; namespace WTF { -#if defined(USE_FREETYPE) +#if USE(FREETYPE) template <> void deleteOwnedPtr<FcObjectSet>(FcObjectSet*); template <> void deleteOwnedPtr<FcFontSet>(FcFontSet*); #endif diff --git a/Source/WebCore/platform/graphics/cairo/PathCairo.cpp b/Source/WebCore/platform/graphics/cairo/PathCairo.cpp index 7a09a52..533df10 100644 --- a/Source/WebCore/platform/graphics/cairo/PathCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/PathCairo.cpp @@ -281,7 +281,7 @@ FloatRect Path::boundingRect() const return FloatRect(x0, y0, x1 - x0, y1 - y0); } -FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) +FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) const { cairo_t* cr = platformPath()->context(); if (applier) { diff --git a/Source/WebCore/platform/mac/WebCoreKeyGenerator.h b/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.cpp index c9260e1..ba75162 100644 --- a/Source/WebCore/platform/mac/WebCoreKeyGenerator.h +++ b/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003 Apple Computer, 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 @@ -23,10 +23,16 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -@interface WebCoreKeyGenerator : NSObject +#include "config.h" +#include "PlatformContextCairo.h" -+ (WebCoreKeyGenerator *)sharedGenerator; -- (NSArray *)strengthMenuItemTitles; -- (NSString *)signedPublicKeyAndChallengeStringWithStrengthIndex:(unsigned)index challenge:(NSString *)challenge pageURL:(NSURL *)pageURL; +#include <cairo.h> -@end +namespace WebCore { + +PlatformContextCairo::PlatformContextCairo(cairo_t* cr) + : m_cr(cr) +{ +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/mac/SSLKeyGeneratorMac.mm b/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.h index dd76b59..c6cceda 100644 --- a/Source/WebCore/platform/mac/SSLKeyGeneratorMac.mm +++ b/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2008 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 @@ -23,27 +23,30 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#import "config.h" -#import "SSLKeyGenerator.h" +#ifndef PlatformContextCairo_h +#define PlatformContextCairo_h -#import "KURL.h" -#import "WebCoreKeyGenerator.h" +#include "ContextShadow.h" +#include "RefPtrCairo.h" namespace WebCore { -void getSupportedKeySizes(Vector<String>& supportedKeySizes) -{ - NSEnumerator *enumerator = [[[WebCoreKeyGenerator sharedGenerator] strengthMenuItemTitles] objectEnumerator]; - NSString *string; - while ((string = [enumerator nextObject]) != nil) - supportedKeySizes.append(string); -} - -String signedPublicKeyAndChallengeString(unsigned keySizeIndex, const String& challengeString, const KURL& url) -{ - return [[WebCoreKeyGenerator sharedGenerator] signedPublicKeyAndChallengeStringWithStrengthIndex:keySizeIndex - challenge:challengeString - pageURL:url]; -} - -} +// 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 +// code from the platform-independent GraphicsContext. + +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; } + +private: + RefPtr<cairo_t> m_cr; +}; + +} // namespace WebCore + +#endif // PlatformContextCairo_h diff --git a/Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp b/Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp index c8b242c..1792002 100644 --- a/Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp @@ -21,7 +21,7 @@ #include <cairo.h> -#if defined(USE_FREETYPE) +#if USE(FREETYPE) #include <cairo-ft.h> #include <fontconfig/fcfreetype.h> #endif @@ -88,7 +88,7 @@ template<> void derefIfNotNull(cairo_pattern_t* ptr) cairo_pattern_destroy(ptr); } -#if defined(USE_FREETYPE) +#if USE(FREETYPE) template<> void refIfNotNull(FcPattern* ptr) { if (LIKELY(ptr != 0)) diff --git a/Source/WebCore/platform/graphics/cairo/RefPtrCairo.h b/Source/WebCore/platform/graphics/cairo/RefPtrCairo.h index 204d1e3..540f9dc 100644 --- a/Source/WebCore/platform/graphics/cairo/RefPtrCairo.h +++ b/Source/WebCore/platform/graphics/cairo/RefPtrCairo.h @@ -28,7 +28,7 @@ typedef struct _cairo_font_face cairo_font_face_t; typedef struct _cairo_scaled_font cairo_scaled_font_t; typedef struct _cairo_pattern cairo_pattern_t; -#if defined(USE_FREETYPE) +#if USE(FREETYPE) typedef struct _FcPattern FcPattern; #endif @@ -49,7 +49,7 @@ template<> void derefIfNotNull(cairo_scaled_font_t* ptr); template<> void refIfNotNull(cairo_pattern_t*); template<> void derefIfNotNull(cairo_pattern_t*); -#if defined(USE_FREETYPE) +#if USE(FREETYPE) template<> void refIfNotNull(FcPattern* ptr); template<> void derefIfNotNull(FcPattern* ptr); #endif diff --git a/Source/WebCore/platform/graphics/cg/FontPlatformData.h b/Source/WebCore/platform/graphics/cg/FontPlatformData.h deleted file mode 100644 index e21b444..0000000 --- a/Source/WebCore/platform/graphics/cg/FontPlatformData.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * This file is part of the internal font implementation. It should not be included by anyone other than - * FontMac.cpp, FontWin.cpp and Font.cpp. - * - * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#ifndef FontPlatformData_h -#define FontPlatformData_h - -#include "FontOrientation.h" -#include "RefCountedGDIHandle.h" -#include "StringImpl.h" -#include <wtf/Forward.h> -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> -#include <wtf/RetainPtr.h> - -typedef struct HFONT__* HFONT; -typedef struct CGFont* CGFontRef; - -namespace WebCore { - -class FontDescription; - -class FontPlatformData { -public: - FontPlatformData() - : m_size(0) - , m_syntheticBold(false) - , m_syntheticOblique(false) - , m_useGDI(false) - { - } - - FontPlatformData(HFONT, float size, bool bold, bool oblique, bool useGDI); - FontPlatformData(float size, bool bold, bool oblique); - - FontPlatformData(HFONT, CGFontRef, float size, bool bold, bool oblique, bool useGDI); - ~FontPlatformData(); - - FontPlatformData(WTF::HashTableDeletedValueType) : m_font(WTF::HashTableDeletedValue) { } - bool isHashTableDeletedValue() const { return m_font.isHashTableDeletedValue(); } - - HFONT hfont() const { return m_font->handle(); } - CGFontRef cgFont() const { return m_cgFont.get(); } - - float size() const { return m_size; } - void setSize(float size) { m_size = size; } - bool syntheticBold() const { return m_syntheticBold; } - bool syntheticOblique() const { return m_syntheticOblique; } - bool useGDI() const { return m_useGDI; } - - FontOrientation orientation() const { return Horizontal; } // FIXME: Implement. - - unsigned hash() const - { - return m_font->hash(); - } - - bool operator==(const FontPlatformData& other) const - { - return m_font == other.m_font - && m_cgFont == other.m_cgFont - && m_size == other.m_size - && m_syntheticBold == other.m_syntheticBold - && m_syntheticOblique == other.m_syntheticOblique - && m_useGDI == other.m_useGDI; - } - -#ifndef NDEBUG - String description() const; -#endif - -private: - void platformDataInit(HFONT, float size, HDC, WCHAR* faceName); - - RefPtr<RefCountedGDIHandle<HFONT> > m_font; - RetainPtr<CGFontRef> m_cgFont; - - float m_size; - bool m_syntheticBold; - bool m_syntheticOblique; - bool m_useGDI; -}; - -} // namespace WebCore - -#endif diff --git a/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp index dbcab45..7799137 100644 --- a/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp +++ b/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp @@ -695,7 +695,7 @@ void GraphicsContext::fillRect(const FloatRect& rect) if (m_state.fillPattern) applyFillPattern(); - bool drawOwnShadow = hasBlurredShadow(m_state) && !m_state.shadowsIgnoreTransforms; // Don't use ShadowBlur for canvas yet. + 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; // Turn off CG shadows. @@ -724,7 +724,7 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorS if (oldFillColor != color || oldColorSpace != colorSpace) setCGFillColor(context, color, colorSpace); - bool drawOwnShadow = hasBlurredShadow(m_state) && !m_state.shadowsIgnoreTransforms; // Don't use ShadowBlur for canvas yet. + 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; // Turn off CG shadows. @@ -759,7 +759,7 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef Path path; path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight); - bool drawOwnShadow = hasBlurredShadow(m_state) && !m_state.shadowsIgnoreTransforms; // Don't use ShadowBlur for canvas yet. + 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; @@ -803,7 +803,7 @@ void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const Rounded setFillColor(color, colorSpace); // fillRectWithRoundedHole() assumes that the edges of rect are clipped out, so we only care about shadows cast around inside the hole. - bool drawOwnShadow = hasBlurredShadow(m_state) && !m_state.shadowsIgnoreTransforms; + bool drawOwnShadow = !isAcceleratedContext() && hasBlurredShadow(m_state) && !m_state.shadowsIgnoreTransforms; if (drawOwnShadow) { float shadowBlur = m_state.shadowsUseLegacyRadius ? radiusToLegacyRadius(m_state.shadowBlur) : m_state.shadowBlur; @@ -929,8 +929,7 @@ void GraphicsContext::setPlatformShadow(const FloatSize& offset, float blur, con CGFloat smallEigenvalue = narrowPrecisionToCGFloat(sqrt(0.5 * ((A + D) - sqrt(4 * B * C + (A - D) * (A - D))))); - // Extreme "blur" values can make text drawing crash or take crazy long times, so clamp - blurRadius = min(blur * smallEigenvalue, narrowPrecisionToCGFloat(1000.0)); + blurRadius = blur * smallEigenvalue; CGSize offsetInBaseSpace = CGSizeApplyAffineTransform(offset, userToBaseCTM); @@ -938,6 +937,9 @@ void GraphicsContext::setPlatformShadow(const FloatSize& offset, float blur, con yOffset = offsetInBaseSpace.height; } + // Extreme "blur" values can make text drawing crash or take crazy long times, so clamp + blurRadius = min(blurRadius, narrowPrecisionToCGFloat(1000.0)); + // Work around <rdar://problem/5539388> by ensuring that the offsets will get truncated // to the desired integer. static const CGFloat extraShadowOffset = narrowPrecisionToCGFloat(1.0 / 128); @@ -1343,14 +1345,30 @@ void GraphicsContext::setAllowsFontSmoothing(bool allowsFontSmoothing) #endif } -void GraphicsContext::setIsCALayerContext(bool) +void GraphicsContext::setIsCALayerContext(bool isLayerContext) { - m_data->m_isCALayerContext = true; + if (isLayerContext) + m_data->m_contextFlags |= IsLayerCGContext; + else + m_data->m_contextFlags &= ~IsLayerCGContext; } bool GraphicsContext::isCALayerContext() const { - return m_data->m_isCALayerContext; + return m_data->m_contextFlags & IsLayerCGContext; +} + +void GraphicsContext::setIsAcceleratedContext(bool isAccelerated) +{ + if (isAccelerated) + m_data->m_contextFlags |= IsAcceleratedCGContext; + else + m_data->m_contextFlags &= ~IsAcceleratedCGContext; +} + +bool GraphicsContext::isAcceleratedContext() const +{ + return m_data->m_contextFlags & IsAcceleratedCGContext; } void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode) diff --git a/Source/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h b/Source/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h index f9255df..722f5a0 100644 --- a/Source/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h +++ b/Source/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h @@ -31,9 +31,16 @@ namespace WebCore { +enum GraphicsContextCGFlag { + IsLayerCGContext = 1 << 0, + IsAcceleratedCGContext = 1 << 1 +}; + +typedef unsigned GraphicsContextCGFlags; + class GraphicsContextPlatformPrivate { public: - GraphicsContextPlatformPrivate(CGContextRef cgContext, bool isLayerContext = false) + GraphicsContextPlatformPrivate(CGContextRef cgContext, GraphicsContextCGFlags flags = 0) : m_cgContext(cgContext) #if PLATFORM(WIN) , m_hdc(0) @@ -41,7 +48,7 @@ public: , m_shouldIncludeChildWindows(false) #endif , m_userToDeviceTransformKnownToBeIdentity(false) - , m_isCALayerContext(isLayerContext) + , m_contextFlags(flags) { } @@ -87,7 +94,7 @@ public: RetainPtr<CGContextRef> m_cgContext; bool m_userToDeviceTransformKnownToBeIdentity; - bool m_isCALayerContext; + GraphicsContextCGFlags m_contextFlags; }; } diff --git a/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp b/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp index 7c8e313..3c8f959 100644 --- a/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp +++ b/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp @@ -32,6 +32,7 @@ #include "BitmapImage.h" #include "GraphicsContext.h" #include "GraphicsContextCG.h" +#include "ImageData.h" #include "MIMETypeRegistry.h" #include <ApplicationServices/ApplicationServices.h> #include <wtf/Assertions.h> @@ -498,21 +499,8 @@ static RetainPtr<CFStringRef> utiFromMIMEType(const String& mimeType) #endif } -String ImageBuffer::toDataURL(const String& mimeType, const double* quality) const +static String CGImageToDataURL(CGImageRef image, const String& mimeType, const double* quality) { - ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType)); - - RetainPtr<CGImageRef> image; - if (!m_accelerateRendering) - image.adoptCF(CGBitmapContextCreateImage(context()->platformContext())); -#if USE(IOSURFACE_CANVAS_BACKING_STORE) - else - image.adoptCF(wkIOSurfaceContextCreateImage(context()->platformContext())); -#endif - - if (!image) - return "data:,"; - RetainPtr<CFMutableDataRef> data(AdoptCF, CFDataCreateMutable(kCFAllocatorDefault, 0)); if (!data) return "data:,"; @@ -533,7 +521,7 @@ String ImageBuffer::toDataURL(const String& mimeType, const double* quality) con imageProperties.adoptCF(CFDictionaryCreate(0, &key, &value, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); } - CGImageDestinationAddImage(destination.get(), image.get(), imageProperties.get()); + CGImageDestinationAddImage(destination.get(), image, imageProperties.get()); CGImageDestinationFinalize(destination.get()); Vector<char> out; @@ -541,4 +529,46 @@ String ImageBuffer::toDataURL(const String& mimeType, const double* quality) con return makeString("data:", mimeType, ";base64,", out); } + +String ImageBuffer::toDataURL(const String& mimeType, const double* quality) const +{ + ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType)); + + RetainPtr<CGImageRef> image; + if (!m_accelerateRendering) + image.adoptCF(CGBitmapContextCreateImage(context()->platformContext())); +#if USE(IOSURFACE_CANVAS_BACKING_STORE) + else + image.adoptCF(wkIOSurfaceContextCreateImage(context()->platformContext())); +#endif + + if (!image) + return "data:,"; + + return CGImageToDataURL(image.get(), mimeType, quality); +} + +String ImageDataToDataURL(const ImageData& source, const String& mimeType, const double* quality) +{ + ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType)); + + RetainPtr<CGImageRef> image; + RetainPtr<CGDataProviderRef> dataProvider; + + dataProvider.adoptCF(CGDataProviderCreateWithData(0, source.data()->data()->data(), + 4 * source.width() * source.height(), 0)); + + if (!dataProvider) + return "data:,"; + + image.adoptCF(CGImageCreate(source.width(), source.height(), 8, 32, 4 * source.width(), + CGColorSpaceCreateDeviceRGB(), kCGBitmapByteOrderDefault | kCGImageAlphaLast, + dataProvider.get(), 0, false, kCGRenderingIntentDefault)); + + + if (!image) + return "data:,"; + + return CGImageToDataURL(image.get(), mimeType, quality); +} } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/cg/PathCG.cpp b/Source/WebCore/platform/graphics/cg/PathCG.cpp index d6a1e6e..b8fc7d4 100644 --- a/Source/WebCore/platform/graphics/cg/PathCG.cpp +++ b/Source/WebCore/platform/graphics/cg/PathCG.cpp @@ -166,7 +166,7 @@ FloatRect Path::boundingRect() const return CGPathGetBoundingBox(m_path); } -FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) +FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) const { CGContextRef context = scratchContext(); diff --git a/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp index ad961aa..4cb119a 100644 --- a/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp @@ -56,7 +56,7 @@ Canvas2DLayerChromium::~Canvas2DLayerChromium() layerRendererContext()->deleteTexture(m_textureId); } -void Canvas2DLayerChromium::updateContentsIfDirty() +void Canvas2DLayerChromium::updateCompositorResources() { if (!m_contentsDirty || !m_drawingBuffer) return; diff --git a/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h b/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h index a14cb98..81b118c 100644 --- a/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h @@ -46,7 +46,7 @@ public: static PassRefPtr<Canvas2DLayerChromium> create(DrawingBuffer*, GraphicsLayerChromium* owner); virtual ~Canvas2DLayerChromium(); virtual bool drawsContent() const { return true; } - virtual void updateContentsIfDirty(); + virtual void updateCompositorResources(); void setTextureChanged(); unsigned textureId() const; @@ -55,8 +55,6 @@ public: private: explicit Canvas2DLayerChromium(DrawingBuffer*, GraphicsLayerChromium* owner); DrawingBuffer* m_drawingBuffer; - - static unsigned m_shaderProgramId; }; } diff --git a/Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.cpp index 0264868..f306207 100644 --- a/Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.cpp @@ -40,8 +40,6 @@ namespace WebCore { -unsigned CanvasLayerChromium::m_shaderProgramId = 0; - CanvasLayerChromium::CanvasLayerChromium(GraphicsLayerChromium* owner) : LayerChromium(owner) , m_textureChanged(true) @@ -54,22 +52,18 @@ CanvasLayerChromium::~CanvasLayerChromium() { } -void CanvasLayerChromium::draw() +PassRefPtr<CCLayerImpl> CanvasLayerChromium::createCCLayerImpl() { - ASSERT(layerRenderer()); - const CanvasLayerChromium::Program* program = layerRenderer()->canvasLayerProgram(); - ASSERT(program && program->initialized()); - GraphicsContext3D* context = layerRendererContext(); - GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); - GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textureId)); - GC3Denum sfactor = m_premultipliedAlpha ? GraphicsContext3D::ONE : GraphicsContext3D::SRC_ALPHA; - GLC(context, context->blendFunc(sfactor, GraphicsContext3D::ONE_MINUS_SRC_ALPHA)); - layerRenderer()->useShader(program->program()); - GLC(context, context->uniform1i(program->fragmentShader().samplerLocation(), 0)); - drawTexturedQuad(context, layerRenderer()->projectionMatrix(), ccLayerImpl()->drawTransform(), - bounds().width(), bounds().height(), ccLayerImpl()->drawOpacity(), - program->vertexShader().matrixLocation(), - program->fragmentShader().alphaLocation()); + return CCCanvasLayerImpl::create(this); +} + +void CanvasLayerChromium::pushPropertiesTo(CCLayerImpl* layer) +{ + LayerChromium::pushPropertiesTo(layer); + + CCCanvasLayerImpl* canvasLayer = static_cast<CCCanvasLayerImpl*>(layer); + canvasLayer->setTextureId(m_textureId); + canvasLayer->setPremultipliedAlpha(m_premultipliedAlpha); } } diff --git a/Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.h b/Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.h index ed3a06f..cb2ccc9 100644 --- a/Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.h @@ -43,9 +43,9 @@ class CanvasLayerChromium : public LayerChromium { public: virtual ~CanvasLayerChromium(); - virtual void draw(); + virtual PassRefPtr<CCLayerImpl> createCCLayerImpl(); - typedef ProgramBinding<VertexShaderPosTex, FragmentShaderRGBATexFlipAlpha> Program; + virtual void pushPropertiesTo(CCLayerImpl*); protected: explicit CanvasLayerChromium(GraphicsLayerChromium* owner); @@ -55,9 +55,6 @@ protected: bool m_textureChanged; unsigned m_textureId; bool m_premultipliedAlpha; - -private: - static unsigned m_shaderProgramId; }; } diff --git a/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp index 78f93d5..4ea9c92 100644 --- a/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp @@ -66,7 +66,7 @@ void ContentLayerChromium::cleanupResources() m_contentsTexture.clear(); } -bool ContentLayerChromium::requiresClippedUpdateRect() const +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 @@ -77,7 +77,7 @@ bool ContentLayerChromium::requiresClippedUpdateRect() const || !layerRenderer()->checkTextureSize(bounds())); } -void ContentLayerChromium::updateContentsIfDirty() +void ContentLayerChromium::paintContentsIfDirty() { RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_owner->client()); if (!backing || backing->paintingGoesToWindow()) @@ -93,34 +93,25 @@ void ContentLayerChromium::updateContentsIfDirty() // FIXME: Remove this test when tiled layers are implemented. if (requiresClippedUpdateRect()) { - // A layer with 3D transforms could require an arbitrarily large number - // of texels to be repainted, so ignore these layers until tiling is - // implemented. - if (!ccLayerImpl()->drawTransform().isIdentityOrTranslation()) { - m_skipsDraw = true; - return; - } - // 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); - // For now we apply the large layer treatment only for layers that are either untransformed - // or are purely translated. Their matrix is expected to be invertible. - ASSERT(layerOriginTransform.isInvertible()); - + // 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(); - IntRect visibleRectInLayerCoords = targetToLayerMatrix.mapRect(clipRect); + FloatQuad mappedClipToLayer = targetToLayerMatrix.projectQuad(FloatRect(clipRect)); + IntRect visibleRectInLayerCoords = mappedClipToLayer.enclosingBoundingBox(); visibleRectInLayerCoords.intersect(IntRect(0, 0, bounds().width(), bounds().height())); - // For normal layers, the center of the texture corresponds with the center of the layer. - // In large layers the center of the texture is the center of the visible region so we have - // to keep track of the offset in order to render correctly. - IntRect visibleRectInSurfaceCoords = layerOriginTransform.mapRect(visibleRectInLayerCoords); - m_layerCenterInSurfaceCoords = FloatRect(visibleRectInSurfaceCoords).center(); - // If this is still too large to render, then skip the layer completely. if (!layerRenderer()->checkTextureSize(visibleRectInLayerCoords.size())) { m_skipsDraw = true; @@ -256,9 +247,14 @@ void ContentLayerChromium::draw() GLC(context, context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA)); if (requiresClippedUpdateRect()) { - float m43 = ccLayerImpl()->drawTransform().m43(); - TransformationMatrix transform; - transform.translate3d(m_layerCenterInSurfaceCoords.x(), m_layerCenterInSurfaceCoords.y(), m43); + // 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(), @@ -273,6 +269,11 @@ void ContentLayerChromium::draw() unreserveContentsTexture(); } +void ContentLayerChromium::updateCompositorResources() +{ + updateTextureIfNeeded(); +} + void ContentLayerChromium::unreserveContentsTexture() { if (!m_skipsDraw && m_contentsTexture) @@ -281,8 +282,6 @@ void ContentLayerChromium::unreserveContentsTexture() void ContentLayerChromium::bindContentsTexture() { - updateTextureIfNeeded(); - if (!m_skipsDraw && m_contentsTexture) m_contentsTexture->bindTexture(); } diff --git a/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h index 6f070c2..cf296ab 100644 --- a/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h @@ -50,7 +50,8 @@ public: virtual ~ContentLayerChromium(); - virtual void updateContentsIfDirty(); + virtual void paintContentsIfDirty(); + virtual void updateCompositorResources(); virtual void unreserveContentsTexture(); virtual void bindContentsTexture(); @@ -63,7 +64,7 @@ protected: explicit ContentLayerChromium(GraphicsLayerChromium* owner); virtual void cleanupResources(); - bool requiresClippedUpdateRect() const; + bool requiresClippedUpdateRect(); void resizeUploadBuffer(const IntSize&); virtual const char* layerTypeAsString() const { return "ContentLayer"; } @@ -82,7 +83,6 @@ private: PlatformCanvas m_canvas; IntRect m_visibleRectInLayerCoords; - FloatPoint m_layerCenterInSurfaceCoords; }; } diff --git a/Source/WebCore/platform/graphics/chromium/CrossProcessFontLoading.mm b/Source/WebCore/platform/graphics/chromium/CrossProcessFontLoading.mm index 227fbe4..b442d53 100644 --- a/Source/WebCore/platform/graphics/chromium/CrossProcessFontLoading.mm +++ b/Source/WebCore/platform/graphics/chromium/CrossProcessFontLoading.mm @@ -29,7 +29,7 @@ #import "config.h" #import "CrossProcessFontLoading.h" -#import "../graphics/cocoa/FontPlatformData.h" +#import "../graphics/FontPlatformData.h" #import "PlatformBridge.h" #import <AppKit/NSFont.h> #import <wtf/HashMap.h> diff --git a/Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp b/Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp index d956841..e559edb 100644 --- a/Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp @@ -46,10 +46,6 @@ namespace WebCore { -#if ENABLE(SKIA_GPU) -extern GrContext* GetGlobalGrContext(); -#endif - struct DrawingBufferInternal { unsigned offscreenColorTexture; #if USE(ACCELERATED_COMPOSITING) @@ -91,6 +87,9 @@ DrawingBuffer::DrawingBuffer(GraphicsContext3D* context, , m_multisampleFBO(0) , m_multisampleColorBuffer(0) , m_internal(new DrawingBufferInternal) +#if ENABLE(SKIA_GPU) + , m_grContext(0) +#endif { if (!m_context->getExtensions()->supports("GL_CHROMIUM_copy_texture_to_parent_texture")) { m_context.clear(); @@ -137,7 +136,8 @@ void DrawingBuffer::publishToPlatformLayer() // would insert a fence into the child command stream that the compositor could wait for. m_context->makeContextCurrent(); #if ENABLE(SKIA_GPU) - GetGlobalGrContext()->flush(false); + if (m_grContext) + m_grContext->flush(0); #endif static_cast<Extensions3DChromium*>(m_context->getExtensions())->copyTextureToParentTextureCHROMIUM(m_colorBuffer, parentTexture); m_context->flush(); @@ -166,4 +166,13 @@ Platform3DObject DrawingBuffer::platformColorBuffer() const return m_colorBuffer; } +#if ENABLE(SKIA_GPU) +void DrawingBuffer::setGrContext(GrContext* context) +{ + // We just take a ptr without referencing it, as we require that we never outlive + // the SharedGraphicsContext3D object that is giving us the context. + m_grContext = context; +} +#endif + } diff --git a/Source/WebCore/platform/graphics/chromium/FontCacheLinux.cpp b/Source/WebCore/platform/graphics/chromium/FontCacheLinux.cpp index bbe6d62..598ae86 100644 --- a/Source/WebCore/platform/graphics/chromium/FontCacheLinux.cpp +++ b/Source/WebCore/platform/graphics/chromium/FontCacheLinux.cpp @@ -153,7 +153,8 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD fontDescription.computedSize(), (style & SkTypeface::kBold) && !tf->isBold(), (style & SkTypeface::kItalic) && !tf->isItalic(), - fontDescription.orientation()); + fontDescription.orientation(), + fontDescription.textOrientation()); tf->unref(); return result; } diff --git a/Source/WebCore/platform/graphics/chromium/FontChromiumWin.cpp b/Source/WebCore/platform/graphics/chromium/FontChromiumWin.cpp index e57a84c..3c254dc 100644 --- a/Source/WebCore/platform/graphics/chromium/FontChromiumWin.cpp +++ b/Source/WebCore/platform/graphics/chromium/FontChromiumWin.cpp @@ -196,7 +196,7 @@ class TransparencyAwareGlyphPainter : public TransparencyAwareFontPainter { // left of m_point. We express it this way so that if we're using the Skia // drawing path we can use floating-point positioning, even though we have // to use integer positioning in the GDI path. - bool drawGlyphs(int numGlyphs, const WORD* glyphs, const int* advances, int startAdvance) const; + bool drawGlyphs(int numGlyphs, const WORD* glyphs, const int* advances, float startAdvance) const; private: virtual IntRect estimateTextBounds(); @@ -256,11 +256,11 @@ IntRect TransparencyAwareGlyphPainter::estimateTextBounds() bool TransparencyAwareGlyphPainter::drawGlyphs(int numGlyphs, const WORD* glyphs, const int* advances, - int startAdvance) const + float startAdvance) const { if (!m_useGDI) { SkPoint origin = m_point; - origin.fX += startAdvance; + origin.fX += SkFloatToScalar(startAdvance); return paintSkiaText(m_graphicsContext, m_font->platformData().hfont(), numGlyphs, glyphs, advances, 0, &origin); } @@ -400,17 +400,25 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, Vector<WORD, kMaxBufferLength> glyphs; Vector<int, kMaxBufferLength> advances; int glyphIndex = 0; // The starting glyph of the current chunk. - int curAdvance = 0; // How far from the left the current chunk is. + + // In order to round all offsets to the correct pixel boundary, this code keeps track of the absolute position + // of each glyph in floating point units and rounds to integer advances at the last possible moment. + + float horizontalOffset = point.x(); // The floating point offset of the left side of the current glyph. + int lastHorizontalOffsetRounded = lroundf(horizontalOffset); // The rounded offset of the left side of the last glyph rendered. while (glyphIndex < numGlyphs) { // How many chars will be in this chunk? int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex); glyphs.resize(curLen); advances.resize(curLen); - int curWidth = 0; + float currentWidth = 0; for (int i = 0; i < curLen; ++i, ++glyphIndex) { glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex); - advances[i] = static_cast<int>(glyphBuffer.advanceAt(from + glyphIndex)); + horizontalOffset += glyphBuffer.advanceAt(from + glyphIndex); + advances[i] = lroundf(horizontalOffset) - lastHorizontalOffsetRounded; + lastHorizontalOffsetRounded += advances[i]; + currentWidth += glyphBuffer.advanceAt(from + glyphIndex); // Bug 26088 - very large positive or negative runs can fail to // render so we clamp the size here. In the specs, negative @@ -420,15 +428,14 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, // -32830, so we give ourselves a little breathing room. const int maxNegativeRun = -32768; const int maxPositiveRun = 32768; - if ((curWidth + advances[i] < maxNegativeRun) || (curWidth + advances[i] > maxPositiveRun)) + if ((currentWidth + advances[i] < maxNegativeRun) || (currentWidth + advances[i] > maxPositiveRun)) advances[i] = 0; - curWidth += advances[i]; } // Actually draw the glyphs (with retry on failure). bool success = false; for (int executions = 0; executions < 2; ++executions) { - success = painter.drawGlyphs(curLen, &glyphs[0], &advances[0], curAdvance); + success = painter.drawGlyphs(curLen, &glyphs[0], &advances[0], horizontalOffset - point.x() - currentWidth); if (!success && executions == 0) { // Ask the browser to load the font for us and retry. PlatformBridge::ensureFontLoaded(font->platformData().hfont()); @@ -439,8 +446,6 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, if (!success) LOG_ERROR("Unable to draw the glyphs after second attempt"); - - curAdvance += curWidth; } } @@ -509,8 +514,7 @@ void Font::drawComplexText(GraphicsContext* graphicsContext, // Uniscribe counts the coordinates from the upper left, while WebKit uses // the baseline, so we have to subtract off the ascent. - state.draw(graphicsContext, hdc, static_cast<int>(point.x()), - static_cast<int>(point.y() - fontMetrics().ascent()), from, to); + state.draw(graphicsContext, hdc, lroundf(point.x()), lroundf(point.y() - fontMetrics().ascent()), from, to); context->canvas()->endPlatformPaint(); } diff --git a/Source/WebCore/platform/graphics/chromium/FontLinux.cpp b/Source/WebCore/platform/graphics/chromium/FontLinux.cpp index 823dbc9..3c4a494 100644 --- a/Source/WebCore/platform/graphics/chromium/FontLinux.cpp +++ b/Source/WebCore/platform/graphics/chromium/FontLinux.cpp @@ -98,7 +98,7 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, SkPoint* vPosBegin = storage2.get(); SkPoint* vPosEnd = storage3.get(); - bool isVertical = font->orientation() == Vertical; + bool isVertical = font->platformData().orientation() == Vertical; for (int i = 0; i < numGlyphs; i++) { SkScalar myWidth = SkFloatToScalar(adv[i].width()); pos[i].set(x, y); diff --git a/Source/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h b/Source/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h index b6ebb2e..84edebc 100644 --- a/Source/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h +++ b/Source/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h @@ -71,6 +71,7 @@ public: float size() const { return m_size; } FontOrientation orientation() const { return Horizontal; } // FIXME: Implement. + void setOrientation(FontOrientation) { } // FIXME: Implement. unsigned hash() const { @@ -105,7 +106,7 @@ private: HFONT hfont() const { return m_hfont; } unsigned hash() const { - return WTF::StringHasher::createBlobHash<sizeof(HFONT)>(&m_hfont); + return StringHasher::hashMemory<sizeof(HFONT)>(&m_hfont); } bool operator==(const RefCountedHFONT& other) const diff --git a/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp b/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp index 6f9009f..c3edfac 100644 --- a/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp +++ b/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp @@ -76,13 +76,14 @@ FontPlatformData::FontPlatformData(const FontPlatformData& src) , m_fakeBold(src.m_fakeBold) , m_fakeItalic(src.m_fakeItalic) , m_orientation(src.m_orientation) + , m_textOrientation(src.m_textOrientation) , m_style(src.m_style) , m_harfbuzzFace(src.m_harfbuzzFace) { SkSafeRef(m_typeface); } -FontPlatformData::FontPlatformData(SkTypeface* tf, const char* family, float textSize, bool fakeBold, bool fakeItalic, FontOrientation orientation) +FontPlatformData::FontPlatformData(SkTypeface* tf, const char* family, float textSize, bool fakeBold, bool fakeItalic, FontOrientation orientation, TextOrientation textOrientation) : m_typeface(tf) , m_family(family) , m_textSize(textSize) @@ -90,6 +91,7 @@ FontPlatformData::FontPlatformData(SkTypeface* tf, const char* family, float tex , m_fakeBold(fakeBold) , m_fakeItalic(fakeItalic) , m_orientation(orientation) + , m_textOrientation(textOrientation) { SkSafeRef(m_typeface); querySystemForRenderStyle(); @@ -102,6 +104,8 @@ FontPlatformData::FontPlatformData(const FontPlatformData& src, float textSize) , m_emSizeInFontUnits(src.m_emSizeInFontUnits) , m_fakeBold(src.m_fakeBold) , m_fakeItalic(src.m_fakeItalic) + , m_orientation(src.m_orientation) + , m_textOrientation(src.m_textOrientation) , m_harfbuzzFace(src.m_harfbuzzFace) { SkSafeRef(m_typeface); @@ -134,6 +138,7 @@ FontPlatformData& FontPlatformData::operator=(const FontPlatformData& src) m_fakeItalic = src.m_fakeItalic; m_harfbuzzFace = src.m_harfbuzzFace; m_orientation = src.m_orientation; + m_textOrientation = src.m_textOrientation; m_style = src.m_style; m_emSizeInFontUnits = src.m_emSizeInFontUnits; @@ -199,13 +204,14 @@ bool FontPlatformData::operator==(const FontPlatformData& a) const && m_fakeBold == a.m_fakeBold && m_fakeItalic == a.m_fakeItalic && m_orientation == a.m_orientation + && m_textOrientation == a.m_textOrientation && m_style == a.m_style; } unsigned FontPlatformData::hash() const { unsigned h = SkTypeface::UniqueID(m_typeface); - h ^= 0x01010101 * ((static_cast<int>(m_orientation) << 2) | (static_cast<int>(m_fakeBold) << 1) | static_cast<int>(m_fakeItalic)); + h ^= 0x01010101 * ((static_cast<int>(m_textOrientation) << 3) | (static_cast<int>(m_orientation) << 2) | (static_cast<int>(m_fakeBold) << 1) | static_cast<int>(m_fakeItalic)); // This memcpy is to avoid a reinterpret_cast that breaks strict-aliasing // rules. Memcpy is generally optimized enough so that performance doesn't diff --git a/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h b/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h index d9ebb61..541aa86 100644 --- a/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h +++ b/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h @@ -33,6 +33,7 @@ #include "FontOrientation.h" #include "FontRenderStyle.h" +#include "TextOrientation.h" #include <wtf/Forward.h> #include <wtf/RefPtr.h> #include <wtf/text/CString.h> @@ -66,6 +67,8 @@ public: , m_emSizeInFontUnits(0) , m_fakeBold(false) , m_fakeItalic(false) + , m_orientation(Horizontal) + , m_textOrientation(TextOrientationVerticalRight) { } FontPlatformData() @@ -75,6 +78,7 @@ public: , m_fakeBold(false) , m_fakeItalic(false) , m_orientation(Horizontal) + , m_textOrientation(TextOrientationVerticalRight) { } FontPlatformData(float textSize, bool fakeBold, bool fakeItalic) @@ -84,10 +88,11 @@ public: , m_fakeBold(fakeBold) , m_fakeItalic(fakeItalic) , m_orientation(Horizontal) + , m_textOrientation(TextOrientationVerticalRight) { } FontPlatformData(const FontPlatformData&); - FontPlatformData(SkTypeface*, const char* name, float textSize, bool fakeBold, bool fakeItalic, FontOrientation orientation = Horizontal); + FontPlatformData(SkTypeface*, const char* name, float textSize, bool fakeBold, bool fakeItalic, FontOrientation = Horizontal, TextOrientation = TextOrientationVerticalRight); FontPlatformData(const FontPlatformData& src, float textSize); ~FontPlatformData(); @@ -113,7 +118,8 @@ public: int emSizeInFontUnits() const; FontOrientation orientation() const { return m_orientation; } - + void setOrientation(FontOrientation orientation) { m_orientation = orientation; } + bool operator==(const FontPlatformData&) const; FontPlatformData& operator=(const FontPlatformData&); bool isHashTableDeletedValue() const { return m_typeface == hashTableDeletedFontValue(); } @@ -161,6 +167,7 @@ private: bool m_fakeBold; bool m_fakeItalic; FontOrientation m_orientation; + TextOrientation m_textOrientation; FontRenderStyle m_style; mutable RefPtr<RefCountedHarfbuzzFace> m_harfbuzzFace; diff --git a/Source/WebCore/platform/graphics/chromium/GLES2Canvas.cpp b/Source/WebCore/platform/graphics/chromium/GLES2Canvas.cpp index 2ff6b8b..cc5a060 100644 --- a/Source/WebCore/platform/graphics/chromium/GLES2Canvas.cpp +++ b/Source/WebCore/platform/graphics/chromium/GLES2Canvas.cpp @@ -62,29 +62,51 @@ typedef void (GLAPIENTRY *TESSCB)(); typedef WTF::Vector<float> FloatVector; typedef WTF::Vector<double> DoubleVector; +struct PathAndTransform { + PathAndTransform(const Path& p, const AffineTransform& t) + : path(p) + , transform(t) + { + } + Path path; + AffineTransform transform; +}; + struct GLES2Canvas::State { State() : m_fillColor(0, 0, 0, 255) + , m_shadowColor(0, 0, 0, 0) , m_alpha(1.0f) , m_compositeOp(CompositeSourceOver) - , m_clippingEnabled(false) + , m_numClippingPaths(0) + , m_shadowOffset(0, 0) + , m_shadowBlur(0) + , m_shadowsIgnoreTransforms(false) { } State(const State& other) : m_fillColor(other.m_fillColor) + , m_shadowColor(other.m_shadowColor) , m_alpha(other.m_alpha) , m_compositeOp(other.m_compositeOp) , m_ctm(other.m_ctm) , m_clippingPaths() // Don't copy; clipping paths are tracked per-state. - , m_clippingEnabled(other.m_clippingEnabled) + , m_numClippingPaths(other.m_numClippingPaths) + , m_shadowOffset(other.m_shadowOffset) + , m_shadowBlur(other.m_shadowBlur) + , m_shadowsIgnoreTransforms(other.m_shadowsIgnoreTransforms) { } Color m_fillColor; + Color m_shadowColor; float m_alpha; CompositeOperator m_compositeOp; AffineTransform m_ctm; - WTF::Vector<Path> m_clippingPaths; - bool m_clippingEnabled; + WTF::Vector<PathAndTransform> m_clippingPaths; + int m_numClippingPaths; + FloatSize m_shadowOffset; + float m_shadowBlur; + bool m_shadowsIgnoreTransforms; // Helper function for applying the state's alpha value to the given input // color to produce a new output color. The logic is the same as @@ -100,7 +122,11 @@ struct GLES2Canvas::State { int a = (c.alpha() * s) >> 8; return Color(c.red(), c.green(), c.blue(), a); } - + bool shadowActive() const + { + return m_shadowColor.alpha() > 0 && (m_shadowBlur || m_shadowOffset.width() || m_shadowOffset.height()); + } + bool clippingEnabled() { return m_numClippingPaths > 0; } }; static inline FloatPoint operator*(const FloatPoint& f, float scale) @@ -193,12 +219,8 @@ void GLES2Canvas::bindFramebuffer() void GLES2Canvas::clearRect(const FloatRect& rect) { bindFramebuffer(); - if (m_state->m_ctm.isIdentity() && !m_state->m_clippingEnabled) { - m_context->scissor(rect.x(), m_size.height() - rect.height() - rect.y(), rect.width(), rect.height()); - m_context->enable(GraphicsContext3D::SCISSOR_TEST); - m_context->clearColor(Color(RGBA32(0))); - m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT); - m_context->disable(GraphicsContext3D::SCISSOR_TEST); + if (m_state->m_ctm.isIdentity() && !m_state->clippingEnabled()) { + scissorClear(rect.x(), rect.y(), rect.width(), rect.height()); } else { save(); setCompositeOperation(CompositeClear); @@ -207,35 +229,66 @@ void GLES2Canvas::clearRect(const FloatRect& rect) } } +void GLES2Canvas::scissorClear(float x, float y, float width, float height) +{ + int intX = static_cast<int>(x + 0.5f); + int intY = static_cast<int>(y + 0.5f); + int intWidth = static_cast<int>(x + width + 0.5f) - intX; + int intHeight = static_cast<int>(y + height + 0.5f) - intY; + m_context->scissor(intX, m_size.height() - intHeight - intY, intWidth, intHeight); + m_context->enable(GraphicsContext3D::SCISSOR_TEST); + m_context->clearColor(Color(RGBA32(0))); + m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT); + m_context->disable(GraphicsContext3D::SCISSOR_TEST); +} + void GLES2Canvas::fillPath(const Path& path) { + if (m_state->shadowActive()) { + beginShadowDraw(); + fillPathInternal(path, m_state->m_shadowColor); + endShadowDraw(path.boundingRect()); + } + + bindFramebuffer(); m_context->applyCompositeOperator(m_state->m_compositeOp); - applyClipping(m_state->m_clippingEnabled); - fillPath(path, m_state->applyAlpha(m_state->m_fillColor)); + applyClipping(m_state->clippingEnabled()); + + fillPathInternal(path, m_state->applyAlpha(m_state->m_fillColor)); } void GLES2Canvas::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) { + if (m_state->shadowActive()) { + beginShadowDraw(); + fillRectInternal(rect, m_state->m_shadowColor); + endShadowDraw(rect); + } + + bindFramebuffer(); m_context->applyCompositeOperator(m_state->m_compositeOp); - applyClipping(m_state->m_clippingEnabled); - m_context->useQuadVertices(); + applyClipping(m_state->clippingEnabled()); + + fillRectInternal(rect, color); +} + +void GLES2Canvas::fillRect(const FloatRect& rect) +{ + fillRect(rect, m_state->applyAlpha(m_state->m_fillColor), ColorSpaceDeviceRGB); +} +void GLES2Canvas::fillRectInternal(const FloatRect& rect, const Color& color) +{ AffineTransform matrix(m_flipMatrix); matrix *= m_state->m_ctm; matrix.translate(rect.x(), rect.y()); matrix.scale(rect.width(), rect.height()); + m_context->useQuadVertices(); m_context->useFillSolidProgram(matrix, color); - - bindFramebuffer(); m_context->drawArrays(GraphicsContext3D::TRIANGLE_STRIP, 0, 4); } -void GLES2Canvas::fillRect(const FloatRect& rect) -{ - fillRect(rect, m_state->applyAlpha(m_state->m_fillColor), ColorSpaceDeviceRGB); -} - void GLES2Canvas::setFillColor(const Color& color, ColorSpace colorSpace) { m_state->m_fillColor = color; @@ -246,6 +299,26 @@ void GLES2Canvas::setAlpha(float alpha) m_state->m_alpha = alpha; } +void GLES2Canvas::setShadowColor(const Color& color, ColorSpace) +{ + m_state->m_shadowColor = color; +} + +void GLES2Canvas::setShadowOffset(const FloatSize& offset) +{ + m_state->m_shadowOffset = offset; +} + +void GLES2Canvas::setShadowBlur(float shadowBlur) +{ + m_state->m_shadowBlur = shadowBlur; +} + +void GLES2Canvas::setShadowsIgnoreTransforms(bool shadowsIgnoreTransforms) +{ + m_state->m_shadowsIgnoreTransforms = shadowsIgnoreTransforms; +} + void GLES2Canvas::translate(float x, float y) { m_state->m_ctm.translate(x, y); @@ -275,12 +348,12 @@ void GLES2Canvas::clipPath(const Path& path) { bindFramebuffer(); checkGLError("bindFramebuffer"); - beginStencilDraw(); + beginStencilDraw(GraphicsContext3D::INCR); // Red is used so we can see it if it ends up in the color buffer. Color red(255, 0, 0, 255); - fillPath(path, red); - m_state->m_clippingPaths.append(path); - m_state->m_clippingEnabled = true; + fillPathInternal(path, red); + m_state->m_clippingPaths.append(PathAndTransform(path, m_state->m_ctm)); + m_state->m_numClippingPaths++; } void GLES2Canvas::clipOut(const Path& path) @@ -297,53 +370,48 @@ void GLES2Canvas::save() void GLES2Canvas::restore() { ASSERT(!m_stateStack.isEmpty()); - bool hadClippingPaths = !m_state->m_clippingPaths.isEmpty(); - m_stateStack.removeLast(); - m_state = &m_stateStack.last(); - if (hadClippingPaths) { - m_context->clear(GraphicsContext3D::STENCIL_BUFFER_BIT); - beginStencilDraw(); - StateVector::const_iterator iter; - for (iter = m_stateStack.begin(); iter < m_stateStack.end(); ++iter) { - const State& state = *iter; - const Vector<Path>& clippingPaths = state.m_clippingPaths; - Vector<Path>::const_iterator pathIter; - for (pathIter = clippingPaths.begin(); pathIter < clippingPaths.end(); ++pathIter) { - // Red is used so we can see it if it ends up in the color buffer. - Color red(255, 0, 0, 255); - fillPath(*pathIter, red); - } + const Vector<PathAndTransform>& clippingPaths = m_state->m_clippingPaths; + if (!clippingPaths.isEmpty()) { + beginStencilDraw(GraphicsContext3D::DECR); + WTF::Vector<PathAndTransform>::const_iterator pathIter; + for (pathIter = clippingPaths.begin(); pathIter < clippingPaths.end(); ++pathIter) { + m_state->m_ctm = pathIter->transform; + // Red is used so we can see it if it ends up in the color buffer. + Color red(255, 0, 0, 255); + fillPathInternal(pathIter->path, red); } } + m_stateStack.removeLast(); + m_state = &m_stateStack.last(); } void GLES2Canvas::drawTexturedRect(unsigned texture, const IntSize& textureSize, const FloatRect& srcRect, const FloatRect& dstRect, ColorSpace colorSpace, CompositeOperator compositeOp) { + bindFramebuffer(); m_context->applyCompositeOperator(compositeOp); applyClipping(false); - m_context->useQuadVertices(); m_context->setActiveTexture(GraphicsContext3D::TEXTURE0); m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, texture); - drawQuad(textureSize, srcRect, dstRect, m_state->m_ctm, m_state->m_alpha); + drawTexturedQuad(textureSize, srcRect, dstRect, m_state->m_ctm, m_state->m_alpha); } void GLES2Canvas::drawTexturedRect(Texture* texture, const FloatRect& srcRect, const FloatRect& dstRect, ColorSpace colorSpace, CompositeOperator compositeOp) { - drawTexturedRect(texture, srcRect, dstRect, m_state->m_ctm, m_state->m_alpha, colorSpace, compositeOp, m_state->m_clippingEnabled); + drawTexturedRect(texture, srcRect, dstRect, m_state->m_ctm, m_state->m_alpha, colorSpace, compositeOp, m_state->clippingEnabled()); } void GLES2Canvas::drawTexturedRect(Texture* texture, const FloatRect& srcRect, const FloatRect& dstRect, const AffineTransform& transform, float alpha, ColorSpace colorSpace, CompositeOperator compositeOp, bool clip) { + bindFramebuffer(); m_context->applyCompositeOperator(compositeOp); applyClipping(clip); const TilingData& tiles = texture->tiles(); IntRect tileIdxRect = tiles.overlappedTileIndices(srcRect); - m_context->useQuadVertices(); m_context->setActiveTexture(GraphicsContext3D::TEXTURE0); for (int y = tileIdxRect.y(); y <= tileIdxRect.maxY(); y++) { @@ -367,13 +435,18 @@ void GLES2Canvas::drawTexturedRectTile(Texture* texture, int tile, const FloatRe IntRect tileBoundsWithBorder = tiles.tileBoundsWithBorder(tile); - drawQuad(tileBoundsWithBorder.size(), srcRectClippedInTileSpace, dstRectIntersected, transform, alpha); + drawTexturedQuad(tileBoundsWithBorder.size(), srcRectClippedInTileSpace, dstRectIntersected, transform, alpha); } -void GLES2Canvas::drawQuad(const IntSize& textureSize, const FloatRect& srcRect, const FloatRect& dstRect, const AffineTransform& transform, float alpha) +void GLES2Canvas::convolveRect(unsigned texture, const IntSize& textureSize, const FloatRect& srcRect, const FloatRect& dstRect, float imageIncrement[2], const float* kernel, int kernelWidth) { + m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, texture); + m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE); + m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE); + m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST); + m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::NEAREST); + AffineTransform matrix(m_flipMatrix); - matrix *= transform; matrix.translate(dstRect.x(), dstRect.y()); matrix.scale(dstRect.width(), dstRect.height()); @@ -382,13 +455,79 @@ void GLES2Canvas::drawQuad(const IntSize& textureSize, const FloatRect& srcRect, texMatrix.translate(srcRect.x(), srcRect.y()); texMatrix.scale(srcRect.width(), srcRect.height()); - bindFramebuffer(); + m_context->useQuadVertices(); + m_context->useConvolutionProgram(matrix, texMatrix, kernel, kernelWidth, imageIncrement); + m_context->drawArrays(GraphicsContext3D::TRIANGLE_STRIP, 0, 4); + checkGLError("glDrawArrays"); +} +static float gauss(float x, float sigma) +{ + return exp(- (x * x) / (2.0f * sigma * sigma)); +} + +static void buildKernel(float sigma, float* kernel, int kernelWidth) +{ + float halfWidth = (kernelWidth - 1.0f) / 2.0f; + float sum = 0.0f; + for (int i = 0; i < kernelWidth; ++i) { + kernel[i] = gauss(i - halfWidth, sigma); + sum += kernel[i]; + } + // Normalize the kernel + float scale = 1.0f / sum; + for (int i = 0; i < kernelWidth; ++i) + kernel[i] *= scale; +} + +void GLES2Canvas::drawTexturedQuad(const IntSize& textureSize, const FloatRect& srcRect, const FloatRect& dstRect, const AffineTransform& transform, float alpha) +{ + AffineTransform matrix(m_flipMatrix); + matrix *= transform; + matrix.translate(dstRect.x(), dstRect.y()); + matrix.scale(dstRect.width(), dstRect.height()); + + AffineTransform texMatrix; + texMatrix.scale(1.0f / textureSize.width(), 1.0f / textureSize.height()); + texMatrix.translate(srcRect.x(), srcRect.y()); + texMatrix.scale(srcRect.width(), srcRect.height()); + + m_context->useQuadVertices(); m_context->useTextureProgram(matrix, texMatrix, alpha); m_context->drawArrays(GraphicsContext3D::TRIANGLE_STRIP, 0, 4); checkGLError("glDrawArrays"); } +void GLES2Canvas::drawTexturedQuadMitchell(const IntSize& textureSize, const FloatRect& srcRect, const FloatRect& dstRect, const AffineTransform& transform, float alpha) +{ + static const float mitchellCoefficients[16] = { + 0.0f / 18.0f, 1.0f / 18.0f, 16.0f / 18.0f, 1.0f / 18.0f, + 0.0f / 18.0f, 9.0f / 18.0f, 0.0f / 18.0f, -9.0f / 18.0f, + -6.0f / 18.0f, 27.0f / 18.0f, -36.0f / 18.0f, 15.0f / 18.0f, + 7.0f / 18.0f, -21.0f / 18.0f, 21.0f / 18.0f, -7.0f / 18.0f, + }; + + AffineTransform matrix(m_flipMatrix); + matrix *= transform; + matrix.translate(dstRect.x(), dstRect.y()); + matrix.scale(dstRect.width(), dstRect.height()); + + float imageIncrement[2] = { 1.0f / textureSize.width(), 1.0f / textureSize.height() }; + + AffineTransform texMatrix; + texMatrix.scale(imageIncrement[0], imageIncrement[1]); + texMatrix.translate(srcRect.x(), srcRect.y()); + texMatrix.scale(srcRect.width(), srcRect.height()); + + m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST); + m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::NEAREST); + + m_context->useQuadVertices(); + m_context->useBicubicProgram(matrix, texMatrix, mitchellCoefficients, imageIncrement, alpha); + m_context->drawArrays(GraphicsContext3D::TRIANGLE_STRIP, 0, 4); + checkGLError("glDrawArrays"); +} + void GLES2Canvas::setCompositeOperation(CompositeOperator op) { m_state->m_compositeOp = op; @@ -554,12 +693,9 @@ void GLES2Canvas::createVertexBufferFromPath(const Path& path, int* count, unsig *count = indices.size(); } -void GLES2Canvas::fillPath(const Path& path, const Color& color) +void GLES2Canvas::fillPathInternal(const Path& path, const Color& color) { if (SharedGraphicsContext3D::useLoopBlinnForPathRendering()) { - bindFramebuffer(); - m_context->applyCompositeOperator(m_state->m_compositeOp); - m_pathCache.clear(); LoopBlinnPathProcessor processor; processor.process(path, m_pathCache); @@ -590,18 +726,18 @@ void GLES2Canvas::fillPath(const Path& path, const Color& color) 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"); - AffineTransform matrix(m_flipMatrix); - matrix *= m_state->m_ctm; - m_context->useFillSolidProgram(matrix, color); checkGLError("useFillSolidProgram"); - bindFramebuffer(); m_context->graphicsContext3D()->drawElements(GraphicsContext3D::TRIANGLES, count, GraphicsContext3D::UNSIGNED_SHORT, 0); checkGLError("drawArrays"); @@ -613,7 +749,141 @@ void GLES2Canvas::fillPath(const Path& path, const Color& color) } } -void GLES2Canvas::beginStencilDraw() +FloatRect GLES2Canvas::flipRect(const FloatRect& rect) +{ + FloatRect flippedRect(rect); + flippedRect.setY(m_size.height() - rect.y()); + flippedRect.setHeight(-rect.height()); + return flippedRect; +} + +void GLES2Canvas::clearBorders(const FloatRect& rect, int width) +{ + scissorClear(rect.x(), rect.y() - width, rect.width() + width, width); + scissorClear(rect.maxX(), rect.y(), width, rect.height() + width); + scissorClear(rect.x() - width, rect.maxY(), rect.width() + width, width); + scissorClear(rect.x() - width, rect.y() - width, width, rect.height() + width); +} + +void GLES2Canvas::beginShadowDraw() +{ + float offsetX = m_state->m_shadowOffset.width(); + float offsetY = m_state->m_shadowOffset.height(); + save(); + if (m_state->m_shadowsIgnoreTransforms) { + AffineTransform newCTM; + newCTM.translate(offsetX, -offsetY); + newCTM *= m_state->m_ctm; + m_state->m_ctm = newCTM; + } else + m_state->m_ctm.translate(offsetX, offsetY); + + if (m_state->m_shadowBlur > 0) { + // Draw hard shadow to offscreen buffer 0. + DrawingBuffer* dstBuffer = m_context->getOffscreenBuffer(0, m_size); + dstBuffer->bind(); + m_context->applyCompositeOperator(CompositeCopy); + applyClipping(false); + 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()); + } +} + +void GLES2Canvas::endShadowDraw(const FloatRect& boundingBox) +{ + if (m_state->m_shadowBlur > 0) { + // Buffer 0 contains the primitive drawn with a hard shadow. + DrawingBuffer* srcBuffer = m_context->getOffscreenBuffer(0, m_size); + DrawingBuffer* dstBuffer = m_context->getOffscreenBuffer(1, m_size); + + float sigma = m_state->m_shadowBlur * 0.333333f; + FloatRect shadowBoundingBox(m_state->m_ctm.mapRect(boundingBox)); + FloatRect rect(FloatPoint(0, 0), m_size); + FloatRect srcRect(shadowBoundingBox); + + int scaleFactor = 1; + while (sigma > cMaxSigma) { + srcRect.scale(0.5f); + scaleFactor *= 2; + sigma *= 0.5f; + } + srcRect = enclosingIntRect(srcRect); + srcRect.scale(scaleFactor); + for (int i = 1; i < scaleFactor; i *= 2) { + dstBuffer->bind(); + m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, srcBuffer->colorBuffer()); + m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE); + m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE); + m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR); + m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR); + FloatRect dstRect(srcRect); + dstRect.scale(0.5f); + // Clear out 1 pixel border for linear filtering. + clearBorders(dstRect, 1); + drawTexturedQuad(srcBuffer->size(), flipRect(srcRect), dstRect, AffineTransform(), 1.0); + srcRect = dstRect; + std::swap(srcBuffer, dstBuffer); + } + + int halfWidth = static_cast<int>(sigma * 3.0f); + int kernelWidth = halfWidth * 2 + 1; + OwnArrayPtr<float> kernel = adoptArrayPtr(new float[kernelWidth]); + buildKernel(sigma, kernel.get(), kernelWidth); + + if (scaleFactor > 1) { + scissorClear(srcRect.maxX(), srcRect.y(), kernelWidth, srcRect.height()); + scissorClear(srcRect.x() - kernelWidth, srcRect.y(), kernelWidth, srcRect.height()); + } + + // Blur in X offscreen. + dstBuffer->bind(); + srcRect.inflateX(halfWidth); + srcRect.intersect(rect); + float imageIncrementX[2] = {1.0f / srcBuffer->size().width(), 0.0f}; + convolveRect(srcBuffer->colorBuffer(), srcBuffer->size(), flipRect(srcRect), srcRect, imageIncrementX, kernel.get(), kernelWidth); + + if (scaleFactor > 1) { + scissorClear(srcRect.x(), srcRect.maxY(), srcRect.width(), kernelWidth); + scissorClear(srcRect.x(), srcRect.y() - kernelWidth, srcRect.width(), kernelWidth); + } + srcRect.inflateY(halfWidth); + srcRect.intersect(rect); + std::swap(srcBuffer, dstBuffer); + + float imageIncrementY[2] = {0.0f, 1.0f / srcBuffer->size().height()}; + if (scaleFactor > 1) { + // Blur in Y offscreen. + dstBuffer->bind(); + convolveRect(srcBuffer->colorBuffer(), srcBuffer->size(), flipRect(srcRect), srcRect, imageIncrementY, kernel.get(), kernelWidth); + // Clear out 2 pixel border for bicubic filtering. + clearBorders(srcRect, 2); + std::swap(srcBuffer, dstBuffer); + + // Upsample srcBuffer -> main framebuffer using bicubic filtering. + bindFramebuffer(); + m_context->applyCompositeOperator(m_state->m_compositeOp); + applyClipping(m_state->clippingEnabled()); + 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()); + + convolveRect(srcBuffer->colorBuffer(), srcBuffer->size(), flipRect(srcRect), srcRect, imageIncrementY, kernel.get(), kernelWidth); + } + } + restore(); +} + +void GLES2Canvas::beginStencilDraw(unsigned op) { // Turn on stencil test. m_context->enableStencil(true); @@ -624,9 +894,7 @@ void GLES2Canvas::beginStencilDraw() checkGLError("stencilFunc"); // All writes incremement the stencil buffer. - m_context->graphicsContext3D()->stencilOp(GraphicsContext3D::INCR, - GraphicsContext3D::INCR, - GraphicsContext3D::INCR); + m_context->graphicsContext3D()->stencilOp(op, op, op); checkGLError("stencilOp"); } @@ -635,7 +903,7 @@ void GLES2Canvas::applyClipping(bool enable) m_context->enableStencil(enable); if (enable) { // Enable drawing only where stencil is non-zero. - m_context->graphicsContext3D()->stencilFunc(GraphicsContext3D::EQUAL, m_state->m_clippingPaths.size() % 256, 1); + m_context->graphicsContext3D()->stencilFunc(GraphicsContext3D::EQUAL, m_state->m_numClippingPaths, -1); checkGLError("stencilFunc"); // Keep all stencil values the same. m_context->graphicsContext3D()->stencilOp(GraphicsContext3D::KEEP, diff --git a/Source/WebCore/platform/graphics/chromium/GLES2Canvas.h b/Source/WebCore/platform/graphics/chromium/GLES2Canvas.h index 8887a16..f6a8bcf 100644 --- a/Source/WebCore/platform/graphics/chromium/GLES2Canvas.h +++ b/Source/WebCore/platform/graphics/chromium/GLES2Canvas.h @@ -64,6 +64,10 @@ public: void clearRect(const FloatRect&); void setFillColor(const Color&, ColorSpace); void setAlpha(float alpha); + void setShadowColor(const Color&, ColorSpace); + void setShadowOffset(const FloatSize&); + void setShadowBlur(float); + void setShadowsIgnoreTransforms(bool); void setCompositeOperation(CompositeOperator); void translate(float x, float y); void rotate(float angleInRadians); @@ -96,12 +100,21 @@ public: DrawingBuffer* drawingBuffer() const { return m_drawingBuffer; } private: + 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 drawQuad(const IntSize& textureSize, 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 fillPath(const Path&, const Color&); - void beginStencilDraw(); + void fillPathInternal(const Path&, const Color&); + void fillRectInternal(const FloatRect&, const Color&); + FloatRect flipRect(const FloatRect&); + void clearBorders(const FloatRect&, int width); + void beginShadowDraw(); + void endShadowDraw(const FloatRect& boundingBox); + void beginStencilDraw(unsigned op); void applyClipping(bool enable); void checkGLError(const char* header); diff --git a/Source/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp b/Source/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp index ee2b5ab..cfc1754 100644 --- a/Source/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp +++ b/Source/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp @@ -36,8 +36,8 @@ #include "GlyphPageTreeNode.h" #include "PlatformBridge.h" #include "SimpleFontData.h" +#include "SystemInfo.h" #include "UniscribeHelperTextRun.h" -#include "WindowsVersion.h" namespace WebCore { @@ -134,7 +134,7 @@ static bool fillBMPGlyphs(unsigned offset, bool haveGlyphs = false; int invalidGlyph = 0xFFFF; const DWORD cffTableTag = 0x20464643; // 4-byte identifier for OpenType CFF table ('CFF '). - if (!isVistaOrNewer() && !(tm.tmPitchAndFamily & TMPF_TRUETYPE) && (GetFontData(dc, cffTableTag, 0, 0, 0) == GDI_ERROR)) + if ((windowsVersion() < WindowsVista) && !(tm.tmPitchAndFamily & TMPF_TRUETYPE) && (GetFontData(dc, cffTableTag, 0, 0, 0) == GDI_ERROR)) invalidGlyph = 0x1F; Glyph spaceGlyph = 0; // Glyph for a space. Lazily filled. diff --git a/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp index 7c42366..60c1332 100644 --- a/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp @@ -60,7 +60,7 @@ void ImageLayerChromium::setContents(Image* contents) setNeedsDisplay(); } -void ImageLayerChromium::updateContentsIfDirty() +void ImageLayerChromium::paintContentsIfDirty() { ASSERT(layerRenderer()); @@ -68,7 +68,7 @@ void ImageLayerChromium::updateContentsIfDirty() 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::updateContentsIfDirty(); + ContentLayerChromium::paintContentsIfDirty(); return; } diff --git a/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.h b/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.h index cc9064d..6addabc 100644 --- a/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.h @@ -50,7 +50,7 @@ class ImageLayerChromium : public ContentLayerChromium { public: static PassRefPtr<ImageLayerChromium> create(GraphicsLayerChromium* owner = 0); - virtual void updateContentsIfDirty(); + virtual void paintContentsIfDirty(); virtual bool drawsContent() const { return m_contents; } void setContents(Image* image); diff --git a/Source/WebCore/platform/graphics/chromium/LayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/LayerChromium.cpp index 95b7386..bc28239 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/LayerChromium.cpp @@ -62,6 +62,7 @@ LayerChromium::LayerChromium(GraphicsLayerChromium* owner) : m_owner(owner) , m_contentsDirty(false) , m_maskLayer(0) + , m_ccLayerImpl(0) , m_superlayer(0) #ifndef NDEBUG , m_debugID(s_nextLayerDebugID++) @@ -77,7 +78,7 @@ LayerChromium::LayerChromium(GraphicsLayerChromium* owner) , m_opaque(true) , m_geometryFlipped(false) , m_needsDisplayOnBoundsChange(false) - , m_ccLayerImpl(CCLayerImpl::create(this)) + , m_doubleSided(true) , m_replicaLayer(0) { } @@ -94,7 +95,8 @@ LayerChromium::~LayerChromium() void LayerChromium::cleanupResources() { - m_ccLayerImpl->cleanupResources(); + if (m_ccLayerImpl) + m_ccLayerImpl->cleanupResources(); } void LayerChromium::setLayerRenderer(LayerRendererChromium* renderer) @@ -105,8 +107,7 @@ void LayerChromium::setLayerRenderer(LayerRendererChromium* renderer) cleanupResources(); setNeedsDisplay(); } - - m_ccLayerImpl->setLayerRenderer(renderer); + m_layerRenderer = renderer; } void LayerChromium::setNeedsCommit() @@ -188,7 +189,7 @@ void LayerChromium::setBounds(const IntSize& size) bool firstResize = !bounds().width() && !bounds().height() && size.width() && size.height(); - m_ccLayerImpl->setBounds(size); + m_bounds = size; if (firstResize) setNeedsDisplay(FloatRect(0, 0, bounds().width(), bounds().height())); @@ -240,7 +241,6 @@ LayerChromium* LayerChromium::superlayer() const void LayerChromium::setName(const String& name) { m_name = name; - m_ccLayerImpl->setName(name); } void LayerChromium::setNeedsDisplay(const FloatRect& dirtyRect) @@ -288,6 +288,29 @@ void LayerChromium::toGLMatrix(float* flattened, const TransformationMatrix& m) flattened[15] = m.m44(); } +void LayerChromium::pushPropertiesTo(CCLayerImpl* layer) +{ + layer->setAnchorPoint(m_anchorPoint); + layer->setAnchorPointZ(m_anchorPointZ); + layer->setBounds(m_bounds); + layer->setDebugBorderColor(m_debugBorderColor); + layer->setDebugBorderWidth(m_debugBorderWidth); + layer->setDoubleSided(m_doubleSided); + layer->setLayerRenderer(m_layerRenderer.get()); + layer->setMasksToBounds(m_masksToBounds); + layer->setName(m_name); + layer->setOpacity(m_opacity); + layer->setPosition(m_position); + layer->setPreserves3D(preserves3D()); + layer->setSublayerTransform(m_sublayerTransform); + layer->setTransform(m_transform); + + if (maskLayer()) + maskLayer()->pushPropertiesTo(layer->maskLayer()); + if (replicaLayer()) + replicaLayer()->pushPropertiesTo(layer->replicaLayer()); +} + GraphicsContext3D* LayerChromium::layerRendererContext() const { ASSERT(layerRenderer()); @@ -316,31 +339,6 @@ void LayerChromium::drawTexturedQuad(GraphicsContext3D* context, const Transform GLC(context, context->drawElements(GraphicsContext3D::TRIANGLES, 6, GraphicsContext3D::UNSIGNED_SHORT, 0)); } - - -// Returns true if any of the layer's descendants has drawable content. -bool LayerChromium::descendantsDrawContent() -{ - const Vector<RefPtr<LayerChromium> >& sublayers = getSublayers(); - for (size_t i = 0; i < sublayers.size(); ++i) - if (sublayers[i]->descendantsDrawContentRecursive()) - return true; - return false; -} - -// Returns true if either this layer or one of its descendants has drawable content. -bool LayerChromium::descendantsDrawContentRecursive() -{ - if (drawsContent()) - return true; - - const Vector<RefPtr<LayerChromium> >& sublayers = getSublayers(); - for (size_t i = 0; i < sublayers.size(); ++i) - if (sublayers[i]->descendantsDrawContentRecursive()) - return true; - return false; -} - String LayerChromium::layerTreeAsText() const { TextStream ts; @@ -359,7 +357,8 @@ void LayerChromium::dumpLayer(TextStream& ts, int indent) const writeIndent(ts, indent); ts << layerTypeAsString() << "(" << m_name << ")\n"; dumpLayerProperties(ts, indent+2); - m_ccLayerImpl->dumpLayerProperties(ts, indent+2); + if (m_ccLayerImpl) + m_ccLayerImpl->dumpLayerProperties(ts, indent+2); if (m_replicaLayer) { writeIndent(ts, indent+2); ts << "Replica:\n"; @@ -385,48 +384,38 @@ void LayerChromium::dumpLayerProperties(TextStream& ts, int indent) const } -// Begin calls that forward to the CCLayerImpl. -// ============================================== -// These exists just for debugging (via drawDebugBorder()). -void LayerChromium::setBorderColor(const Color& color) +PassRefPtr<CCLayerImpl> LayerChromium::createCCLayerImpl() { - m_ccLayerImpl->setDebugBorderColor(color); - setNeedsCommit(); + return CCLayerImpl::create(this); } -Color LayerChromium::borderColor() const +void LayerChromium::createCCLayerImplIfNeeded() { - return m_ccLayerImpl->debugBorderColor(); + if (!m_ccLayerImpl) + m_ccLayerImpl = createCCLayerImpl(); } -void LayerChromium::setBorderWidth(float width) +CCLayerImpl* LayerChromium::ccLayerImpl() { - m_ccLayerImpl->setDebugBorderWidth(width); - setNeedsCommit(); + return m_ccLayerImpl.get(); } -float LayerChromium::borderWidth() const -{ - return m_ccLayerImpl->debugBorderWidth(); -} - -LayerRendererChromium* LayerChromium::layerRenderer() const +void LayerChromium::setBorderColor(const Color& color) { - return m_ccLayerImpl->layerRenderer(); + m_debugBorderColor = color; + setNeedsCommit(); } -void LayerChromium::setDoubleSided(bool doubleSided) +void LayerChromium::setBorderWidth(float width) { - m_ccLayerImpl->setDoubleSided(doubleSided); + m_debugBorderWidth = width; setNeedsCommit(); } -const IntSize& LayerChromium::bounds() const +LayerRendererChromium* LayerChromium::layerRenderer() const { - return m_ccLayerImpl->bounds(); + return m_layerRenderer.get(); } -// ============================================== -// End calls that forward to the CCLayerImpl. } #endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/chromium/LayerChromium.h b/Source/WebCore/platform/graphics/chromium/LayerChromium.h index 29a2165..428ce61 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/LayerChromium.h @@ -89,6 +89,9 @@ public: void setBackgroundColor(const Color& color) { m_backgroundColor = color; setNeedsCommit(); } Color backgroundColor() const { return m_backgroundColor; } + void setBounds(const IntSize&); + const IntSize& bounds() const { return m_bounds; } + void setClearsContext(bool clears) { m_clearsContext = clears; setNeedsCommit(); } bool clearsContext() const { return m_clearsContext; } @@ -133,6 +136,9 @@ public: void setTransform(const TransformationMatrix& transform) { m_transform = transform; setNeedsCommit(); } const TransformationMatrix& transform() const { return m_transform; } + bool doubleSided() const { return m_doubleSided; } + void setDoubleSided(bool doubleSided) { m_doubleSided = doubleSided; setNeedsCommit(); } + // FIXME: This setting is currently ignored. void setGeometryFlipped(bool flipped) { m_geometryFlipped = flipped; setNeedsCommit(); } bool geometryFlipped() const { return m_geometryFlipped; } @@ -143,9 +149,6 @@ public: // in the LayerRendererChromium. virtual void setLayerRenderer(LayerRendererChromium*); - // Returns true if any of the layer's descendants has content to draw. - bool descendantsDrawContent(); - void setOwner(GraphicsLayerChromium* owner) { m_owner = owner; } void setReplicaLayer(LayerChromium* layer) { m_replicaLayer = layer; } @@ -153,14 +156,14 @@ public: // These methods typically need to be overwritten by derived classes. virtual bool drawsContent() const { return false; } - virtual void updateContentsIfDirty() { } + virtual void paintContentsIfDirty() { } + virtual void updateCompositorResources() { } virtual void unreserveContentsTexture() { } virtual void bindContentsTexture() { } virtual void draw() { } // These exists just for debugging (via drawDebugBorder()). void setBorderColor(const Color&); - Color borderColor() const; #ifndef NDEBUG int debugID() const { return m_debugID; } @@ -170,21 +173,19 @@ public: String layerTreeAsText() const; void setBorderWidth(float); - float borderWidth() const; // Everything from here down in the public section will move to CCLayerImpl. - - CCLayerImpl* ccLayerImpl() const { return m_ccLayerImpl.get(); } + CCLayerImpl* ccLayerImpl(); + void createCCLayerImplIfNeeded(); static void drawTexturedQuad(GraphicsContext3D*, const TransformationMatrix& projectionMatrix, const TransformationMatrix& layerMatrix, float width, float height, float opacity, int matrixLocation, int alphaLocation); + virtual void pushPropertiesTo(CCLayerImpl*); + // Begin calls that forward to the CCLayerImpl. LayerRendererChromium* layerRenderer() const; - void setDoubleSided(bool); - void setBounds(const IntSize&); - const IntSize& bounds() const; // End calls that forward to the CCLayerImpl. typedef ProgramBinding<VertexShaderPos, FragmentShaderColor> BorderProgram; @@ -217,6 +218,11 @@ protected: static const unsigned s_positionAttribLocation; static const unsigned s_texCoordAttribLocation; + // Constructs a CCLayerImpl of the correct runtime type for this LayerChromium type. + virtual PassRefPtr<CCLayerImpl> createCCLayerImpl(); + + // For now, the LayerChromium directly owns its CCLayerImpl. + RefPtr<CCLayerImpl> m_ccLayerImpl; private: void setNeedsCommit(); @@ -233,19 +239,22 @@ private: // This should only be called from removeFromSuperlayer. void removeSublayer(LayerChromium*); - bool descendantsDrawContentRecursive(); - Vector<RefPtr<LayerChromium> > m_sublayers; LayerChromium* m_superlayer; + RefPtr<LayerRendererChromium> m_layerRenderer; + #ifndef NDEBUG int m_debugID; #endif // Layer properties. + IntSize m_bounds; FloatPoint m_position; FloatPoint m_anchorPoint; Color m_backgroundColor; + Color m_debugBorderColor; + float m_debugBorderWidth; float m_opacity; float m_zPosition; float m_anchorPointZ; @@ -255,13 +264,12 @@ private: bool m_opaque; bool m_geometryFlipped; bool m_needsDisplayOnBoundsChange; + bool m_doubleSided; TransformationMatrix m_transform; TransformationMatrix m_sublayerTransform; FloatRect m_frame; - // For now, the LayerChromium directly owns its CCLayerImpl. - RefPtr<CCLayerImpl> m_ccLayerImpl; // Replica layer used for reflections. LayerChromium* m_replicaLayer; diff --git a/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp index e7b299f..fc15abd 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp @@ -36,6 +36,7 @@ #include "cc/CCLayerImpl.h" #include "Canvas2DLayerChromium.h" +#include "FloatQuad.h" #include "GeometryBinding.h" #include "GraphicsContext3D.h" #include "LayerChromium.h" @@ -43,6 +44,7 @@ #include "NotImplemented.h" #include "TextStream.h" #include "TextureManager.h" +#include "TraceEvent.h" #include "WebGLLayerChromium.h" #include "cc/CCLayerImpl.h" #if USE(SKIA) @@ -91,21 +93,23 @@ bool LayerRendererChromium::compareLayerZ(const CCLayerImpl* a, const CCLayerImp return a->drawDepth() < b->drawDepth(); } -PassRefPtr<LayerRendererChromium> LayerRendererChromium::create(PassRefPtr<GraphicsContext3D> context) +PassRefPtr<LayerRendererChromium> LayerRendererChromium::create(PassRefPtr<GraphicsContext3D> context, PassOwnPtr<TilePaintInterface> contentPaint, PassOwnPtr<TilePaintInterface> scrollbarPaint) { if (!context) return 0; - RefPtr<LayerRendererChromium> layerRenderer(adoptRef(new LayerRendererChromium(context))); + RefPtr<LayerRendererChromium> layerRenderer(adoptRef(new LayerRendererChromium(context, contentPaint, scrollbarPaint))); if (!layerRenderer->hardwareCompositing()) return 0; return layerRenderer.release(); } -LayerRendererChromium::LayerRendererChromium(PassRefPtr<GraphicsContext3D> context) - : m_rootLayer(0) - , m_scrollPosition(IntPoint(-1, -1)) +LayerRendererChromium::LayerRendererChromium(PassRefPtr<GraphicsContext3D> context, PassOwnPtr<TilePaintInterface> contentPaint, PassOwnPtr<TilePaintInterface> scrollbarPaint) + : m_viewportScrollPosition(IntPoint(-1, -1)) + , m_rootLayer(0) + , m_rootLayerContentPaint(contentPaint) + , m_rootLayerScrollbarPaint(scrollbarPaint) , m_currentShader(0) , m_currentRenderSurface(0) , m_offscreenFramebufferId(0) @@ -114,8 +118,8 @@ LayerRendererChromium::LayerRendererChromium(PassRefPtr<GraphicsContext3D> conte , m_defaultRenderSurface(0) { m_hardwareCompositing = initializeSharedObjects(); - m_rootLayerTiler = LayerTilerChromium::create(this, IntSize(256, 256), LayerTilerChromium::NoBorderTexels); - ASSERT(m_rootLayerTiler); + m_rootLayerContentTiler = LayerTilerChromium::create(this, IntSize(256, 256), LayerTilerChromium::NoBorderTexels); + ASSERT(m_rootLayerContentTiler); m_headsUpDisplay = CCHeadsUpDisplay::create(this); } @@ -146,129 +150,149 @@ void LayerRendererChromium::useShader(unsigned programId) } } -IntRect LayerRendererChromium::verticalScrollbarRect(const IntRect& visibleRect, const IntRect& contentRect) +IntRect LayerRendererChromium::verticalScrollbarRect() const { - IntRect verticalScrollbar(IntPoint(contentRect.maxX(), contentRect.y()), IntSize(visibleRect.width() - contentRect.width(), visibleRect.height())); + 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& visibleRect, const IntRect& contentRect) +IntRect LayerRendererChromium::horizontalScrollbarRect() const { - IntRect horizontalScrollbar(IntPoint(contentRect.x(), contentRect.maxY()), IntSize(visibleRect.width(), visibleRect.height() - contentRect.height())); + 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, const IntRect& visibleRect, const IntRect& contentRect) +void LayerRendererChromium::invalidateRootLayerRect(const IntRect& dirtyRect) { - m_rootLayerTiler->invalidateRect(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(visibleRect, contentRect); - if (dirtyRect.intersects(scrollbar)) { + IntRect scrollbar = horizontalScrollbarRect(); + if (visibleDirtyRect.intersects(scrollbar)) { m_horizontalScrollbarTiler->setLayerPosition(scrollbar.location()); - m_horizontalScrollbarTiler->invalidateRect(dirtyRect); + m_horizontalScrollbarTiler->invalidateRect(visibleDirtyRect); } } if (m_verticalScrollbarTiler) { - IntRect scrollbar = verticalScrollbarRect(visibleRect, contentRect); - if (dirtyRect.intersects(scrollbar)) { + IntRect scrollbar = verticalScrollbarRect(); + if (visibleDirtyRect.intersects(scrollbar)) { m_verticalScrollbarTiler->setLayerPosition(scrollbar.location()); - m_verticalScrollbarTiler->invalidateRect(dirtyRect); + m_verticalScrollbarTiler->invalidateRect(visibleDirtyRect); } } } -void LayerRendererChromium::updateRootLayerContents(TilePaintInterface& tilePaint, const IntRect& visibleRect) +void LayerRendererChromium::updateRootLayerContents() { - m_rootLayerTiler->update(tilePaint, visibleRect); + TRACE_EVENT("LayerRendererChromium::updateRootLayerContents", this, 0); + m_rootLayerContentTiler->update(*m_rootLayerContentPaint, m_viewportVisibleRect); } -void LayerRendererChromium::updateRootLayerScrollbars(TilePaintInterface& scrollbarPaint, const IntRect& visibleRect, const IntRect& contentRect) +void LayerRendererChromium::updateRootLayerScrollbars() { - if (visibleRect.width() > contentRect.width()) { - IntRect verticalScrollbar = verticalScrollbarRect(visibleRect, contentRect); + 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(scrollbarPaint, visibleRect); + m_verticalScrollbarTiler->update(*m_rootLayerScrollbarPaint, m_viewportVisibleRect); } else m_verticalScrollbarTiler.clear(); - if (visibleRect.height() > contentRect.height()) { - IntRect horizontalScrollbar = horizontalScrollbarRect(visibleRect, contentRect); + 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(scrollbarPaint, visibleRect); + m_horizontalScrollbarTiler->update(*m_rootLayerScrollbarPaint, m_viewportVisibleRect); } else m_horizontalScrollbarTiler.clear(); } void LayerRendererChromium::drawRootLayer() { - m_rootLayerTiler->draw(m_visibleRect); + m_rootLayerContentTiler->draw(m_viewportVisibleRect); if (m_verticalScrollbarTiler) - m_verticalScrollbarTiler->draw(m_visibleRect); + m_verticalScrollbarTiler->draw(m_viewportVisibleRect); if (m_horizontalScrollbarTiler) - m_horizontalScrollbarTiler->draw(m_visibleRect); + m_horizontalScrollbarTiler->draw(m_viewportVisibleRect); +} + +void LayerRendererChromium::setViewport(const IntRect& visibleRect, const IntRect& contentRect, const IntPoint& scrollPosition) +{ + bool visibleRectChanged = m_viewportVisibleRect.size() != visibleRect.size(); + + m_viewportVisibleRect = visibleRect; + m_viewportContentRect = contentRect; + m_viewportScrollPosition = scrollPosition; + + if (visibleRectChanged) { + // 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(); + } } -void LayerRendererChromium::updateAndDrawLayers(const IntRect& visibleRect, const IntRect& contentRect, const IntPoint& scrollPosition, - TilePaintInterface& tilePaint, TilePaintInterface& scrollbarPaint) +void LayerRendererChromium::updateAndDrawLayers() { ASSERT(m_hardwareCompositing); if (!m_rootLayer) return; - updateRootLayerContents(tilePaint, visibleRect); + updateRootLayerContents(); + // Recheck that we still have a root layer. This may become null if // compositing gets turned off during a paint operation. if (!m_rootLayer) return; - updateRootLayerScrollbars(scrollbarPaint, visibleRect, contentRect); + updateRootLayerScrollbars(); Vector<CCLayerImpl*> renderSurfaceLayerList; - updateLayers(visibleRect, contentRect, scrollPosition, renderSurfaceLayerList); + updateLayers(renderSurfaceLayerList); drawLayers(renderSurfaceLayerList); + + if (isCompositingOffscreen()) + copyOffscreenTextureToDisplay(); } -void LayerRendererChromium::updateLayers(const IntRect& visibleRect, const IntRect& contentRect, const IntPoint& scrollPosition, - Vector<CCLayerImpl*>& renderSurfaceLayerList) +void LayerRendererChromium::updateLayers(Vector<CCLayerImpl*>& renderSurfaceLayerList) { + TRACE_EVENT("LayerRendererChromium::updateLayers", this, 0); + m_rootLayer->createCCLayerImplIfNeeded(); CCLayerImpl* rootDrawLayer = m_rootLayer->ccLayerImpl(); if (!rootDrawLayer->renderSurface()) rootDrawLayer->createRenderSurface(); ASSERT(rootDrawLayer->renderSurface()); - // If the size of the visible area has changed then allocate a new texture - // to store the contents of the root layer and adjust the projection matrix - // and viewport. - - rootDrawLayer->renderSurface()->m_contentRect = IntRect(IntPoint(0, 0), visibleRect.size()); + rootDrawLayer->renderSurface()->m_contentRect = IntRect(IntPoint(0, 0), m_viewportVisibleRect.size()); - if (visibleRect.size() != m_visibleRect.size()) { - // Reset the current render surface to force an update of the viewport and - // projection matrix next time useRenderSurface is called. - m_currentRenderSurface = 0; - } - m_visibleRect = visibleRect; - - m_scrollPosition = scrollPosition; // Scissor out the scrollbars to avoid rendering on top of them. - IntRect rootScissorRect(contentRect); + IntRect rootScissorRect(m_viewportContentRect); // The scissorRect should not include the scroll offset. - rootScissorRect.move(-m_scrollPosition.x(), -m_scrollPosition.y()); + rootScissorRect.move(-m_viewportScrollPosition.x(), -m_viewportScrollPosition.y()); rootDrawLayer->setScissorRect(rootScissorRect); m_defaultRenderSurface = rootDrawLayer->renderSurface(); @@ -283,16 +307,19 @@ void LayerRendererChromium::updateLayers(const IntRect& visibleRect, const IntRe // concept of a large content layer. updatePropertiesAndRenderSurfaces(m_rootLayer.get(), identityMatrix, renderSurfaceLayerList, m_defaultRenderSurface->m_layerList); - updateContentsRecursive(m_rootLayer.get()); + paintContentsRecursive(m_rootLayer.get()); + + updateCompositorResourcesRecursive(m_rootLayer.get()); } void LayerRendererChromium::drawLayers(const Vector<CCLayerImpl*>& renderSurfaceLayerList) { + TRACE_EVENT("LayerRendererChromium::drawLayers", this, 0); CCLayerImpl* rootDrawLayer = m_rootLayer->ccLayerImpl(); makeContextCurrent(); // The GL viewport covers the entire visible area, including the scrollbars. - GLC(m_context.get(), m_context->viewport(0, 0, m_visibleRect.width(), m_visibleRect.height())); + GLC(m_context.get(), m_context->viewport(0, 0, m_viewportVisibleRect.width(), m_viewportVisibleRect.height())); // Bind the common vertex attributes used for drawing all the layers. m_sharedGeometry->prepareForDraw(); @@ -363,11 +390,13 @@ void LayerRendererChromium::drawLayers(const Vector<CCLayerImpl*>& renderSurface void LayerRendererChromium::finish() { + TRACE_EVENT("LayerRendererChromium::finish", this, 0); m_context->finish(); } void LayerRendererChromium::present() { + TRACE_EVENT("LayerRendererChromium::present", this, 0); // We're done! Time to swapbuffers! // Note that currently this has the same effect as swapBuffers; we should @@ -382,7 +411,7 @@ void LayerRendererChromium::setRootLayer(PassRefPtr<LayerChromium> layer) m_rootLayer = layer; if (m_rootLayer) m_rootLayer->setLayerRenderer(this); - m_rootLayerTiler->invalidateEntireLayer(); + m_rootLayerContentTiler->invalidateEntireLayer(); if (m_horizontalScrollbarTiler) m_horizontalScrollbarTiler->invalidateEntireLayer(); if (m_verticalScrollbarTiler) @@ -391,7 +420,7 @@ void LayerRendererChromium::setRootLayer(PassRefPtr<LayerChromium> layer) void LayerRendererChromium::getFramebufferPixels(void *pixels, const IntRect& rect) { - ASSERT(rect.maxX() <= visibleRectSize().width() && rect.maxY() <= visibleRectSize().height()); + ASSERT(rect.maxX() <= m_viewportVisibleRect.width() && rect.maxY() <= m_viewportVisibleRect.height()); if (!pixels) return; @@ -446,8 +475,29 @@ bool LayerRendererChromium::isLayerVisible(LayerChromium* layer, const Transform // necessary transformations, scissor rectangles, render surfaces, etc. void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* layer, const TransformationMatrix& parentMatrix, Vector<CCLayerImpl*>& renderSurfaceLayerList, Vector<CCLayerImpl*>& layerList) { + // Make sure we have CCLayerImpls for this subtree. + layer->createCCLayerImplIfNeeded(); layer->setLayerRenderer(this); + if (layer->maskLayer()) { + layer->maskLayer()->createCCLayerImplIfNeeded(); + layer->maskLayer()->setLayerRenderer(this); + } + if (layer->replicaLayer()) { + layer->replicaLayer()->createCCLayerImplIfNeeded(); + layer->replicaLayer()->setLayerRenderer(this); + } + if (layer->replicaLayer() && layer->replicaLayer()->maskLayer()) { + layer->replicaLayer()->maskLayer()->createCCLayerImplIfNeeded(); + layer->replicaLayer()->maskLayer()->setLayerRenderer(this); + } + CCLayerImpl* drawLayer = layer->ccLayerImpl(); + // Currently we're calling pushPropertiesTo() twice - once here and once in updateCompositorResourcesRecursive(). + // We should only call pushPropertiesTo() in commit, but because we rely on the draw layer state to update + // RenderSurfaces and we rely on RenderSurfaces being up to date in order to paint contents we have + // to update the draw layers twice. + // FIXME: Remove this call once layer updates no longer depend on render surfaces. + layer->pushPropertiesTo(drawLayer); // Compute the new matrix transformation that will be applied to this layer and // all its sublayers. It's important to remember that the layer's position @@ -467,9 +517,9 @@ void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* lay // Where: P is the projection matrix // M is the layer's matrix computed above // S is the scale adjustment (to scale up to the layer size) - IntSize bounds = layer->bounds(); - FloatPoint anchorPoint = layer->anchorPoint(); - FloatPoint position = layer->position(); + IntSize bounds = drawLayer->bounds(); + FloatPoint anchorPoint = drawLayer->anchorPoint(); + FloatPoint position = drawLayer->position(); // Offset between anchor point and the center of the quad. float centerOffsetX = (0.5 - anchorPoint.x()) * bounds.width(); @@ -477,16 +527,16 @@ void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* lay TransformationMatrix layerLocalTransform; // LT = Tr[l] - layerLocalTransform.translate3d(position.x(), position.y(), layer->anchorPointZ()); + layerLocalTransform.translate3d(position.x(), position.y(), drawLayer->anchorPointZ()); // LT = Tr[l] * M[l] - layerLocalTransform.multiply(layer->transform()); + layerLocalTransform.multiply(drawLayer->transform()); // LT = Tr[l] * M[l] * Tr[c] - layerLocalTransform.translate3d(centerOffsetX, centerOffsetY, -layer->anchorPointZ()); + layerLocalTransform.translate3d(centerOffsetX, centerOffsetY, -drawLayer->anchorPointZ()); TransformationMatrix combinedTransform = parentMatrix; combinedTransform = combinedTransform.multiply(layerLocalTransform); - FloatRect layerRect(-0.5 * layer->bounds().width(), -0.5 * layer->bounds().height(), layer->bounds().width(), layer->bounds().height()); + FloatRect layerRect(-0.5 * drawLayer->bounds().width(), -0.5 * drawLayer->bounds().height(), drawLayer->bounds().width(), drawLayer->bounds().height()); IntRect transformedLayerRect; // The layer and its descendants render on a new RenderSurface if any of @@ -498,12 +548,11 @@ void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* lay // If a layer preserves-3d then we don't create a RenderSurface for it to avoid flattening // out its children. The opacity value of the children layers is multiplied by the opacity // of their parent. - bool useSurfaceForClipping = layer->masksToBounds() && !isScaleOrTranslation(combinedTransform); - bool useSurfaceForOpacity = layer->opacity() != 1 && !layer->preserves3D(); - bool useSurfaceForMasking = layer->maskDrawLayer(); - bool useSurfaceForReflection = layer->replicaLayer(); - if (((useSurfaceForClipping || useSurfaceForOpacity) && layer->descendantsDrawContent()) - || useSurfaceForMasking || useSurfaceForReflection) { + bool useSurfaceForClipping = drawLayer->masksToBounds() && !isScaleOrTranslation(combinedTransform); + bool useSurfaceForOpacity = drawLayer->opacity() != 1 && !drawLayer->preserves3D(); + bool useSurfaceForMasking = drawLayer->maskLayer(); + bool useSurfaceForReflection = drawLayer->replicaLayer(); + if (useSurfaceForMasking || useSurfaceForReflection || ((useSurfaceForClipping || useSurfaceForOpacity) && drawLayer->descendantsDrawsContent())) { RenderSurfaceChromium* renderSurface = drawLayer->renderSurface(); if (!renderSurface) renderSurface = drawLayer->createRenderSurface(); @@ -516,15 +565,15 @@ void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* lay transformedLayerRect = IntRect(0, 0, bounds.width(), bounds.height()); // Layer's opacity will be applied when drawing the render surface. - renderSurface->m_drawOpacity = layer->opacity(); - if (layer->superlayer() && layer->superlayer()->preserves3D()) + renderSurface->m_drawOpacity = drawLayer->opacity(); + if (drawLayer->superlayer() && drawLayer->superlayer()->preserves3D()) renderSurface->m_drawOpacity *= drawLayer->superlayer()->drawOpacity(); drawLayer->setDrawOpacity(1); TransformationMatrix layerOriginTransform = combinedTransform; layerOriginTransform.translate3d(-0.5 * bounds.width(), -0.5 * bounds.height(), 0); renderSurface->m_originTransform = layerOriginTransform; - if (layerOriginTransform.isInvertible() && layer->superlayer()) { + if (layerOriginTransform.isInvertible() && drawLayer->superlayer()) { TransformationMatrix parentToLayer = layerOriginTransform.inverse(); drawLayer->setScissorRect(parentToLayer.mapRect(drawLayer->superlayer()->scissorRect())); @@ -538,17 +587,14 @@ void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* lay renderSurface->m_layerList.clear(); - if (layer->maskDrawLayer()) { - renderSurface->m_maskLayer = layer->maskDrawLayer(); - layer->maskDrawLayer()->setLayerRenderer(this); - layer->maskDrawLayer()->setTargetRenderSurface(renderSurface); + if (drawLayer->maskLayer()) { + renderSurface->m_maskLayer = drawLayer->maskLayer(); + drawLayer->maskLayer()->setTargetRenderSurface(renderSurface); } else renderSurface->m_maskLayer = 0; - if (layer->replicaLayer() && layer->replicaLayer()->maskDrawLayer()) { - layer->replicaLayer()->maskDrawLayer()->setLayerRenderer(this); - layer->replicaLayer()->maskDrawLayer()->setTargetRenderSurface(renderSurface); - } + if (drawLayer->replicaLayer() && drawLayer->replicaLayer()->maskLayer()) + drawLayer->replicaLayer()->maskLayer()->setTargetRenderSurface(renderSurface); renderSurfaceLayerList.append(drawLayer); } else { @@ -556,10 +602,10 @@ void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* lay drawLayer->setDrawTransform(combinedTransform); transformedLayerRect = enclosingIntRect(drawLayer->drawTransform().mapRect(layerRect)); - drawLayer->setDrawOpacity(layer->opacity()); + drawLayer->setDrawOpacity(drawLayer->opacity()); - if (layer->superlayer()) { - if (layer->superlayer()->preserves3D()) + if (drawLayer->superlayer()) { + if (drawLayer->superlayer()->preserves3D()) drawLayer->setDrawOpacity(drawLayer->drawOpacity() * drawLayer->superlayer()->drawOpacity()); // Layers inherit the scissor rect from their superlayer. @@ -571,7 +617,7 @@ void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* lay if (layer != m_rootLayer) drawLayer->clearRenderSurface(); - if (layer->masksToBounds()) { + if (drawLayer->masksToBounds()) { IntRect scissor = drawLayer->scissorRect(); scissor.intersect(transformedLayerRect); drawLayer->setScissorRect(scissor); @@ -581,7 +627,7 @@ void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* lay if (drawLayer->renderSurface()) drawLayer->setTargetRenderSurface(drawLayer->renderSurface()); else { - ASSERT(layer->superlayer()); + ASSERT(drawLayer->superlayer()); drawLayer->setTargetRenderSurface(drawLayer->superlayer()->targetRenderSurface()); } @@ -595,7 +641,7 @@ void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* lay TransformationMatrix sublayerMatrix = drawLayer->drawTransform(); // Flatten to 2D if the layer doesn't preserve 3D. - if (!layer->preserves3D()) { + if (!drawLayer->preserves3D()) { sublayerMatrix.setM13(0); sublayerMatrix.setM23(0); sublayerMatrix.setM31(0); @@ -606,7 +652,7 @@ void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* lay } // Apply the sublayer transform at the center of the layer. - sublayerMatrix.multiply(layer->sublayerTransform()); + sublayerMatrix.multiply(drawLayer->sublayerTransform()); // The origin of the sublayers is the top left corner of the layer, not the // center. The matrix passed down to the sublayers is therefore: @@ -619,6 +665,7 @@ void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* lay const Vector<RefPtr<LayerChromium> >& sublayers = layer->getSublayers(); for (size_t i = 0; i < sublayers.size(); ++i) { + sublayers[i]->createCCLayerImplIfNeeded(); CCLayerImpl* sublayer = sublayers[i]->ccLayerImpl(); updatePropertiesAndRenderSurfaces(sublayers[i].get(), sublayerMatrix, renderSurfaceLayerList, descendants); @@ -635,7 +682,7 @@ void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* lay } } - if (layer->masksToBounds() || useSurfaceForMasking) { + if (drawLayer->masksToBounds() || useSurfaceForMasking) { IntRect drawableContentRect = drawLayer->drawableContentRect(); drawableContentRect.intersect(transformedLayerRect); drawLayer->setDrawableContentRect(drawableContentRect); @@ -651,7 +698,7 @@ void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* lay // Don't clip if the layer is reflected as the reflection shouldn't be // clipped. - if (!layer->replicaLayer()) { + if (!drawLayer->replicaLayer()) { renderSurface->m_contentRect.intersect(drawLayer->scissorRect()); FloatPoint clippedSurfaceCenter = renderSurface->contentRectCenter(); centerOffsetDueToClipping = clippedSurfaceCenter - surfaceCenter; @@ -675,10 +722,10 @@ void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* lay // Compute the transformation matrix used to draw the replica of the render // surface. - if (layer->replicaLayer()) { + if (drawLayer->replicaLayer()) { renderSurface->m_replicaDrawTransform = renderSurface->m_originTransform; - renderSurface->m_replicaDrawTransform.translate3d(layer->replicaLayer()->position().x(), layer->replicaLayer()->position().y(), 0); - renderSurface->m_replicaDrawTransform.multiply(layer->replicaLayer()->transform()); + renderSurface->m_replicaDrawTransform.translate3d(drawLayer->replicaLayer()->position().x(), drawLayer->replicaLayer()->position().y(), 0); + renderSurface->m_replicaDrawTransform.multiply(drawLayer->replicaLayer()->transform()); renderSurface->m_replicaDrawTransform.translate3d(surfaceCenter.x() - anchorPoint.x() * bounds.width(), surfaceCenter.y() - anchorPoint.y() * bounds.height(), 0); } } @@ -686,8 +733,8 @@ 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 (layer->superlayer()) { - if (!layer->superlayer()->preserves3D()) + if (drawLayer->superlayer()) { + if (!drawLayer->superlayer()->preserves3D()) drawLayer->setDrawDepth(drawLayer->superlayer()->drawDepth()); else drawLayer->setDrawDepth(layerDrawMatrix.m43()); @@ -697,24 +744,50 @@ void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* lay // 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. - if (layer->preserves3D() && (!layer->superlayer() || !layer->superlayer()->preserves3D())) + if (drawLayer->preserves3D() && (!drawLayer->superlayer() || !drawLayer->superlayer()->preserves3D())) std::stable_sort(&descendants.at(thisLayerIndex), descendants.end(), compareLayerZ); } -void LayerRendererChromium::updateContentsRecursive(LayerChromium* layer) +void LayerRendererChromium::paintContentsRecursive(LayerChromium* layer) { const Vector<RefPtr<LayerChromium> >& sublayers = layer->getSublayers(); for (size_t i = 0; i < sublayers.size(); ++i) - updateContentsRecursive(sublayers[i].get()); + paintContentsRecursive(sublayers[i].get()); + + if (layer->bounds().isEmpty()) + return; if (layer->drawsContent()) - layer->updateContentsIfDirty(); + layer->paintContentsIfDirty(); if (layer->maskLayer() && layer->maskLayer()->drawsContent()) - layer->maskLayer()->updateContentsIfDirty(); + layer->maskLayer()->paintContentsIfDirty(); if (layer->replicaLayer() && layer->replicaLayer()->drawsContent()) - layer->replicaLayer()->updateContentsIfDirty(); + layer->replicaLayer()->paintContentsIfDirty(); if (layer->replicaLayer() && layer->replicaLayer()->maskLayer() && layer->replicaLayer()->maskLayer()->drawsContent()) - layer->replicaLayer()->maskLayer()->updateContentsIfDirty(); + layer->replicaLayer()->maskLayer()->paintContentsIfDirty(); +} + +void LayerRendererChromium::updateCompositorResourcesRecursive(LayerChromium* layer) +{ + const Vector<RefPtr<LayerChromium> >& sublayers = layer->getSublayers(); + for (size_t i = 0; i < sublayers.size(); ++i) + updateCompositorResourcesRecursive(sublayers[i].get()); + + if (layer->bounds().isEmpty()) + return; + + CCLayerImpl* drawLayer = layer->ccLayerImpl(); + + if (drawLayer->drawsContent()) + drawLayer->updateCompositorResources(); + if (drawLayer->maskLayer() && drawLayer->maskLayer()->drawsContent()) + drawLayer->maskLayer()->updateCompositorResources(); + if (drawLayer->replicaLayer() && drawLayer->replicaLayer()->drawsContent()) + drawLayer->replicaLayer()->updateCompositorResources(); + if (drawLayer->replicaLayer() && drawLayer->replicaLayer()->maskLayer() && drawLayer->replicaLayer()->maskLayer()->drawsContent()) + drawLayer->replicaLayer()->maskLayer()->updateCompositorResources(); + + layer->pushPropertiesTo(drawLayer); } void LayerRendererChromium::setCompositeOffscreen(bool compositeOffscreen) @@ -788,22 +861,38 @@ void LayerRendererChromium::drawLayer(CCLayerImpl* layer, RenderSurfaceChromium* return; } - if (layer->bounds().isEmpty()) + if (layer->bounds().isEmpty()) { + layer->unreserveContentsTexture(); return; + } setScissorToRect(layer->scissorRect()); // Check if the layer falls within the visible bounds of the page. IntRect layerRect = layer->getDrawRect(); bool isLayerVisible = layer->scissorRect().intersects(layerRect); - if (!isLayerVisible) + if (!isLayerVisible) { + layer->unreserveContentsTexture(); return; + } // FIXME: Need to take into account the commulative render surface transforms all the way from // the default render surface in order to determine visibility. - TransformationMatrix combinedDrawMatrix = (layer->renderSurface() ? layer->renderSurface()->drawTransform().multiply(layer->drawTransform()) : layer->drawTransform()); - if (!layer->doubleSided() && combinedDrawMatrix.m33() < 0) - return; + TransformationMatrix combinedDrawMatrix = (layer->targetRenderSurface() ? layer->targetRenderSurface()->drawTransform().multiply(layer->drawTransform()) : layer->drawTransform()); + + if (!layer->doubleSided()) { + FloatRect layerRect(FloatPoint(0, 0), FloatSize(layer->bounds())); + FloatQuad mappedLayer = combinedDrawMatrix.mapQuad(FloatQuad(layerRect)); + FloatSize horizontalDir = mappedLayer.p2() - mappedLayer.p1(); + FloatSize verticalDir = mappedLayer.p4() - mappedLayer.p1(); + FloatPoint3D xAxis(horizontalDir.width(), horizontalDir.height(), 0); + FloatPoint3D yAxis(verticalDir.width(), verticalDir.height(), 0); + FloatPoint3D zAxis = xAxis.cross(yAxis); + if (zAxis.z() < 0) { + layer->unreserveContentsTexture(); + return; + } + } if (layer->drawsContent()) layer->draw(); @@ -880,10 +969,10 @@ 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 CanvasLayerChromium::Program(m_context.get())); - m_videoLayerRGBAProgram = adoptPtr(new VideoLayerChromium::RGBAProgram(m_context.get())); - m_videoLayerYUVProgram = adoptPtr(new VideoLayerChromium::YUVProgram(m_context.get())); - m_pluginLayerProgram = adoptPtr(new PluginLayerChromium::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())); + m_pluginLayerProgram = adoptPtr(new CCPluginLayerImpl::Program(m_context.get())); m_renderSurfaceProgram = adoptPtr(new RenderSurfaceChromium::Program(m_context.get())); m_renderSurfaceMaskProgram = adoptPtr(new RenderSurfaceChromium::MaskProgram(m_context.get())); m_tilerProgram = adoptPtr(new LayerTilerChromium::Program(m_context.get())); @@ -920,7 +1009,7 @@ void LayerRendererChromium::cleanupSharedObjects() GLC(m_context.get(), m_context->deleteFramebuffer(m_offscreenFramebufferId)); // Clear tilers before the texture manager, as they have references to textures. - m_rootLayerTiler.clear(); + m_rootLayerContentTiler.clear(); m_horizontalScrollbarTiler.clear(); m_verticalScrollbarTiler.clear(); diff --git a/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h index 7e8850a..667ede2 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h +++ b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h @@ -34,16 +34,17 @@ #if USE(ACCELERATED_COMPOSITING) -#include "CanvasLayerChromium.h" #include "ContentLayerChromium.h" #include "IntRect.h" #include "LayerChromium.h" #include "LayerTilerChromium.h" -#include "PluginLayerChromium.h" #include "RenderSurfaceChromium.h" #include "SkBitmap.h" #include "VideoLayerChromium.h" +#include "cc/CCCanvasLayerImpl.h" #include "cc/CCHeadsUpDisplay.h" +#include "cc/CCPluginLayerImpl.h" +#include "cc/CCVideoLayerImpl.h" #include <wtf/HashMap.h> #include <wtf/Noncopyable.h> #include <wtf/PassOwnPtr.h> @@ -66,17 +67,18 @@ class CCHeadsUpDisplay; // Class that handles drawing of composited render layers using GL. class LayerRendererChromium : public RefCounted<LayerRendererChromium> { public: - static PassRefPtr<LayerRendererChromium> create(PassRefPtr<GraphicsContext3D> graphicsContext3D); + static PassRefPtr<LayerRendererChromium> create(PassRefPtr<GraphicsContext3D>, PassOwnPtr<TilePaintInterface> contentPaint, PassOwnPtr<TilePaintInterface> scrollbarPaint); ~LayerRendererChromium(); GraphicsContext3D* context(); - void invalidateRootLayerRect(const IntRect& dirtyRect, const IntRect& visibleRect, const IntRect& contentRect); + void invalidateRootLayerRect(const IntRect& dirtyRect); + + void setViewport(const IntRect& visibleRect, const IntRect& contentRect, const IntPoint& scrollPosition); // updates and draws the current layers onto the backbuffer - void updateAndDrawLayers(const IntRect& visibleRect, const IntRect& contentRect, const IntPoint& scrollPosition, - TilePaintInterface&, TilePaintInterface& scrollbarPaint); + void updateAndDrawLayers(); // waits for rendering to finish void finish(); @@ -84,7 +86,7 @@ public: // puts backbuffer onscreen void present(); - IntSize visibleRectSize() const { return m_visibleRect.size(); } + IntSize viewportSize() const { return m_viewportVisibleRect.size(); } void setRootLayer(PassRefPtr<LayerChromium> layer); LayerChromium* rootLayer() { return m_rootLayer.get(); } @@ -94,8 +96,6 @@ public: void setCompositeOffscreen(bool); bool isCompositingOffscreen() const { return m_compositeOffscreen; } - LayerTexture* getOffscreenLayerTexture(); - void copyOffscreenTextureToDisplay(); unsigned createLayerTexture(); void deleteLayerTexture(unsigned); @@ -111,13 +111,13 @@ 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 CanvasLayerChromium::Program* canvasLayerProgram() const { return m_canvasLayerProgram.get(); } - const VideoLayerChromium::RGBAProgram* videoLayerRGBAProgram() const { return m_videoLayerRGBAProgram.get(); } - const VideoLayerChromium::YUVProgram* videoLayerYUVProgram() const { return m_videoLayerYUVProgram.get(); } - const PluginLayerChromium::Program* pluginLayerProgram() const { return m_pluginLayerProgram.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(); } + const CCCanvasLayerImpl::Program* canvasLayerProgram() const { return m_canvasLayerProgram.get(); } + const CCPluginLayerImpl::Program* pluginLayerProgram() const { return m_pluginLayerProgram.get(); } + const CCVideoLayerImpl::RGBAProgram* videoLayerRGBAProgram() const { return m_videoLayerRGBAProgram.get(); } + const CCVideoLayerImpl::YUVProgram* videoLayerYUVProgram() const { return m_videoLayerYUVProgram.get(); } void resizeOnscreenContent(const IntSize&); @@ -132,19 +132,21 @@ public: String layerTreeAsText() const; private: - explicit LayerRendererChromium(PassRefPtr<GraphicsContext3D> graphicsContext3D); + explicit LayerRendererChromium(PassRefPtr<GraphicsContext3D>, PassOwnPtr<TilePaintInterface> contentPaint, PassOwnPtr<TilePaintInterface> scrollbarPaint); - void updateLayers(const IntRect& visibleRect, const IntRect& contentRect, const IntPoint& scrollPosition, - Vector<CCLayerImpl*>& renderSurfaceLayerList); - void updateRootLayerContents(TilePaintInterface&, const IntRect& visibleRect); - void updateRootLayerScrollbars(TilePaintInterface& scrollbarPaint, const IntRect& visibleRect, const IntRect& contentRect); + void updateLayers(Vector<CCLayerImpl*>& renderSurfaceLayerList); + void updateRootLayerContents(); + void updateRootLayerScrollbars(); void updatePropertiesAndRenderSurfaces(LayerChromium*, const TransformationMatrix& parentMatrix, Vector<CCLayerImpl*>& renderSurfaceLayerList, Vector<CCLayerImpl*>& layerList); - void updateContentsRecursive(LayerChromium*); + void paintContentsRecursive(LayerChromium*); + void updateCompositorResourcesRecursive(LayerChromium*); void drawLayers(const Vector<CCLayerImpl*>& renderSurfaceLayerList); void drawLayer(CCLayerImpl*, RenderSurfaceChromium*); void drawRootLayer(); + LayerTexture* getOffscreenLayerTexture(); + void copyOffscreenTextureToDisplay(); bool isLayerVisible(LayerChromium*, const TransformationMatrix&, const IntRect& visibleRect); @@ -161,19 +163,22 @@ private: bool initializeSharedObjects(); void cleanupSharedObjects(); - static IntRect verticalScrollbarRect(const IntRect& visibleRect, const IntRect& contentRect); - static IntRect horizontalScrollbarRect(const IntRect& visibleRect, const IntRect& contentRect); + IntRect verticalScrollbarRect() const; + IntRect horizontalScrollbarRect() const; - IntRect m_visibleRect; + IntRect m_viewportVisibleRect; + IntRect m_viewportContentRect; + IntPoint m_viewportScrollPosition; TransformationMatrix m_projectionMatrix; RefPtr<LayerChromium> m_rootLayer; - OwnPtr<LayerTilerChromium> m_rootLayerTiler; + OwnPtr<TilePaintInterface> m_rootLayerContentPaint; + OwnPtr<TilePaintInterface> m_rootLayerScrollbarPaint; + OwnPtr<LayerTilerChromium> m_rootLayerContentTiler; OwnPtr<LayerTilerChromium> m_horizontalScrollbarTiler; OwnPtr<LayerTilerChromium> m_verticalScrollbarTiler; - IntPoint m_scrollPosition; bool m_hardwareCompositing; unsigned m_currentShader; @@ -202,13 +207,13 @@ private: OwnPtr<GeometryBinding> m_sharedGeometry; OwnPtr<LayerChromium::BorderProgram> m_borderProgram; OwnPtr<ContentLayerChromium::Program> m_contentLayerProgram; - OwnPtr<CanvasLayerChromium::Program> m_canvasLayerProgram; - OwnPtr<VideoLayerChromium::RGBAProgram> m_videoLayerRGBAProgram; - OwnPtr<VideoLayerChromium::YUVProgram> m_videoLayerYUVProgram; - OwnPtr<PluginLayerChromium::Program> m_pluginLayerProgram; OwnPtr<RenderSurfaceChromium::Program> m_renderSurfaceProgram; OwnPtr<RenderSurfaceChromium::MaskProgram> m_renderSurfaceMaskProgram; OwnPtr<LayerTilerChromium::Program> m_tilerProgram; + OwnPtr<CCCanvasLayerImpl::Program> m_canvasLayerProgram; + OwnPtr<CCVideoLayerImpl::RGBAProgram> m_videoLayerRGBAProgram; + OwnPtr<CCVideoLayerImpl::YUVProgram> m_videoLayerYUVProgram; + OwnPtr<CCPluginLayerImpl::Program> m_pluginLayerProgram; OwnPtr<TextureManager> m_textureManager; diff --git a/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.cpp b/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.cpp index 86592a6..bc37201 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.cpp @@ -34,6 +34,7 @@ #include "GraphicsContext3D.h" #include "LayerRendererChromium.h" #include "LayerTexture.h" +#include "TraceEvent.h" #include <wtf/PassOwnArrayPtr.h> @@ -84,58 +85,50 @@ void LayerTilerChromium::reset() { m_tiles.clear(); m_unusedTiles.clear(); - m_tilingData.setTotalSize(0, 0); - m_lastUpdateLayerRect = IntRect(); } LayerTilerChromium::Tile* LayerTilerChromium::createTile(int i, int j) { - const int index = tileIndex(i, j); - ASSERT(!m_tiles[index]); + ASSERT(!tileAt(i, j)); + RefPtr<Tile> tile; if (m_unusedTiles.size() > 0) { - m_tiles[index] = m_unusedTiles.last().release(); + tile = m_unusedTiles.last().release(); m_unusedTiles.removeLast(); + ASSERT(tile->refCount() == 1); } else { GraphicsContext3D* context = layerRendererContext(); TextureManager* manager = layerRenderer()->textureManager(); - OwnPtr<Tile> tile = adoptPtr(new Tile(LayerTexture::create(context, manager))); - m_tiles[index] = tile.release(); + tile = adoptRef(new Tile(LayerTexture::create(context, manager))); } + m_tiles.add(make_pair(i, j), tile); + + tile->moveTo(i, j); + tile->m_dirtyLayerRect = tileLayerRect(tile.get()); - m_tiles[index]->m_dirtyLayerRect = tileLayerRect(i, j); - return m_tiles[index].get(); + return tile.get(); } -void LayerTilerChromium::invalidateTiles(const IntRect& oldLayerRect, const IntRect& newLayerRect) +void LayerTilerChromium::invalidateTiles(const IntRect& contentRect) { if (!m_tiles.size()) return; - IntRect oldContentRect = layerRectToContentRect(oldLayerRect); - int oldLeft, oldTop, oldRight, oldBottom; - contentRectToTileIndices(oldContentRect, oldLeft, oldTop, oldRight, oldBottom); - - IntRect newContentRect = layerRectToContentRect(newLayerRect); - int newLeft, newTop, newRight, newBottom; - contentRectToTileIndices(newContentRect, newLeft, newTop, newRight, newBottom); - - // Iterating through just the old tile indices is an optimization to avoid - // iterating through the entire m_tiles array. - for (int j = oldTop; j <= oldBottom; ++j) { - for (int i = oldLeft; i <= oldRight; ++i) { - if (i >= newLeft && i <= newRight && j >= newTop && j <= newBottom) - continue; - - const int index = tileIndex(i, j); - if (m_tiles[index]) - m_unusedTiles.append(m_tiles[index].release()); - } + Vector<TileMapKey> removeKeys; + for (TileMap::iterator iter = m_tiles.begin(); iter != m_tiles.end(); ++iter) { + Tile* tile = iter->second.get(); + IntRect tileRect = tileContentRect(tile); + if (tileRect.intersects(contentRect)) + continue; + removeKeys.append(iter->first); } + + for (size_t i = 0; i < removeKeys.size(); ++i) + m_unusedTiles.append(m_tiles.take(removeKeys[i])); } -void LayerTilerChromium::contentRectToTileIndices(const IntRect& contentRect, int &left, int &top, int &right, int &bottom) const +void LayerTilerChromium::contentRectToTileIndices(const IntRect& contentRect, int& left, int& top, int& right, int& bottom) const { const IntRect layerRect = contentRectToLayerRect(contentRect); @@ -163,36 +156,28 @@ IntRect LayerTilerChromium::layerRectToContentRect(const IntRect& layerRect) con return contentRect; } -int LayerTilerChromium::tileIndex(int i, int j) const +LayerTilerChromium::Tile* LayerTilerChromium::tileAt(int i, int j) const { - return m_tilingData.tileIndex(i, j); + Tile* tile = m_tiles.get(make_pair(i, j)).get(); + ASSERT(!tile || tile->refCount() == 1); + return tile; } -IntRect LayerTilerChromium::tileContentRect(int i, int j) const +IntRect LayerTilerChromium::tileContentRect(const Tile* tile) const { - IntRect contentRect = tileLayerRect(i, j); + IntRect contentRect = tileLayerRect(tile); contentRect.move(m_layerPosition.x(), m_layerPosition.y()); return contentRect; } -IntRect LayerTilerChromium::tileLayerRect(int i, int j) const +IntRect LayerTilerChromium::tileLayerRect(const Tile* tile) const { - const int index = m_tilingData.tileIndex(i, j); + const int index = m_tilingData.tileIndex(tile->i(), tile->j()); IntRect layerRect = m_tilingData.tileBoundsWithBorder(index); layerRect.setSize(m_tileSize); return layerRect; } -IntSize LayerTilerChromium::layerSize() const -{ - return IntSize(m_tilingData.totalSizeX(), m_tilingData.totalSizeY()); -} - -IntSize LayerTilerChromium::layerTileSize() const -{ - return IntSize(m_tilingData.numTilesX(), m_tilingData.numTilesY()); -} - void LayerTilerChromium::invalidateRect(const IntRect& contentRect) { if (contentRect.isEmpty()) @@ -202,16 +187,16 @@ void LayerTilerChromium::invalidateRect(const IntRect& contentRect) // Dirty rects are always in layer space, as the layer could be repositioned // after invalidation. - IntRect layerRect = contentRectToLayerRect(contentRect); + const IntRect layerRect = contentRectToLayerRect(contentRect); int left, top, right, bottom; contentRectToTileIndices(contentRect, left, top, right, bottom); for (int j = top; j <= bottom; ++j) { for (int i = left; i <= right; ++i) { - Tile* tile = m_tiles[tileIndex(i, j)].get(); + Tile* tile = tileAt(i, j); if (!tile) continue; - IntRect bound = tileLayerRect(i, j); + IntRect bound = tileLayerRect(tile); bound.intersect(layerRect); tile->m_dirtyLayerRect.unite(bound); } @@ -220,14 +205,13 @@ void LayerTilerChromium::invalidateRect(const IntRect& contentRect) void LayerTilerChromium::invalidateEntireLayer() { - for (size_t i = 0; i < m_tiles.size(); ++i) { - if (m_tiles[i]) - m_unusedTiles.append(m_tiles[i].release()); + for (TileMap::iterator iter = m_tiles.begin(); iter != m_tiles.end(); ++iter) { + ASSERT(iter->second->refCount() == 1); + m_unusedTiles.append(iter->second.release()); } m_tiles.clear(); m_tilingData.setTotalSize(0, 0); - m_lastUpdateLayerRect = IntRect(); } void LayerTilerChromium::update(TilePaintInterface& painter, const IntRect& contentRect) @@ -237,10 +221,7 @@ void LayerTilerChromium::update(TilePaintInterface& painter, const IntRect& cont // Invalidate old tiles that were previously used but aren't in use this // frame so that they can get reused for new tiles. - IntRect layerRect = contentRectToLayerRect(contentRect); - invalidateTiles(m_lastUpdateLayerRect, layerRect); - m_lastUpdateLayerRect = layerRect; - + invalidateTiles(contentRect); growLayerToContain(contentRect); // Create tiles as needed, expanding a dirty rect to contain all @@ -250,11 +231,11 @@ void LayerTilerChromium::update(TilePaintInterface& painter, const IntRect& cont contentRectToTileIndices(contentRect, left, top, right, bottom); for (int j = top; j <= bottom; ++j) { for (int i = left; i <= right; ++i) { - Tile* tile = m_tiles[tileIndex(i, j)].get(); + Tile* tile = tileAt(i, j); if (!tile) tile = createTile(i, j); if (!tile->texture()->isValid(m_tileSize, GraphicsContext3D::RGBA)) - tile->m_dirtyLayerRect = tileLayerRect(i, j); + tile->m_dirtyLayerRect = tileLayerRect(tile); dirtyLayerRect.unite(tile->m_dirtyLayerRect); } } @@ -267,10 +248,16 @@ void LayerTilerChromium::update(TilePaintInterface& painter, const IntRect& cont m_canvas.resize(paintRect.size()); PlatformCanvas::Painter canvasPainter(&m_canvas); canvasPainter.context()->translate(-paintRect.x(), -paintRect.y()); - painter.paint(*canvasPainter.context(), paintRect); + { + TRACE_EVENT("LayerTilerChromium::update::paint", this, 0); + painter.paint(*canvasPainter.context(), paintRect); + } PlatformCanvas::AutoLocker locker(&m_canvas); - updateFromPixels(paintRect, locker.pixels()); + { + TRACE_EVENT("LayerTilerChromium::updateFromPixels", this, 0); + updateFromPixels(paintRect, locker.pixels()); + } } void LayerTilerChromium::updateFromPixels(const IntRect& paintRect, const uint8_t* paintPixels) @@ -285,14 +272,14 @@ void LayerTilerChromium::updateFromPixels(const IntRect& paintRect, const uint8_ contentRectToTileIndices(paintRect, left, top, right, bottom); for (int j = top; j <= bottom; ++j) { for (int i = left; i <= right; ++i) { - Tile* tile = m_tiles[tileIndex(i, j)].get(); + Tile* tile = tileAt(i, j); if (!tile) CRASH(); if (!tile->dirty()) continue; // Calculate page-space rectangle to copy from. - IntRect sourceRect = tileContentRect(i, j); + IntRect sourceRect = tileContentRect(tile); const IntPoint anchor = sourceRect.location(); sourceRect.intersect(layerRectToContentRect(tile->m_dirtyLayerRect)); if (sourceRect.isEmpty()) @@ -366,8 +353,7 @@ void LayerTilerChromium::draw(const IntRect& contentRect) contentRectToTileIndices(contentRect, left, top, right, bottom); for (int j = top; j <= bottom; ++j) { for (int i = left; i <= right; ++i) { - const int index = tileIndex(i, j); - Tile* tile = m_tiles[index].get(); + Tile* tile = tileAt(i, j); ASSERT(tile); tile->texture()->bindTexture(); @@ -376,11 +362,11 @@ void LayerTilerChromium::draw(const IntRect& contentRect) // Don't use tileContentRect here, as that contains the full // rect with border texels which shouldn't be drawn. - IntRect tileRect = m_tilingData.tileBounds(index); + 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); - IntPoint texOffset = m_tilingData.textureOffset(i, j); + IntPoint texOffset = m_tilingData.textureOffset(tile->i(), tile->j()); float tileWidth = static_cast<float>(m_tileSize.width()); float tileHeight = static_cast<float>(m_tileSize.height()); float texTranslateX = texOffset.x() / tileWidth; @@ -395,37 +381,15 @@ void LayerTilerChromium::draw(const IntRect& contentRect) } } -void LayerTilerChromium::resizeLayer(const IntSize& size) -{ - if (layerSize() == size) - return; - - const IntSize oldTileSize = layerTileSize(); - m_tilingData.setTotalSize(size.width(), size.height()); - const IntSize newTileSize = layerTileSize(); - - if (oldTileSize == newTileSize) - return; - - if (newTileSize.height() && (newTileSize.width() > INT_MAX / newTileSize.height())) - CRASH(); - - Vector<OwnPtr<Tile> > newTiles; - newTiles.resize(newTileSize.width() * newTileSize.height()); - for (int j = 0; j < oldTileSize.height(); ++j) - for (int i = 0; i < oldTileSize.width(); ++i) - newTiles[i + j * newTileSize.width()].swap(m_tiles[i + j * oldTileSize.width()]); - m_tiles.swap(newTiles); -} - void LayerTilerChromium::growLayerToContain(const IntRect& contentRect) { // Grow the tile array to contain this content rect. IntRect layerRect = contentRectToLayerRect(contentRect); IntSize rectSize = IntSize(layerRect.maxX(), layerRect.maxY()); - IntSize newSize = rectSize.expandedTo(layerSize()); - resizeLayer(newSize); + IntSize oldLayerSize(m_tilingData.totalSizeX(), m_tilingData.totalSizeY()); + IntSize newSize = rectSize.expandedTo(oldLayerSize); + m_tilingData.setTotalSize(newSize.width(), newSize.height()); } void LayerTilerChromium::drawTexturedQuad(GraphicsContext3D* context, const TransformationMatrix& projectionMatrix, const TransformationMatrix& drawMatrix, diff --git a/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.h b/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.h index bdb35a5..2f356e4 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.h @@ -33,7 +33,9 @@ #include "LayerTexture.h" #include "PlatformCanvas.h" #include "TilingData.h" +#include <wtf/HashTraits.h> #include <wtf/OwnArrayPtr.h> +#include <wtf/RefCounted.h> namespace WebCore { @@ -70,20 +72,26 @@ public: private: LayerTilerChromium(LayerRendererChromium*, const IntSize& tileSize, BorderTexelOption); - class Tile { + class Tile : public RefCounted<Tile> { WTF_MAKE_NONCOPYABLE(Tile); public: - explicit Tile(PassOwnPtr<LayerTexture> tex) : m_tex(tex) {} + explicit Tile(PassOwnPtr<LayerTexture> tex) : m_tex(tex), m_i(-1), m_j(-1) {} LayerTexture* texture() { return m_tex.get(); } bool dirty() const { return !m_dirtyLayerRect.isEmpty(); } void clearDirty() { m_dirtyLayerRect = IntRect(); } + int i() const { return m_i; } + int j() const { return m_j; } + void moveTo(int i, int j) { m_i = i; m_j = j; } + // Layer-space dirty rectangle that needs to be repainted. IntRect m_dirtyLayerRect; private: OwnPtr<LayerTexture> m_tex; + int m_i; + int m_j; }; void drawTexturedQuad(GraphicsContext3D*, const TransformationMatrix& projectionMatrix, const TransformationMatrix& drawMatrix, @@ -92,40 +100,45 @@ private: float texScaleX, float texScaleY, const LayerTilerChromium::Program*); - void resizeLayer(const IntSize& size); // Grow layer size to contain this rectangle. void growLayerToContain(const IntRect& contentRect); LayerRendererChromium* layerRenderer() const { return m_layerRenderer; } GraphicsContext3D* layerRendererContext() const; Tile* createTile(int i, int j); - // Invalidate any tiles which do not intersect with the newLayerRect. - void invalidateTiles(const IntRect& oldLayerRect, const IntRect& newLayerRect); + // Invalidate any tiles which do not intersect with the contentRect + void invalidateTiles(const IntRect& contentRect); void reset(); void contentRectToTileIndices(const IntRect& contentRect, int &left, int &top, int &right, int &bottom) const; IntRect contentRectToLayerRect(const IntRect& contentRect) const; IntRect layerRectToContentRect(const IntRect& layerRect) const; - // Returns the index into m_tiles for a given tile location. - int tileIndex(int i, int j) const; - // Returns the bounds in content space for a given tile location. - IntRect tileContentRect(int i, int j) const; - // Returns the bounds in layer space for a given tile location. - IntRect tileLayerRect(int i, int j) const; - - IntSize layerSize() const; - IntSize layerTileSize() const; + Tile* tileAt(int, int) const; + IntRect tileContentRect(const Tile*) const; + IntRect tileLayerRect(const Tile*) const; IntSize m_tileSize; - IntRect m_lastUpdateLayerRect; IntPoint m_layerPosition; bool m_skipsDraw; - // Logical 2D array of tiles (dimensions of m_layerTileSize) - Vector<OwnPtr<Tile> > m_tiles; - // Linear array of unused tiles. - Vector<OwnPtr<Tile> > m_unusedTiles; + // Default hash key traits for integers disallow 0 and -1 as a key, so + // use a custom hash trait which disallows -1 and -2 instead. + typedef std::pair<int, int> TileMapKey; + struct TileMapKeyTraits : HashTraits<TileMapKey> { + static const bool emptyValueIsZero = false; + static const bool needsDestruction = false; + static TileMapKey emptyValue() { return std::make_pair(-1, -1); } + static void constructDeletedValue(TileMapKey& slot) { slot = std::make_pair(-2, -2); } + static bool isDeletedValue(TileMapKey value) { return value.first == -2 && value.second == -2; } + }; + // FIXME: The mapped value in TileMap should really be an OwnPtr, as the + // refcount of a Tile should never be more than 1. However, HashMap + // doesn't easily support OwnPtr as a value. + typedef HashMap<TileMapKey, RefPtr<Tile>, DefaultHash<TileMapKey>::Hash, TileMapKeyTraits> TileMap; + TileMap m_tiles; + // Tightly packed set of unused tiles. + Vector<RefPtr<Tile> > m_unusedTiles; PlatformCanvas m_canvas; diff --git a/Source/WebCore/platform/graphics/chromium/PluginLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/PluginLayerChromium.cpp index 5d595ad..3667fbb 100644 --- a/Source/WebCore/platform/graphics/chromium/PluginLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/PluginLayerChromium.cpp @@ -29,10 +29,10 @@ #include "PluginLayerChromium.h" -#include "cc/CCLayerImpl.h" #include "GraphicsContext3D.h" #include "LayerRendererChromium.h" -#include <GLES2/gl2.h> +#include "cc/CCLayerImpl.h" +#include "cc/CCPluginLayerImpl.h" namespace WebCore { @@ -43,40 +43,26 @@ PassRefPtr<PluginLayerChromium> PluginLayerChromium::create(GraphicsLayerChromiu PluginLayerChromium::PluginLayerChromium(GraphicsLayerChromium* owner) : LayerChromium(owner) + , m_textureId(0) { } -void PluginLayerChromium::setTextureId(unsigned id) +PassRefPtr<CCLayerImpl> PluginLayerChromium::createCCLayerImpl() { - m_textureId = id; + return CCPluginLayerImpl::create(this); } -void PluginLayerChromium::updateContentsIfDirty() +void PluginLayerChromium::setTextureId(unsigned id) { + m_textureId = id; } -void PluginLayerChromium::draw() +void PluginLayerChromium::pushPropertiesTo(CCLayerImpl* layer) { - ASSERT(layerRenderer()); - const PluginLayerChromium::Program* program = layerRenderer()->pluginLayerProgram(); - ASSERT(program && program->initialized()); - GraphicsContext3D* context = layerRendererContext(); - GLC(context, context->activeTexture(GL_TEXTURE0)); - GLC(context, context->bindTexture(GL_TEXTURE_2D, m_textureId)); - - // FIXME: setting the texture parameters every time is redundant. Move this code somewhere - // where it will only happen once per texture. - GLC(context, context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - GLC(context, context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); - GLC(context, context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); - GLC(context, context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); - - layerRenderer()->useShader(program->program()); - GLC(context, context->uniform1i(program->fragmentShader().samplerLocation(), 0)); - drawTexturedQuad(context, layerRenderer()->projectionMatrix(), ccLayerImpl()->drawTransform(), - bounds().width(), bounds().height(), ccLayerImpl()->drawOpacity(), - program->vertexShader().matrixLocation(), - program->fragmentShader().alphaLocation()); + LayerChromium::pushPropertiesTo(layer); + + CCPluginLayerImpl* pluginLayer = static_cast<CCPluginLayerImpl*>(layer); + pluginLayer->setTextureId(m_textureId); } } diff --git a/Source/WebCore/platform/graphics/chromium/PluginLayerChromium.h b/Source/WebCore/platform/graphics/chromium/PluginLayerChromium.h index 8d66f5f..852dc2e 100644 --- a/Source/WebCore/platform/graphics/chromium/PluginLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/PluginLayerChromium.h @@ -38,18 +38,19 @@ class PluginLayerChromium : public LayerChromium { public: static PassRefPtr<PluginLayerChromium> create(GraphicsLayerChromium* owner = 0); virtual bool drawsContent() const { return true; } - virtual void updateContentsIfDirty(); - virtual void draw(); - + + virtual PassRefPtr<CCLayerImpl> createCCLayerImpl(); + void setTextureId(unsigned textureId); - - typedef ProgramBinding<VertexShaderPosTex, FragmentShaderRGBATexFlipAlpha> Program; + unsigned textureId() const { return m_textureId; } + + virtual void pushPropertiesTo(CCLayerImpl*); protected: virtual const char* layerTypeAsString() const { return "PluginLayer"; } private: - PluginLayerChromium(GraphicsLayerChromium* owner); + explicit PluginLayerChromium(GraphicsLayerChromium* owner); unsigned m_textureId; }; diff --git a/Source/WebCore/platform/graphics/chromium/ShaderChromium.cpp b/Source/WebCore/platform/graphics/chromium/ShaderChromium.cpp index 49b3462..b7f447b 100644 --- a/Source/WebCore/platform/graphics/chromium/ShaderChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/ShaderChromium.cpp @@ -248,7 +248,7 @@ FragmentShaderYUVVideo::FragmentShaderYUVVideo() , m_vTextureLocation(-1) , m_alphaLocation(-1) , m_ccMatrixLocation(-1) - , m_signAdjLocation(-1) + , m_yuvAdjLocation(-1) { } @@ -259,10 +259,10 @@ bool FragmentShaderYUVVideo::init(GraphicsContext3D* context, unsigned program) m_vTextureLocation = context->getUniformLocation(program, "v_texture"); m_alphaLocation = context->getUniformLocation(program, "alpha"); m_ccMatrixLocation = context->getUniformLocation(program, "cc_matrix"); - m_signAdjLocation = context->getUniformLocation(program, "adj"); + m_yuvAdjLocation = context->getUniformLocation(program, "yuv_adj"); return m_yTextureLocation != -1 && m_uTextureLocation != -1 && m_vTextureLocation != -1 - && m_alphaLocation != -1 && m_ccMatrixLocation != -1 && m_signAdjLocation != -1; + && m_alphaLocation != -1 && m_ccMatrixLocation != -1 && m_yuvAdjLocation != -1; } String FragmentShaderYUVVideo::getShaderString() const @@ -276,14 +276,15 @@ String FragmentShaderYUVVideo::getShaderString() const uniform sampler2D u_texture; uniform sampler2D v_texture; uniform float alpha; - uniform float adj; + uniform vec3 yuv_adj; uniform mat3 cc_matrix; void main() { - float y = texture2D(y_texture, y_texCoord).x; - float u = texture2D(u_texture, uv_texCoord).x - adj; - float v = texture2D(v_texture, uv_texCoord).x - adj; - vec3 rgb = cc_matrix * vec3(y, u, v); + float y_raw = texture2D(y_texture, y_texCoord).x; + float u_unsigned = texture2D(u_texture, uv_texCoord).x; + float v_unsigned = texture2D(v_texture, uv_texCoord).x; + vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj; + vec3 rgb = cc_matrix * yuv; gl_FragColor = vec4(rgb, float(1)) * alpha; } ); diff --git a/Source/WebCore/platform/graphics/chromium/ShaderChromium.h b/Source/WebCore/platform/graphics/chromium/ShaderChromium.h index 758c62b..3a3e175 100644 --- a/Source/WebCore/platform/graphics/chromium/ShaderChromium.h +++ b/Source/WebCore/platform/graphics/chromium/ShaderChromium.h @@ -158,7 +158,7 @@ public: int vTextureLocation() const { return m_vTextureLocation; } int alphaLocation() const { return m_alphaLocation; } int ccMatrixLocation() const { return m_ccMatrixLocation; } - int signAdjLocation() const { return m_signAdjLocation; } + int yuvAdjLocation() const { return m_yuvAdjLocation; } private: int m_yTextureLocation; @@ -166,7 +166,7 @@ private: int m_vTextureLocation; int m_alphaLocation; int m_ccMatrixLocation; - int m_signAdjLocation; + int m_yuvAdjLocation; }; class FragmentShaderColor { diff --git a/Source/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp b/Source/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp index 9423d1e..7cd47fe 100644 --- a/Source/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp +++ b/Source/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp @@ -113,13 +113,13 @@ void SimpleFontData::platformInit() m_fontMetrics.setXHeight(xHeight); m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap)); - if (m_orientation == Vertical) { + if (platformData().orientation() == Vertical && !isTextOrientationFallback()) { static const uint32_t vheaTag = SkSetFourByteTag('v', 'h', 'e', 'a'); static const uint32_t vorgTag = SkSetFourByteTag('V', 'O', 'R', 'G'); size_t vheaSize = SkFontHost::GetTableSize(fontID, vheaTag); size_t vorgSize = SkFontHost::GetTableSize(fontID, vorgTag); - if ((vheaSize <= 0) && (vorgSize <= 0)) - m_orientation = Horizontal; + if ((vheaSize > 0) || (vorgSize > 0)) + m_hasVerticalGlyphs = true; } // In WebKit/WebCore/platform/graphics/SimpleFontData.cpp, m_spaceWidth is diff --git a/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp index 5d7a6e7..182e730 100644 --- a/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp @@ -33,7 +33,6 @@ #if USE(ACCELERATED_COMPOSITING) #include "VideoLayerChromium.h" -#include "cc/CCLayerImpl.h" #include "Extensions3DChromium.h" #include "GraphicsContext3D.h" #include "LayerRendererChromium.h" @@ -41,17 +40,11 @@ #include "RenderLayerBacking.h" #include "VideoFrameChromium.h" #include "VideoFrameProvider.h" +#include "cc/CCLayerImpl.h" +#include "cc/CCVideoLayerImpl.h" namespace WebCore { -// These values are magic numbers that are used in the transformation -// from YUV to RGB color values. -const float VideoLayerChromium::yuv2RGB[9] = { - 1.f, 1.f, 1.f, - 0.f, -.344f, 1.772f, - 1.403f, -.714f, 0.f, -}; - PassRefPtr<VideoLayerChromium> VideoLayerChromium::create(GraphicsLayerChromium* owner, VideoFrameProvider* provider) { @@ -71,23 +64,37 @@ VideoLayerChromium::VideoLayerChromium(GraphicsLayerChromium* owner, VideoFrameP VideoLayerChromium::~VideoLayerChromium() { cleanupResources(); + deleteTexturesInUse(); } -void VideoLayerChromium::cleanupResources() +PassRefPtr<CCLayerImpl> VideoLayerChromium::createCCLayerImpl() +{ + return CCVideoLayerImpl::create(this); +} + +void VideoLayerChromium::deleteTexturesInUse() { - LayerChromium::cleanupResources(); - releaseCurrentFrame(); if (!layerRenderer()) return; GraphicsContext3D* context = layerRendererContext(); for (unsigned plane = 0; plane < VideoFrameChromium::maxPlanes; plane++) { - if (m_textures[plane]) - GLC(context, context->deleteTexture(m_textures[plane])); + Texture texture = m_textures[plane]; + if (!texture.isEmpty && texture.ownedByLayerRenderer) + GLC(context, context->deleteTexture(texture.id)); } } -void VideoLayerChromium::updateContentsIfDirty() +void VideoLayerChromium::cleanupResources() +{ + LayerChromium::cleanupResources(); + if (m_currentFrame) + releaseCurrentFrame(); + else + resetFrameParameters(); +} + +void VideoLayerChromium::updateCompositorResources() { if (!m_contentsDirty) return; @@ -116,6 +123,9 @@ void VideoLayerChromium::updateContentsIfDirty() return; } + // If the incoming frame is backed by a texture (i.e. decoded in hardware), + // then we do not need to allocate a texture via the layer renderer. Instead + // we save the texture data then exit. if (frame->surfaceType() == VideoFrameChromium::TypeTexture) { releaseCurrentFrame(); saveCurrentFrame(frame); @@ -136,8 +146,9 @@ void VideoLayerChromium::updateContentsIfDirty() // Update texture planes. for (unsigned plane = 0; plane < frame->planes(); plane++) { - ASSERT(frame->requiredTextureSize(plane) == m_textureSizes[plane]); - updateTexture(context, m_textures[plane], frame->requiredTextureSize(plane), textureFormat, frame->data(plane)); + Texture texture = m_textures[plane]; + ASSERT(frame->requiredTextureSize(plane) == texture.size); + updateTexture(context, texture.id, texture.size, textureFormat, frame->data(plane)); } m_dirtyRect.setSize(FloatSize()); @@ -146,7 +157,19 @@ void VideoLayerChromium::updateContentsIfDirty() m_provider->putCurrentFrame(frame); } -unsigned VideoLayerChromium::determineTextureFormat(VideoFrameChromium* frame) +void VideoLayerChromium::pushPropertiesTo(CCLayerImpl* layer) +{ + LayerChromium::pushPropertiesTo(layer); + + CCVideoLayerImpl* videoLayer = static_cast<CCVideoLayerImpl*>(layer); + videoLayer->setSkipsDraw(m_skipsDraw); + videoLayer->setFrameFormat(m_frameFormat); + for (size_t i = 0; i < 3; ++i) + videoLayer->setTexture(i, m_textures[i]); +} + + +unsigned VideoLayerChromium::determineTextureFormat(const VideoFrameChromium* frame) { switch (frame->format()) { case VideoFrameChromium::YV12: @@ -160,56 +183,68 @@ unsigned VideoLayerChromium::determineTextureFormat(VideoFrameChromium* frame) return GraphicsContext3D::INVALID_VALUE; } -bool VideoLayerChromium::allocateTexturesIfNeeded(GraphicsContext3D* context, VideoFrameChromium* frame, unsigned textureFormat) +bool VideoLayerChromium::allocateTexturesIfNeeded(GraphicsContext3D* context, const VideoFrameChromium* frame, unsigned textureFormat) { ASSERT(context); ASSERT(frame); for (unsigned plane = 0; plane < frame->planes(); plane++) { - IntSize planeTextureSize = frame->requiredTextureSize(plane); + IntSize requiredTextureSize = frame->requiredTextureSize(plane); + Texture texture = m_textures[plane]; // If the renderer cannot handle this large of a texture, return false. // FIXME: Remove this test when tiled layers are implemented. - if (!layerRenderer()->checkTextureSize(planeTextureSize)) + if (!layerRenderer()->checkTextureSize(requiredTextureSize)) return false; - if (!m_textures[plane]) - m_textures[plane] = layerRenderer()->createLayerTexture(); - - if (!planeTextureSize.isZero() && planeTextureSize != m_textureSizes[plane]) { - allocateTexture(context, m_textures[plane], planeTextureSize, textureFormat); - m_textureSizes[plane] = planeTextureSize; - int frameWidth = frame->width(plane); - int frameHeight = frame->height(plane); - // When there are dead pixels at the edge of the texture, decrease - // the frame width by 1 to prevent the rightmost pixels from - // interpolating with the dead pixels. - if (frame->hasPaddingBytes(plane)) - --frameWidth; - m_frameSizes[plane] = IntSize(frameWidth, frameHeight); + if (texture.isEmpty) { + texture.id = layerRenderer()->createLayerTexture(); + texture.ownedByLayerRenderer = true; + texture.isEmpty = false; + } + + if (!requiredTextureSize.isZero() && requiredTextureSize != texture.size) { + allocateTexture(context, texture.id, requiredTextureSize, textureFormat); + texture.size = requiredTextureSize; + texture.visibleSize = computeVisibleSize(frame, plane); } + m_textures[plane] = texture; } + return true; +} + +IntSize VideoLayerChromium::computeVisibleSize(const VideoFrameChromium* frame, unsigned plane) +{ + int visibleWidth = frame->width(plane); + int visibleHeight = frame->height(plane); + // When there are dead pixels at the edge of the texture, decrease + // the frame width by 1 to prevent the rightmost pixels from + // interpolating with the dead pixels. + if (frame->hasPaddingBytes(plane)) + --visibleWidth; + // In YV12, every 2x2 square of Y values corresponds to one U and // one V value. If we decrease the width of the UV plane, we must decrease the // width of the Y texture by 2 for proper alignment. This must happen // always, even if Y's texture does not have padding bytes. - if (frame->format() == VideoFrameChromium::YV12) { - int yPlaneOriginalWidth = frame->width(VideoFrameChromium::yPlane); - if (frame->hasPaddingBytes(VideoFrameChromium::uPlane)) - m_frameSizes[VideoFrameChromium::yPlane].setWidth(yPlaneOriginalWidth - 2); + if (plane == VideoFrameChromium::yPlane && frame->format() == VideoFrameChromium::YV12) { + if (frame->hasPaddingBytes(VideoFrameChromium::uPlane)) { + int originalWidth = frame->width(plane); + visibleWidth = originalWidth - 2; + } } - return true; + return IntSize(visibleWidth, visibleHeight); } -void VideoLayerChromium::allocateTexture(GraphicsContext3D* context, unsigned textureId, const IntSize& dimensions, unsigned textureFormat) +void VideoLayerChromium::allocateTexture(GraphicsContext3D* context, unsigned textureId, const IntSize& dimensions, unsigned textureFormat) const { GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId)); GLC(context, context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, textureFormat, dimensions.width(), dimensions.height(), 0, textureFormat, GraphicsContext3D::UNSIGNED_BYTE)); } -void VideoLayerChromium::updateTexture(GraphicsContext3D* context, unsigned textureId, const IntSize& dimensions, unsigned format, const void* data) +void VideoLayerChromium::updateTexture(GraphicsContext3D* context, unsigned textureId, const IntSize& dimensions, unsigned format, const void* data) const { ASSERT(context); GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId)); @@ -225,33 +260,6 @@ void VideoLayerChromium::updateTexture(GraphicsContext3D* context, unsigned text } } -void VideoLayerChromium::draw() -{ - if (m_skipsDraw) - return; - - ASSERT(layerRenderer()); - const RGBAProgram* rgbaProgram = layerRenderer()->videoLayerRGBAProgram(); - ASSERT(rgbaProgram && rgbaProgram->initialized()); - const YUVProgram* yuvProgram = layerRenderer()->videoLayerYUVProgram(); - ASSERT(yuvProgram && yuvProgram->initialized()); - - switch (m_frameFormat) { - case VideoFrameChromium::YV12: - case VideoFrameChromium::YV16: - drawYUV(yuvProgram); - break; - case VideoFrameChromium::RGBA: - drawRGBA(rgbaProgram); - break; - default: - // FIXME: Implement other paths. - notImplemented(); - break; - } - releaseCurrentFrame(); -} - void VideoLayerChromium::releaseCurrentFrame() { if (!m_currentFrame) @@ -262,86 +270,29 @@ void VideoLayerChromium::releaseCurrentFrame() resetFrameParameters(); } -void VideoLayerChromium::drawYUV(const VideoLayerChromium::YUVProgram* program) -{ - GraphicsContext3D* context = layerRendererContext(); - GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE1)); - GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textures[VideoFrameChromium::yPlane])); - GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE2)); - GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textures[VideoFrameChromium::uPlane])); - GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE3)); - GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textures[VideoFrameChromium::vPlane])); - - layerRenderer()->useShader(program->program()); - unsigned yFrameWidth = m_frameSizes[VideoFrameChromium::yPlane].width(); - unsigned yTextureWidth = m_textureSizes[VideoFrameChromium::yPlane].width(); - // Arbitrarily take the u sizes because u and v dimensions are identical. - unsigned uvFrameWidth = m_frameSizes[VideoFrameChromium::uPlane].width(); - unsigned uvTextureWidth = m_textureSizes[VideoFrameChromium::uPlane].width(); - - float yWidthScaleFactor = static_cast<float>(yFrameWidth) / yTextureWidth; - float uvWidthScaleFactor = static_cast<float>(uvFrameWidth) / uvTextureWidth; - GLC(context, context->uniform1f(program->vertexShader().yWidthScaleFactorLocation(), yWidthScaleFactor)); - GLC(context, context->uniform1f(program->vertexShader().uvWidthScaleFactorLocation(), uvWidthScaleFactor)); - - GLC(context, context->uniform1i(program->fragmentShader().yTextureLocation(), 1)); - GLC(context, context->uniform1i(program->fragmentShader().uTextureLocation(), 2)); - GLC(context, context->uniform1i(program->fragmentShader().vTextureLocation(), 3)); - - // This value of 0.5 maps to 128. It is used in the YUV to RGB conversion - // formula to turn unsigned u and v values to signed u and v values. - // This is loaded as a uniform because certain drivers have problems - // reading literal float values. - GLC(context, context->uniform1f(program->fragmentShader().signAdjLocation(), 0.5)); - - GLC(context, context->uniformMatrix3fv(program->fragmentShader().ccMatrixLocation(), 0, const_cast<float*>(yuv2RGB), 1)); - - drawTexturedQuad(context, layerRenderer()->projectionMatrix(), ccLayerImpl()->drawTransform(), - bounds().width(), bounds().height(), ccLayerImpl()->drawOpacity(), - program->vertexShader().matrixLocation(), - program->fragmentShader().alphaLocation()); - - // Reset active texture back to texture 0. - GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); -} - -void VideoLayerChromium::drawRGBA(const VideoLayerChromium::RGBAProgram* program) -{ - GraphicsContext3D* context = layerRendererContext(); - GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); - GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textures[VideoFrameChromium::rgbPlane])); - - layerRenderer()->useShader(program->program()); - unsigned frameWidth = m_frameSizes[VideoFrameChromium::rgbPlane].width(); - unsigned textureWidth = m_textureSizes[VideoFrameChromium::rgbPlane].width(); - float widthScaleFactor = static_cast<float>(frameWidth) / textureWidth; - GLC(context, context->uniform4f(program->vertexShader().texTransformLocation(), 0, 0, widthScaleFactor, 1)); - - GLC(context, context->uniform1i(program->fragmentShader().samplerLocation(), 0)); - - drawTexturedQuad(context, layerRenderer()->projectionMatrix(), ccLayerImpl()->drawTransform(), - bounds().width(), bounds().height(), ccLayerImpl()->drawOpacity(), - program->vertexShader().matrixLocation(), - program->fragmentShader().alphaLocation()); -} - void VideoLayerChromium::resetFrameParameters() { + deleteTexturesInUse(); for (unsigned plane = 0; plane < VideoFrameChromium::maxPlanes; plane++) { - m_textures[plane] = 0; - m_textureSizes[plane] = IntSize(); - m_frameSizes[plane] = IntSize(); + m_textures[plane].id = 0; + m_textures[plane].size = IntSize(); + m_textures[plane].visibleSize = IntSize(); + m_textures[plane].ownedByLayerRenderer = false; + m_textures[plane].isEmpty = true; } } void VideoLayerChromium::saveCurrentFrame(VideoFrameChromium* frame) { ASSERT(!m_currentFrame); + deleteTexturesInUse(); m_currentFrame = frame; for (unsigned plane = 0; plane < frame->planes(); plane++) { - m_textures[plane] = frame->texture(plane); - m_textureSizes[plane] = frame->requiredTextureSize(plane); - m_frameSizes[plane] = m_textureSizes[plane]; + m_textures[plane].id = frame->texture(plane); + m_textures[plane].size = frame->requiredTextureSize(plane); + m_textures[plane].visibleSize = computeVisibleSize(frame, plane); + m_textures[plane].ownedByLayerRenderer = false; + m_textures[plane].isEmpty = false; } } diff --git a/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.h b/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.h index 2170e13..ef08bd8 100644 --- a/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.h @@ -42,19 +42,28 @@ namespace WebCore { // A Layer that contains a Video element. class VideoLayerChromium : public LayerChromium { public: + struct Texture { + unsigned id; + IntSize size; + IntSize visibleSize; + bool ownedByLayerRenderer; + bool isEmpty; + }; + static PassRefPtr<VideoLayerChromium> create(GraphicsLayerChromium* owner = 0, VideoFrameProvider* = 0); virtual ~VideoLayerChromium(); - virtual void updateContentsIfDirty(); + + virtual PassRefPtr<CCLayerImpl> createCCLayerImpl(); + + virtual void updateCompositorResources(); virtual bool drawsContent() const { return true; } - virtual void draw(); // This function is called by VideoFrameProvider. When this method is called // putCurrentFrame() must be called to return the frame currently held. void releaseCurrentFrame(); - typedef ProgramBinding<VertexShaderPosTexTransform, FragmentShaderRGBATexFlipAlpha> RGBAProgram; - typedef ProgramBinding<VertexShaderPosTexYUVStretch, FragmentShaderYUVVideo> YUVProgram; + virtual void pushPropertiesTo(CCLayerImpl*); protected: virtual void cleanupResources(); @@ -63,27 +72,27 @@ protected: private: VideoLayerChromium(GraphicsLayerChromium* owner, VideoFrameProvider*); - static unsigned determineTextureFormat(VideoFrameChromium*); - bool allocateTexturesIfNeeded(GraphicsContext3D*, VideoFrameChromium*, unsigned textureFormat); - void updateYUVContents(GraphicsContext3D*, const VideoFrameChromium*); - void updateRGBAContents(GraphicsContext3D*, const VideoFrameChromium*); - void allocateTexture(GraphicsContext3D*, unsigned textureId, const IntSize& dimensions, unsigned textureFormat); - void updateTexture(GraphicsContext3D*, unsigned textureId, const IntSize& dimensions, unsigned textureFormat, const void* data); - void drawYUV(const YUVProgram*); - void drawRGBA(const RGBAProgram*); + static unsigned determineTextureFormat(const VideoFrameChromium*); + static IntSize computeVisibleSize(const VideoFrameChromium*, unsigned plane); + void deleteTexturesInUse(); + + bool allocateTexturesIfNeeded(GraphicsContext3D*, const VideoFrameChromium*, unsigned textureFormat); + void allocateTexture(GraphicsContext3D*, unsigned textureId, const IntSize& dimensions, unsigned textureFormat) const; + + void updateTexture(GraphicsContext3D*, unsigned textureId, const IntSize& dimensions, unsigned textureFormat, const void* data) const; + void resetFrameParameters(); void saveCurrentFrame(VideoFrameChromium*); - static const float yuv2RGB[9]; - bool m_skipsDraw; VideoFrameChromium::Format m_frameFormat; VideoFrameProvider* m_provider; - VideoFrameChromium* m_currentFrame; - unsigned m_textures[3]; - IntSize m_textureSizes[3]; - IntSize m_frameSizes[3]; + Texture m_textures[3]; + + // This will be null for the entire duration of video playback if hardware + // decoding is not being used. + VideoFrameChromium* m_currentFrame; }; } diff --git a/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp index e83d045..652e752 100644 --- a/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp @@ -47,10 +47,11 @@ PassRefPtr<WebGLLayerChromium> WebGLLayerChromium::create(GraphicsLayerChromium* WebGLLayerChromium::WebGLLayerChromium(GraphicsLayerChromium* owner) : CanvasLayerChromium(owner) , m_context(0) + , m_textureUpdated(false) { } -void WebGLLayerChromium::updateContentsIfDirty() +void WebGLLayerChromium::updateCompositorResources() { if (!m_contentsDirty) return; @@ -68,19 +69,28 @@ void WebGLLayerChromium::updateContentsIfDirty() m_textureChanged = false; } // Update the contents of the texture used by the compositor. - if (m_contentsDirty) { + if (m_contentsDirty && m_textureUpdated) { m_context->prepareTexture(); + m_context->markLayerComposited(); m_contentsDirty = false; + m_textureUpdated = false; } } +void WebGLLayerChromium::setTextureUpdated() +{ + m_textureUpdated = true; +} + void WebGLLayerChromium::setContext(const GraphicsContext3D* context) { m_context = const_cast<GraphicsContext3D*>(context); unsigned int textureId = m_context->platformTexture(); - if (textureId != m_textureId) + if (textureId != m_textureId) { m_textureChanged = true; + m_textureUpdated = true; + } m_textureId = textureId; m_premultipliedAlpha = m_context->getContextAttributes().premultipliedAlpha; } diff --git a/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.h b/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.h index 70be876..33db730 100644 --- a/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.h @@ -45,7 +45,8 @@ class WebGLLayerChromium : public CanvasLayerChromium { public: static PassRefPtr<WebGLLayerChromium> create(GraphicsLayerChromium* owner = 0); virtual bool drawsContent() const { return m_context; } - virtual void updateContentsIfDirty(); + virtual void updateCompositorResources(); + void setTextureUpdated(); void setContext(const GraphicsContext3D* context); @@ -55,6 +56,7 @@ protected: private: explicit WebGLLayerChromium(GraphicsLayerChromium* owner); GraphicsContext3D* m_context; + bool m_textureUpdated; }; } diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.cpp new file mode 100644 index 0000000..649d049 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.cpp @@ -0,0 +1,80 @@ +/* + * 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" + +#if USE(ACCELERATED_COMPOSITING) + +#include "cc/CCCanvasLayerImpl.h" + +#include "CanvasLayerChromium.h" +#include "GraphicsContext3D.h" +#include "LayerRendererChromium.h" +#include <wtf/text/WTFString.h> + +namespace WebCore { + +CCCanvasLayerImpl::CCCanvasLayerImpl(LayerChromium* owner) + : CCLayerImpl(owner) + , m_textureId(0) + , m_premultipliedAlpha(true) +{ +} + +CCCanvasLayerImpl::~CCCanvasLayerImpl() +{ +} + +void CCCanvasLayerImpl::draw() +{ + ASSERT(layerRenderer()); + const CCCanvasLayerImpl::Program* program = layerRenderer()->canvasLayerProgram(); + ASSERT(program && program->initialized()); + GraphicsContext3D* context = layerRenderer()->context(); + GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); + GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textureId)); + GC3Denum sfactor = m_premultipliedAlpha ? GraphicsContext3D::ONE : GraphicsContext3D::SRC_ALPHA; + GLC(context, context->blendFunc(sfactor, GraphicsContext3D::ONE_MINUS_SRC_ALPHA)); + layerRenderer()->useShader(program->program()); + GLC(context, context->uniform1i(program->fragmentShader().samplerLocation(), 0)); + LayerChromium::drawTexturedQuad(context, layerRenderer()->projectionMatrix(), drawTransform(), + bounds().width(), bounds().height(), drawOpacity(), + program->vertexShader().matrixLocation(), + program->fragmentShader().alphaLocation()); + +} + + +void CCCanvasLayerImpl::dumpLayerProperties(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "canvas layer texture id: " << m_textureId << " premultiplied: " << m_premultipliedAlpha << "\n"; + CCLayerImpl::dumpLayerProperties(ts, indent); +} + +} + +#endif // USE(ACCELERATED_COMPOSITING) + diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.h b/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.h new file mode 100644 index 0000000..8cbf8d1 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.h @@ -0,0 +1,61 @@ +/* + * 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 CCCanvasLayerImpl_h +#define CCCanvasLayerImpl_h + +#include "ProgramBinding.h" +#include "ShaderChromium.h" +#include "cc/CCLayerImpl.h" + +namespace WebCore { + +class CCCanvasLayerImpl : public CCLayerImpl { +public: + static PassRefPtr<CCCanvasLayerImpl> create(LayerChromium* owner) + { + return adoptRef(new CCCanvasLayerImpl(owner)); + } + virtual ~CCCanvasLayerImpl(); + + typedef ProgramBinding<VertexShaderPosTex, FragmentShaderRGBATexFlipAlpha> Program; + + virtual void draw(); + + virtual void dumpLayerProperties(TextStream&, int indent) const; + + void setTextureId(unsigned id) { m_textureId = id; } + void setPremultipliedAlpha(bool premultipliedAlpha) { m_premultipliedAlpha = premultipliedAlpha; } +private: + explicit CCCanvasLayerImpl(LayerChromium*); + + unsigned m_textureId; + bool m_premultipliedAlpha; +}; + +} + +#endif // CCCanvasLayerImpl_h + diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp index 604ef61..404944b 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp @@ -66,8 +66,8 @@ void CCHeadsUpDisplay::draw() // Use a fullscreen texture only if we need to... IntSize hudSize; if (m_showPlatformLayerTree) { - hudSize.setWidth(min(2048, m_layerRenderer->visibleRectSize().width())); - hudSize.setHeight(min(2048, m_layerRenderer->visibleRectSize().height())); + hudSize.setWidth(min(2048, m_layerRenderer->viewportSize().width())); + hudSize.setHeight(min(2048, m_layerRenderer->viewportSize().height())); } else { hudSize.setWidth(512); hudSize.setHeight(128); diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.h b/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.h index dbac22a..d56f8ab 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.h @@ -53,7 +53,7 @@ public: void setShowPlatformLayerTree(bool enable) { m_showPlatformLayerTree = enable; } bool showPlatformLayerTree() const { return m_showPlatformLayerTree; } - bool enabled() const { return true || m_showPlatformLayerTree || m_showFPSCounter; } + bool enabled() const { return m_showPlatformLayerTree || m_showFPSCounter; } void draw(); private: diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.cpp index a0ad0fb..9411e5a 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.cpp @@ -62,13 +62,18 @@ namespace WebCore { CCLayerImpl::CCLayerImpl(LayerChromium* owner) : m_owner(owner) + , m_anchorPoint(0.5, 0.5) + , m_anchorPointZ(0) + , m_doubleSided(true) + , m_masksToBounds(false) + , m_opacity(1.0) + , m_preserves3D(false) #ifndef NDEBUG , m_debugID(owner->debugID()) #endif , m_targetRenderSurface(0) , m_drawDepth(0) , m_drawOpacity(0) - , m_doubleSided(true) , m_debugBorderColor(0, 0, 0, 0) , m_debugBorderWidth(0) , m_renderSurface(0) @@ -107,7 +112,18 @@ RenderSurfaceChromium* CCLayerImpl::createRenderSurface() return m_renderSurface.get(); } -// These belong on CCLayerImpl, but should be subclased by each type and not defer to the LayerChromium subtypes. +bool CCLayerImpl::descendantsDrawsContent() +{ + const Vector<RefPtr<LayerChromium> >& sublayers = m_owner->getSublayers(); + for (size_t i = 0; i < sublayers.size(); ++i) { + sublayers[i]->createCCLayerImplIfNeeded(); + if (sublayers[i]->ccLayerImpl()->drawsContent() || sublayers[i]->ccLayerImpl()->descendantsDrawsContent()) + return true; + } + return false; +} + +// 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(); @@ -118,6 +134,11 @@ void CCLayerImpl::draw() return m_owner->draw(); } +void CCLayerImpl::updateCompositorResources() +{ + return m_owner->updateCompositorResources(); +} + void CCLayerImpl::unreserveContentsTexture() { m_owner->unreserveContentsTexture(); @@ -167,7 +188,7 @@ void CCLayerImpl::drawDebugBorder() GLC(context, context->drawElements(GraphicsContext3D::LINE_LOOP, 4, GraphicsContext3D::UNSIGNED_SHORT, 6 * sizeof(unsigned short))); } -static void writeIndent(TextStream& ts, int indent) +void CCLayerImpl::writeIndent(TextStream& ts, int indent) { for (int i = 0; i != indent; ++i) ts << " "; diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.h b/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.h index 6892976..96c4f1b 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.h @@ -49,7 +49,7 @@ public: return adoptRef(new CCLayerImpl(owner)); } // When this class gets subclasses, remember to add 'virtual' here. - ~CCLayerImpl(); + virtual ~CCLayerImpl(); #ifndef NDEBUG int debugID() const { return m_debugID; } @@ -59,13 +59,43 @@ public: CCLayerImpl* maskLayer() const; CCLayerImpl* replicaLayer() const; - void draw(); - bool drawsContent() const; + virtual void draw(); + virtual void updateCompositorResources(); void unreserveContentsTexture(); void bindContentsTexture(); + // Returns true if this layer has content to draw. + virtual bool drawsContent() const; + + // Returns true if any of the layer's descendants has content to draw. + bool descendantsDrawsContent(); + void cleanupResources(); + void setAnchorPoint(const FloatPoint& anchorPoint) { m_anchorPoint = anchorPoint; } + const FloatPoint& anchorPoint() const { return m_anchorPoint; } + + void setAnchorPointZ(float anchorPointZ) { m_anchorPointZ = anchorPointZ; } + float anchorPointZ() const { return m_anchorPointZ; } + + void setMasksToBounds(bool masksToBounds) { m_masksToBounds = masksToBounds; } + bool masksToBounds() const { return m_masksToBounds; } + + void setOpacity(float opacity) { m_opacity = opacity; } + float opacity() const { return m_opacity; } + + void setPosition(const FloatPoint& position) { m_position = position; } + const FloatPoint& position() const { return m_position; } + + void setPreserves3D(bool preserves3D) { m_preserves3D = preserves3D; } + bool preserves3D() const { return m_preserves3D; } + + void setSublayerTransform(const TransformationMatrix& sublayerTransform) { m_sublayerTransform = sublayerTransform; } + const TransformationMatrix& sublayerTransform() const { return m_sublayerTransform; } + + void setTransform(const TransformationMatrix& transform) { m_transform = transform; } + const TransformationMatrix& transform() const { return m_transform; } + void setName(const String& name) { m_name = name; } const String& name() const { return m_name; } @@ -108,11 +138,30 @@ public: virtual void dumpLayerProperties(TextStream&, int indent) const; -private: +protected: // For now, CCLayers are owned directly by a LayerChromium. LayerChromium* m_owner; explicit CCLayerImpl(LayerChromium*); + static void writeIndent(TextStream&, int indent); + +private: + // Properties synchronized from the associated LayerChromium. + FloatPoint m_anchorPoint; + float m_anchorPointZ; + IntSize m_bounds; + + // Whether the "back" of this layer should draw. + bool m_doubleSided; + + bool m_masksToBounds; + float m_opacity; + FloatPoint m_position; + bool m_preserves3D; + TransformationMatrix m_sublayerTransform; + TransformationMatrix m_transform; + + // Properties owned exclusively by this CCLayerImpl. // Debugging. #ifndef NDEBUG int m_debugID; @@ -131,17 +180,12 @@ private: float m_drawDepth; float m_drawOpacity; - // Whether the "back" of this layer should draw. - bool m_doubleSided; - // Debug borders. Color m_debugBorderColor; float m_debugBorderWidth; TransformationMatrix m_drawTransform; - IntSize m_bounds; - // The scissor rectangle that should be used when this layer is drawn. // Inherited by the parent layer and further restricted if this layer masks // to bounds. diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.cpp new file mode 100644 index 0000000..4aef639 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.cpp @@ -0,0 +1,84 @@ +/* + * 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" + +#if USE(ACCELERATED_COMPOSITING) + +#include "cc/CCPluginLayerImpl.h" + +#include "GraphicsContext3D.h" +#include "LayerRendererChromium.h" +#include "PluginLayerChromium.h" +#include <wtf/text/WTFString.h> + +namespace WebCore { + +CCPluginLayerImpl::CCPluginLayerImpl(LayerChromium* owner) + : CCLayerImpl(owner) + , m_textureId(0) +{ +} + +CCPluginLayerImpl::~CCPluginLayerImpl() +{ +} + +void CCPluginLayerImpl::draw() +{ + ASSERT(layerRenderer()); + const CCPluginLayerImpl::Program* program = layerRenderer()->pluginLayerProgram(); + ASSERT(program && program->initialized()); + GraphicsContext3D* context = layerRenderer()->context(); + GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); + GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textureId)); + + // FIXME: setting the texture parameters every time is redundant. Move this code somewhere + // where it will only happen once per texture. + GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR)); + GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR)); + GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE)); + GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE)); + + layerRenderer()->useShader(program->program()); + GLC(context, context->uniform1i(program->fragmentShader().samplerLocation(), 0)); + LayerChromium::drawTexturedQuad(context, layerRenderer()->projectionMatrix(), drawTransform(), + bounds().width(), bounds().height(), drawOpacity(), + program->vertexShader().matrixLocation(), + program->fragmentShader().alphaLocation()); +} + + +void CCPluginLayerImpl::dumpLayerProperties(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "plugin layer texture id: " << m_textureId << "\n"; + CCLayerImpl::dumpLayerProperties(ts, indent); +} + +} + +#endif // USE(ACCELERATED_COMPOSITING) + diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.h b/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.h new file mode 100644 index 0000000..65eb5b7 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.h @@ -0,0 +1,60 @@ +/* + * 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 CCPluginLayerImpl_h +#define CCPluginLayerImpl_h + +#include "ProgramBinding.h" +#include "ShaderChromium.h" +#include "cc/CCLayerImpl.h" + +namespace WebCore { + +class CCPluginLayerImpl : public CCLayerImpl { +public: + static PassRefPtr<CCPluginLayerImpl> create(LayerChromium* owner) + { + return adoptRef(new CCPluginLayerImpl(owner)); + } + virtual ~CCPluginLayerImpl(); + + typedef ProgramBinding<VertexShaderPosTex, FragmentShaderRGBATexFlipAlpha> Program; + + virtual void draw(); + + virtual void dumpLayerProperties(TextStream&, int indent) const; + + void setTextureId(unsigned id) { m_textureId = id; } + +private: + explicit CCPluginLayerImpl(LayerChromium*); + + unsigned m_textureId; +}; + +} + +#endif // CCPluginLayerImpl_h + diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.cpp new file mode 100644 index 0000000..eb3612b --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.cpp @@ -0,0 +1,173 @@ +/* + * 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" + +#if USE(ACCELERATED_COMPOSITING) + +#include "cc/CCVideoLayerImpl.h" + +#include "GraphicsContext3D.h" +#include "LayerRendererChromium.h" +#include "NotImplemented.h" +#include "VideoLayerChromium.h" +#include <wtf/text/WTFString.h> + +namespace WebCore { + +// These values are magic numbers that are used in the transformation +// from YUV to RGB color values. +// They are taken from the following webpage: +// http://www.fourcc.org/fccyvrgb.php +const float CCVideoLayerImpl::yuv2RGB[9] = { + 1.164f, 1.164f, 1.164f, + 0.f, -.391f, 2.018f, + 1.596f, -.813f, 0.f, +}; + +// These values map to 16, 128, and 128 respectively, and are computed +// as a fraction over 256 (e.g. 16 / 256 = 0.0625). +// They are used in the YUV to RGBA conversion formula: +// Y - 16 : Gives 16 values of head and footroom for overshooting +// U - 128 : Turns unsigned U into signed U [-128,127] +// V - 128 : Turns unsigned V into signed V [-128,127] +const float CCVideoLayerImpl::yuvAdjust[3] = { + -0.0625f, + -0.5f, + -0.5f, +}; + +CCVideoLayerImpl::CCVideoLayerImpl(LayerChromium* owner) + : CCLayerImpl(owner) +{ +} + +CCVideoLayerImpl::~CCVideoLayerImpl() +{ + cleanupResources(); +} + +void CCVideoLayerImpl::setTexture(size_t i, VideoLayerChromium::Texture texture) +{ + ASSERT(i < 3); + m_textures[i] = texture; +} + +void CCVideoLayerImpl::draw() +{ + if (m_skipsDraw) + return; + + ASSERT(layerRenderer()); + const RGBAProgram* rgbaProgram = layerRenderer()->videoLayerRGBAProgram(); + ASSERT(rgbaProgram && rgbaProgram->initialized()); + const YUVProgram* yuvProgram = layerRenderer()->videoLayerYUVProgram(); + ASSERT(yuvProgram && yuvProgram->initialized()); + + switch (m_frameFormat) { + case VideoFrameChromium::YV12: + case VideoFrameChromium::YV16: + drawYUV(yuvProgram); + break; + case VideoFrameChromium::RGBA: + drawRGBA(rgbaProgram); + break; + default: + // FIXME: Implement other paths. + notImplemented(); + break; + } +} + +void CCVideoLayerImpl::drawYUV(const CCVideoLayerImpl::YUVProgram* program) const +{ + GraphicsContext3D* context = layerRenderer()->context(); + VideoLayerChromium::Texture yTexture = m_textures[VideoFrameChromium::yPlane]; + VideoLayerChromium::Texture uTexture = m_textures[VideoFrameChromium::uPlane]; + VideoLayerChromium::Texture vTexture = m_textures[VideoFrameChromium::vPlane]; + + GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE1)); + GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, yTexture.id)); + GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE2)); + GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, uTexture.id)); + GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE3)); + GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, vTexture.id)); + + layerRenderer()->useShader(program->program()); + + float yWidthScaleFactor = static_cast<float>(yTexture.visibleSize.width()) / yTexture.size.width(); + // Arbitrarily take the u sizes because u and v dimensions are identical. + float uvWidthScaleFactor = static_cast<float>(uTexture.visibleSize.width()) / uTexture.size.width(); + GLC(context, context->uniform1f(program->vertexShader().yWidthScaleFactorLocation(), yWidthScaleFactor)); + GLC(context, context->uniform1f(program->vertexShader().uvWidthScaleFactorLocation(), uvWidthScaleFactor)); + + GLC(context, context->uniform1i(program->fragmentShader().yTextureLocation(), 1)); + GLC(context, context->uniform1i(program->fragmentShader().uTextureLocation(), 2)); + GLC(context, context->uniform1i(program->fragmentShader().vTextureLocation(), 3)); + + GLC(context, context->uniformMatrix3fv(program->fragmentShader().ccMatrixLocation(), 0, const_cast<float*>(yuv2RGB), 1)); + GLC(context, context->uniform3fv(program->fragmentShader().yuvAdjLocation(), const_cast<float*>(yuvAdjust), 1)); + + LayerChromium::drawTexturedQuad(context, layerRenderer()->projectionMatrix(), drawTransform(), + bounds().width(), bounds().height(), drawOpacity(), + program->vertexShader().matrixLocation(), + program->fragmentShader().alphaLocation()); + + // Reset active texture back to texture 0. + GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); +} + +void CCVideoLayerImpl::drawRGBA(const CCVideoLayerImpl::RGBAProgram* program) const +{ + GraphicsContext3D* context = layerRenderer()->context(); + VideoLayerChromium::Texture texture = m_textures[VideoFrameChromium::rgbPlane]; + + GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); + GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, texture.id)); + + layerRenderer()->useShader(program->program()); + float widthScaleFactor = static_cast<float>(texture.visibleSize.width()) / texture.size.width(); + GLC(context, context->uniform4f(program->vertexShader().texTransformLocation(), 0, 0, widthScaleFactor, 1)); + + GLC(context, context->uniform1i(program->fragmentShader().samplerLocation(), 0)); + + LayerChromium::drawTexturedQuad(context, layerRenderer()->projectionMatrix(), drawTransform(), + bounds().width(), bounds().height(), drawOpacity(), + program->vertexShader().matrixLocation(), + program->fragmentShader().alphaLocation()); +} + + +void CCVideoLayerImpl::dumpLayerProperties(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "video layer\n"; + CCLayerImpl::dumpLayerProperties(ts, indent); +} + +} + +#endif // USE(ACCELERATED_COMPOSITING) + diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.h b/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.h new file mode 100644 index 0000000..62f8778 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.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 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 CCVideoLayerImpl_h +#define CCVideoLayerImpl_h + +#include "ProgramBinding.h" +#include "ShaderChromium.h" +#include "VideoFrameChromium.h" +#include "VideoLayerChromium.h" +#include "cc/CCLayerImpl.h" + +namespace WebCore { + +class VideoFrameProvider; + +class CCVideoLayerImpl : public CCLayerImpl { +public: + static PassRefPtr<CCVideoLayerImpl> create(LayerChromium* owner) + { + return adoptRef(new CCVideoLayerImpl(owner)); + } + virtual ~CCVideoLayerImpl(); + + typedef ProgramBinding<VertexShaderPosTexTransform, FragmentShaderRGBATexFlipAlpha> RGBAProgram; + typedef ProgramBinding<VertexShaderPosTexYUVStretch, FragmentShaderYUVVideo> YUVProgram; + + virtual void draw(); + + virtual void dumpLayerProperties(TextStream&, int indent) const; + + void setSkipsDraw(bool skipsDraw) { m_skipsDraw = skipsDraw; } + void setFrameFormat(VideoFrameChromium::Format format) { m_frameFormat = format; } + void setTexture(size_t, VideoLayerChromium::Texture); + +private: + explicit CCVideoLayerImpl(LayerChromium*); + + void drawYUV(const YUVProgram*) const; + void drawRGBA(const RGBAProgram*) const; + + static const float yuv2RGB[9]; + static const float yuvAdjust[3]; + + bool m_skipsDraw; + VideoFrameChromium::Format m_frameFormat; + VideoLayerChromium::Texture m_textures[3]; +}; + +} + +#endif // CCVideoLayerImpl_h + diff --git a/Source/WebCore/platform/graphics/cocoa/FontPlatformData.h b/Source/WebCore/platform/graphics/cocoa/FontPlatformData.h deleted file mode 100644 index ca38029..0000000 --- a/Source/WebCore/platform/graphics/cocoa/FontPlatformData.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * This file is part of the internal font implementation. - * It should not be included by source files outside of it. - * - * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#ifndef FontPlatformData_h -#define FontPlatformData_h - -#include "FontOrientation.h" -#include "FontWidthVariant.h" -#include <wtf/text/StringImpl.h> - -#ifdef __OBJC__ -@class NSFont; -#else -class NSFont; -#endif - -typedef struct CGFont* CGFontRef; -#ifndef BUILDING_ON_TIGER -typedef const struct __CTFont* CTFontRef; -#endif - -#include <CoreFoundation/CFBase.h> -#include <objc/objc-auto.h> -#include <wtf/Forward.h> -#include <wtf/RetainPtr.h> - -#if PLATFORM(CHROMIUM) && OS(DARWIN) -#include "CrossProcessFontLoading.h" -#endif - - -typedef UInt32 ATSUFontID; -typedef UInt32 ATSFontRef; - -namespace WebCore { - -#ifndef BUILDING_ON_TIGER -inline CTFontRef toCTFontRef(NSFont *nsFont) { return reinterpret_cast<CTFontRef>(nsFont); } -#endif - -class FontPlatformData { - public: - FontPlatformData(float size, bool syntheticBold, bool syntheticOblique, FontOrientation orientation = Horizontal, FontWidthVariant widthVariant = RegularWidth) - : m_syntheticBold(syntheticBold) - , m_syntheticOblique(syntheticOblique) - , m_orientation(orientation) - , m_size(size) - , m_widthVariant(widthVariant) - , m_font(0) -#ifdef BUILDING_ON_TIGER - , m_cgFont(0) -#endif - , m_isColorBitmapFont(false) - { - } - - FontPlatformData(NSFont*, float size, bool syntheticBold = false, bool syntheticOblique = false, FontOrientation = Horizontal, FontWidthVariant = RegularWidth); - - FontPlatformData(CGFontRef cgFont, float size, bool syntheticBold, bool syntheticOblique, FontOrientation orientation, FontWidthVariant widthVariant) - : m_syntheticBold(syntheticBold) - , m_syntheticOblique(syntheticOblique) - , m_orientation(orientation) - , m_size(size) - , m_widthVariant(widthVariant) - , m_font(0) - , m_cgFont(cgFont) - , m_isColorBitmapFont(false) - { - } - - FontPlatformData(const FontPlatformData&); - - ~FontPlatformData(); - - FontPlatformData(WTF::HashTableDeletedValueType) : m_font(hashTableDeletedFontValue()) { } - bool isHashTableDeletedValue() const { return m_font == hashTableDeletedFontValue(); } - - float size() const { return m_size; } - bool syntheticBold() const { return m_syntheticBold; } - bool syntheticOblique() const { return m_syntheticOblique; } - FontOrientation orientation() const { return m_orientation; } - FontWidthVariant widthVariant() const { return m_widthVariant; } - - bool m_syntheticBold; - bool m_syntheticOblique; - FontOrientation m_orientation; - - float m_size; - - FontWidthVariant m_widthVariant; - - unsigned hash() const - { - ASSERT(m_font != 0 || m_cgFont == 0); - uintptr_t hashCodes[3] = { (uintptr_t)m_font, m_widthVariant, m_orientation << 2 | m_syntheticBold << 1 | m_syntheticOblique }; - return WTF::StringHasher::createBlobHash<sizeof(hashCodes)>(hashCodes); - } - - const FontPlatformData& operator=(const FontPlatformData& f); - - bool operator==(const FontPlatformData& other) const - { - return m_font == other.m_font && m_syntheticBold == other.m_syntheticBold && m_syntheticOblique == other.m_syntheticOblique && - m_cgFont == other.m_cgFont && m_size == other.m_size && m_orientation == other.m_orientation && m_widthVariant == other.m_widthVariant; - } - - NSFont *font() const { return m_font; } - void setFont(NSFont *font); - - CTFontRef ctFont() const; - - bool roundsGlyphAdvances() const; - bool allowsLigatures() const; - bool isColorBitmapFont() const { return m_isColorBitmapFont; } - -#ifndef BUILDING_ON_TIGER - CGFontRef cgFont() const { return m_cgFont.get(); } -#else - CGFontRef cgFont() const { return m_cgFont; } -#endif - -#ifndef NDEBUG - String description() const; -#endif - -private: - static NSFont *hashTableDeletedFontValue() { return reinterpret_cast<NSFont *>(-1); } - - // Load various data about the font specified by |nsFont| with the size fontSize into the following output paramters: - // Note: Callers should always take into account that for the Chromium port, |outNSFont| isn't necessarily the same - // font as |nsFont|. This because the sandbox may block loading of the original font. - // * outNSFont - The font that was actually loaded, for the Chromium port this may be different than nsFont. - // The caller is responsible for calling CFRelease() on this parameter when done with it. - // * cgFont - CGFontRef representing the input font at the specified point size. - void loadFont(NSFont* nsFont, float fontSize, NSFont*& outNSFont, CGFontRef& cgFont); - - NSFont *m_font; - -#ifndef BUILDING_ON_TIGER - RetainPtr<CGFontRef> m_cgFont; -#else - CGFontRef m_cgFont; // It is not necessary to refcount this, since either an NSFont owns it or some CachedFont has it referenced. -#endif - - mutable RetainPtr<CTFontRef> m_CTFont; - - bool m_isColorBitmapFont; - -#if PLATFORM(CHROMIUM) && OS(DARWIN) - RefPtr<MemoryActivatedFont> m_inMemoryFont; -#endif -}; - -} // namespace WebCore - -#endif diff --git a/Source/WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm b/Source/WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm index b40f698..6a17707 100644 --- a/Source/WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm +++ b/Source/WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm @@ -45,9 +45,12 @@ void FontPlatformData::loadFont(NSFont* nsFont, float, NSFont*& outNSFont, CGFon } #endif // PLATFORM(MAC) -FontPlatformData::FontPlatformData(NSFont *nsFont, float size, bool syntheticBold, bool syntheticOblique, FontOrientation orientation, FontWidthVariant widthVariant) +FontPlatformData::FontPlatformData(NSFont *nsFont, float size, bool syntheticBold, bool syntheticOblique, FontOrientation orientation, + TextOrientation textOrientation, FontWidthVariant widthVariant) : m_syntheticBold(syntheticBold) , m_syntheticOblique(syntheticOblique) + , m_orientation(orientation) + , m_textOrientation(textOrientation) , m_size(size) , m_widthVariant(widthVariant) , m_font(nsFont) @@ -64,8 +67,6 @@ FontPlatformData::FontPlatformData(NSFont *nsFont, float size, bool syntheticBol CGFontRef cgFont = 0; loadFont(nsFont, size, m_font, cgFont); - m_orientation = orientation; - if (m_font) CFRetain(m_font); @@ -76,35 +77,26 @@ FontPlatformData::FontPlatformData(NSFont *nsFont, float size, bool syntheticBol #endif } -FontPlatformData::FontPlatformData(const FontPlatformData& f) +FontPlatformData:: ~FontPlatformData() +{ + if (m_font && m_font != reinterpret_cast<NSFont *>(-1)) + CFRelease(m_font); +} + +void FontPlatformData::platformDataInit(const FontPlatformData& f) { m_font = f.m_font && f.m_font != reinterpret_cast<NSFont *>(-1) ? const_cast<NSFont *>(static_cast<const NSFont *>(CFRetain(f.m_font))) : f.m_font; - m_syntheticBold = f.m_syntheticBold; - m_syntheticOblique = f.m_syntheticOblique; - m_size = f.m_size; - m_widthVariant = f.m_widthVariant; m_cgFont = f.m_cgFont; - m_isColorBitmapFont = f.m_isColorBitmapFont; - m_orientation = f.m_orientation; m_CTFont = f.m_CTFont; + #if PLATFORM(CHROMIUM) && OS(DARWIN) m_inMemoryFont = f.m_inMemoryFont; #endif } -FontPlatformData:: ~FontPlatformData() +const FontPlatformData& FontPlatformData::platformDataAssign(const FontPlatformData& f) { - if (m_font && m_font != reinterpret_cast<NSFont *>(-1)) - CFRelease(m_font); -} - -const FontPlatformData& FontPlatformData::operator=(const FontPlatformData& f) -{ - m_syntheticBold = f.m_syntheticBold; - m_syntheticOblique = f.m_syntheticOblique; - m_size = f.m_size; - m_widthVariant = f.m_widthVariant; m_cgFont = f.m_cgFont; if (m_font == f.m_font) return *this; @@ -113,8 +105,6 @@ const FontPlatformData& FontPlatformData::operator=(const FontPlatformData& f) if (m_font && m_font != reinterpret_cast<NSFont *>(-1)) CFRelease(m_font); m_font = f.m_font; - m_isColorBitmapFont = f.m_isColorBitmapFont; - m_orientation = f.m_orientation; m_CTFont = f.m_CTFont; #if PLATFORM(CHROMIUM) && OS(DARWIN) m_inMemoryFont = f.m_inMemoryFont; @@ -122,6 +112,12 @@ const FontPlatformData& FontPlatformData::operator=(const FontPlatformData& f) return *this; } +bool FontPlatformData::platformIsEqual(const FontPlatformData& other) const +{ + return m_font == other.m_font + && m_cgFont == other.m_cgFont; +} + void FontPlatformData::setFont(NSFont *font) { ASSERT_ARG(font, font); diff --git a/Source/WebCore/platform/graphics/freetype/FontCustomPlatformDataFreeType.cpp b/Source/WebCore/platform/graphics/freetype/FontCustomPlatformDataFreeType.cpp index 841c8a3..b1cf96b 100644 --- a/Source/WebCore/platform/graphics/freetype/FontCustomPlatformDataFreeType.cpp +++ b/Source/WebCore/platform/graphics/freetype/FontCustomPlatformDataFreeType.cpp @@ -59,7 +59,7 @@ FontCustomPlatformData::~FontCustomPlatformData() cairo_font_face_destroy(m_fontFace); } -FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontWidthVariant, FontRenderingMode) +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, TextOrientation, FontWidthVariant, FontRenderingMode) { return FontPlatformData(m_fontFace, size, bold, italic); } diff --git a/Source/WebCore/platform/graphics/freetype/FontPlatformData.h b/Source/WebCore/platform/graphics/freetype/FontPlatformData.h index 2841b14..d1cb605 100644 --- a/Source/WebCore/platform/graphics/freetype/FontPlatformData.h +++ b/Source/WebCore/platform/graphics/freetype/FontPlatformData.h @@ -71,6 +71,7 @@ public: bool hasCompatibleCharmap(); 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/gpu/BicubicShader.cpp b/Source/WebCore/platform/graphics/gpu/BicubicShader.cpp new file mode 100644 index 0000000..40c9843 --- /dev/null +++ b/Source/WebCore/platform/graphics/gpu/BicubicShader.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(ACCELERATED_2D_CANVAS) + +#include "BicubicShader.h" + +#include "GraphicsContext3D.h" + +namespace WebCore { + +BicubicShader::BicubicShader(GraphicsContext3D* context, unsigned program) + : Shader(context, program) + , m_matrixLocation(context->getUniformLocation(program, "matrix")) + , m_texMatrixLocation(context->getUniformLocation(program, "texMatrix")) + , m_coefficientsLocation(context->getUniformLocation(program, "coefficients")) + , m_imageIncrementLocation(context->getUniformLocation(program, "imageIncrement")) + , m_imageLocation(context->getUniformLocation(program, "image")) + , m_alphaLocation(context->getUniformLocation(program, "alpha")) + , m_positionLocation(context->getAttribLocation(program, "position")) +{ +} + +PassOwnPtr<BicubicShader> BicubicShader::create(GraphicsContext3D* context) +{ + static const char* vertexShaderSource = + "uniform mat3 matrix;\n" + "uniform mat3 texMatrix;\n" + "attribute vec3 position;\n" + "varying vec2 texCoord;\n" + "void main() {\n" + " texCoord = (texMatrix * position).xy;\n" + " gl_Position = vec4(matrix * position, 1.0);\n" + "}\n"; + static const char* fragmentShaderSource = + "#ifdef GL_ES\n" + "precision mediump float;\n" + "#endif\n" + "uniform sampler2D image;\n" + "uniform vec2 imageIncrement;\n" + "uniform mat4 coefficients;\n" + "uniform float alpha;\n" + "varying vec2 texCoord;\n" + "vec4 cubicBlend(float t, vec4 c0, vec4 c1, vec4 c2, vec4 c3) {\n" + " vec4 ts = vec4(1.0, t, t * t, t * t * t);\n" + " vec4 result = coefficients * ts;\n" + " return result.w * c0 + result.z * c1 + result.y * c2 + result.x * c3;\n" + "}\n" + "void main() {\n" + " vec2 imageCoord = texCoord;\n" + " vec2 f = fract(imageCoord / imageIncrement) - vec2(0.5, 0.5);\n" + " vec4 t00 = texture2D(image, imageCoord + imageIncrement * vec2(-1, -1));\n" + " vec4 t10 = texture2D(image, imageCoord + imageIncrement * vec2( 0, -1));\n" + " vec4 t20 = texture2D(image, imageCoord + imageIncrement * vec2( 1, -1));\n" + " vec4 t30 = texture2D(image, imageCoord + imageIncrement * vec2( 2, -1));\n" + " vec4 t0 = cubicBlend(f.x, t00, t10, t20, t30);\n" + " vec4 t01 = texture2D(image, imageCoord + imageIncrement * vec2(-1, 0));\n" + " vec4 t11 = texture2D(image, imageCoord + imageIncrement * vec2( 0, 0));\n" + " vec4 t21 = texture2D(image, imageCoord + imageIncrement * vec2( 1, 0));\n" + " vec4 t31 = texture2D(image, imageCoord + imageIncrement * vec2( 2, 0));\n" + " vec4 t1 = cubicBlend(f.x, t01, t11, t21, t31);\n" + " vec4 t02 = texture2D(image, imageCoord + imageIncrement * vec2(-1, 1));\n" + " vec4 t12 = texture2D(image, imageCoord + imageIncrement * vec2( 0, 1));\n" + " vec4 t22 = texture2D(image, imageCoord + imageIncrement * vec2( 1, 1));\n" + " vec4 t32 = texture2D(image, imageCoord + imageIncrement * vec2( 2, 1));\n" + " vec4 t2 = cubicBlend(f.x, t02, t12, t22, t32);\n" + " vec4 t03 = texture2D(image, imageCoord + imageIncrement * vec2(-1, 2));\n" + " vec4 t13 = texture2D(image, imageCoord + imageIncrement * vec2( 0, 2));\n" + " vec4 t23 = texture2D(image, imageCoord + imageIncrement * vec2( 1, 2));\n" + " vec4 t33 = texture2D(image, imageCoord + imageIncrement * vec2( 2, 2));\n" + " vec4 t3 = cubicBlend(f.x, t03, t13, t23, t33);\n" + " gl_FragColor = cubicBlend(f.y, t0, t1, t2, t3);\n" + "}\n"; + + unsigned program = loadProgram(context, vertexShaderSource, fragmentShaderSource); + if (!program) + return 0; + + return new BicubicShader(context, program); +} + +void BicubicShader::use(const AffineTransform& transform, const AffineTransform& texTransform, const float coefficients[16], const float imageIncrement[2], float alpha) +{ + m_context->useProgram(m_program); + float matrix[9]; + affineTo3x3(transform, matrix); + m_context->uniformMatrix3fv(m_matrixLocation, false /*transpose*/, matrix, 1 /*count*/); + + float texMatrix[9]; + affineTo3x3(texTransform, texMatrix); + m_context->uniformMatrix3fv(m_texMatrixLocation, false /*transpose*/, texMatrix, 1 /*count*/); + m_context->uniformMatrix4fv(m_coefficientsLocation, false /*transpose*/, const_cast<float *>(coefficients), 1 /*count*/); + + m_context->uniform2f(m_imageIncrementLocation, imageIncrement[0], imageIncrement[1]); + + // For now, we always use texture unit 0. If that ever changes, we should + // expose this parameter to the caller. + 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->enableVertexAttribArray(m_positionLocation); +} + +} + +#endif diff --git a/Source/WebCore/platform/graphics/gpu/BicubicShader.h b/Source/WebCore/platform/graphics/gpu/BicubicShader.h new file mode 100644 index 0000000..f7522f4 --- /dev/null +++ b/Source/WebCore/platform/graphics/gpu/BicubicShader.h @@ -0,0 +1,58 @@ +/* + * 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 BicubicShader_h +#define BicubicShader_h + +#include "Shader.h" + +namespace WebCore { + +class BicubicShader : public Shader { +public: + static PassOwnPtr<BicubicShader> create(GraphicsContext3D*); + + void use(const AffineTransform&, const AffineTransform& texTransform, const float coefficients[16], const float imageIncrement[2], float alpha); + +private: + BicubicShader(GraphicsContext3D*, unsigned program); + + int m_matrixLocation; + int m_texMatrixLocation; + int m_coefficientsLocation; + int m_imageIncrementLocation; + int m_imageLocation; + int m_alphaLocation; + int m_positionLocation; +}; + +} + +#endif // BicubicShader_h diff --git a/Source/WebCore/platform/graphics/gpu/ConvolutionShader.cpp b/Source/WebCore/platform/graphics/gpu/ConvolutionShader.cpp new file mode 100644 index 0000000..f0b6bd9 --- /dev/null +++ b/Source/WebCore/platform/graphics/gpu/ConvolutionShader.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(ACCELERATED_2D_CANVAS) + +#include "ConvolutionShader.h" + +#include "GraphicsContext3D.h" +#include "StringExtras.h" + +namespace WebCore { + +ConvolutionShader::ConvolutionShader(GraphicsContext3D* context, unsigned program, int kernelWidth) + : Shader(context, program) + , m_kernelWidth(kernelWidth) + , m_matrixLocation(context->getUniformLocation(program, "matrix")) + , m_texMatrixLocation(context->getUniformLocation(program, "texMatrix")) + , m_kernelLocation(context->getUniformLocation(program, "kernel")) + , m_imageLocation(context->getUniformLocation(program, "image")) + , m_imageIncrementLocation(context->getUniformLocation(program, "imageIncrement")) + , m_positionLocation(context->getAttribLocation(program, "position")) +{ +} + +PassOwnPtr<ConvolutionShader> ConvolutionShader::create(GraphicsContext3D* context, int kernelWidth) +{ + static const char* vertexShaderRaw = + "#define KERNEL_WIDTH %d\n" + "uniform mat3 matrix;\n" + "uniform mat3 texMatrix;\n" + "uniform vec2 imageIncrement;\n" + "attribute vec3 position;\n" + "varying vec2 imageCoord;\n" + "void main() {\n" + " // Offset image coords by half of kernel width, in image texels\n" + " gl_Position = vec4(matrix * position, 1.0);\n" + " float scale = (float(KERNEL_WIDTH) - 1.0) / 2.0;\n" + " imageCoord = (texMatrix * position).xy - vec2(scale, scale) * imageIncrement;\n" + "}\n"; + char vertexShaderSource[1024]; + snprintf(vertexShaderSource, sizeof(vertexShaderSource), vertexShaderRaw, kernelWidth); + static const char* fragmentShaderRaw = + "#ifdef GL_ES\n" + "precision mediump float;\n" + "#endif\n" + "#define KERNEL_WIDTH %d\n" + "uniform sampler2D image;\n" + "uniform float kernel[KERNEL_WIDTH];\n" + "uniform vec2 imageIncrement;\n" + "varying vec2 imageCoord;\n" + "void main() {\n" + " vec2 coord = imageCoord;\n" + " vec4 sum = vec4(0, 0, 0, 0);\n" + " for (int i = 0; i < KERNEL_WIDTH; i++) {\n" + " sum += texture2D(image, coord) * kernel[i];\n" + " coord += imageIncrement;\n" + " }\n" + " gl_FragColor = sum;\n" + "}\n"; + char fragmentShaderSource[1024]; + snprintf(fragmentShaderSource, sizeof(fragmentShaderSource), fragmentShaderRaw, kernelWidth); + + unsigned program = loadProgram(context, vertexShaderSource, fragmentShaderSource); + if (!program) + return 0; + return new ConvolutionShader(context, program, kernelWidth); +} + +void ConvolutionShader::use(const AffineTransform& transform, const AffineTransform& texTransform, const float* kernel, int kernelWidth, float imageIncrement[2]) +{ + m_context->useProgram(m_program); + float matrix[9]; + affineTo3x3(transform, matrix); + m_context->uniformMatrix3fv(m_matrixLocation, false /*transpose*/, matrix, 1 /*count*/); + + float texMatrix[9]; + affineTo3x3(texTransform, texMatrix); + m_context->uniformMatrix3fv(m_texMatrixLocation, false /*transpose*/, texMatrix, 1 /*count*/); + + m_context->uniform2f(m_imageIncrementLocation, imageIncrement[0], imageIncrement[1]); + + // For now, we always use texture unit 0. If that ever changes, we should + // expose this parameter to the caller. + m_context->uniform1i(m_imageLocation, 0); + if (kernelWidth > m_kernelWidth) + 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->enableVertexAttribArray(m_positionLocation); +} + +} + +#endif diff --git a/Source/WebCore/platform/graphics/gpu/ConvolutionShader.h b/Source/WebCore/platform/graphics/gpu/ConvolutionShader.h new file mode 100644 index 0000000..533e0f5 --- /dev/null +++ b/Source/WebCore/platform/graphics/gpu/ConvolutionShader.h @@ -0,0 +1,58 @@ +/* + * 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 ConvolutionShader_h +#define ConvolutionShader_h + +#include "Shader.h" + +namespace WebCore { + +class ConvolutionShader : public Shader { +public: + static PassOwnPtr<ConvolutionShader> create(GraphicsContext3D*, int kernelWidth); + + void use(const AffineTransform&, const AffineTransform& texTransform, const float* kernel, int kernelWidth, float imageIncrement[2]); + +private: + ConvolutionShader(GraphicsContext3D*, unsigned program, int kernelWidth); + + int m_kernelWidth; + int m_matrixLocation; + int m_texMatrixLocation; + int m_kernelLocation; + int m_imageLocation; + int m_imageIncrementLocation; + int m_positionLocation; +}; + +} + +#endif // ConvolutionShader_h diff --git a/Source/WebCore/platform/graphics/gpu/DrawingBuffer.h b/Source/WebCore/platform/graphics/gpu/DrawingBuffer.h index 49ae114..606484e 100644 --- a/Source/WebCore/platform/graphics/gpu/DrawingBuffer.h +++ b/Source/WebCore/platform/graphics/gpu/DrawingBuffer.h @@ -42,6 +42,10 @@ #include <wtf/RetainPtr.h> #endif +#if ENABLE(SKIA_GPU) +class GrContext; +#endif + namespace WebCore { #if PLATFORM(CHROMIUM) @@ -59,6 +63,7 @@ public: void reset(const IntSize&); void bind(); IntSize size() const { return m_size; } + Platform3DObject colorBuffer() const { return m_colorBuffer; } // Clear all resources from this object, as well as context. Called when context is destroyed // to prevent invalid accesses to the resources. @@ -94,6 +99,10 @@ public: void setWillPublishCallback(PassOwnPtr<WillPublishCallback> callback) { m_callback = callback; } #endif +#if ENABLE(SKIA_GPU) + void setGrContext(GrContext* ctx); +#endif + PassRefPtr<GraphicsContext3D> graphicsContext3D() const { return m_context; } private: @@ -130,6 +139,10 @@ private: #if PLATFORM(MAC) RetainPtr<WebGLLayer> m_platformLayer; #endif + +#if ENABLE(SKIA_GPU) + GrContext* m_grContext; +#endif }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/gpu/LoopBlinnPathProcessor.cpp b/Source/WebCore/platform/graphics/gpu/LoopBlinnPathProcessor.cpp index 5439885..a96213c 100644 --- a/Source/WebCore/platform/graphics/gpu/LoopBlinnPathProcessor.cpp +++ b/Source/WebCore/platform/graphics/gpu/LoopBlinnPathProcessor.cpp @@ -42,6 +42,8 @@ #include <algorithm> #include <wtf/Assertions.h> #include <wtf/FastMalloc.h> +#include <wtf/UnusedParam.h> + #if USE(SKIA) #include "SkGeometry.h" @@ -701,6 +703,7 @@ void LoopBlinnPathProcessor::buildContours(const Path& path) } } while (verb != SkPath::kDone_Verb); #else // !USE(SKIA) + UNUSED_PARAM(path); // Must port to your platform. ASSERT_NOT_REACHED(); #endif @@ -1145,6 +1148,8 @@ static void combineCallback(GLdouble coords[3], void* vertexData[4], GLfloat weight[4], void** outData, void* polygonData) { + UNUSED_PARAM(vertexData); + UNUSED_PARAM(weight); TessellationState* state = static_cast<TessellationState*>(polygonData); GLdouble* outVertex = static_cast<GLdouble*>(fastMalloc(3 * sizeof(GLdouble))); state->allocatedPointers.append(outVertex); diff --git a/Source/WebCore/platform/graphics/gpu/PODRedBlackTree.h b/Source/WebCore/platform/graphics/gpu/PODRedBlackTree.h index bd08988..7dd9ddd 100644 --- a/Source/WebCore/platform/graphics/gpu/PODRedBlackTree.h +++ b/Source/WebCore/platform/graphics/gpu/PODRedBlackTree.h @@ -257,7 +257,7 @@ private: // properly update such summary information based only on the values // in the left and right children. This method should return true if // the node's summary information changed. - virtual bool updateNode(Node* node) { return false; } + virtual bool updateNode(Node*) { return false; } //---------------------------------------------------------------------- // Generic binary search tree operations @@ -713,7 +713,7 @@ private: } #ifdef NDEBUG - void logIfVerbose(const char* output) const { } + void logIfVerbose(const char*) const { } #else void logIfVerbose(const char* output) const { diff --git a/Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp b/Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp index ea8bc71..662d6a8 100644 --- a/Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp +++ b/Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp @@ -35,7 +35,10 @@ #include "SharedGraphicsContext3D.h" #include "AffineTransform.h" +#include "BicubicShader.h" #include "Color.h" +#include "ConvolutionShader.h" +#include "DrawingBuffer.h" #include "Extensions3D.h" #include "FloatRect.h" #include "IntSize.h" @@ -43,6 +46,15 @@ #include "SolidFillShader.h" #include "TexShader.h" +#if ENABLE(SKIA_GPU) +#include "GrContext.h" +// Limit the number of textures we hold in the bitmap->texture cache. +static const int maxTextureCacheCount = 512; +// Limit the bytes allocated toward textures in the bitmap->texture cache. +static const size_t maxTextureCacheBytes = 50 * 1024 * 1024; +#endif + +#include <wtf/OwnArrayPtr.h> #include <wtf/text/CString.h> #include <wtf/text/WTFString.h> @@ -65,16 +77,30 @@ PassRefPtr<SharedGraphicsContext3D> SharedGraphicsContext3D::create(HostWindow* OwnPtr<TexShader> texShader = TexShader::create(context.get()); if (!texShader) return 0; - return adoptRef(new SharedGraphicsContext3D(context.release(), solidFillShader.release(), texShader.release())); + OwnPtr<BicubicShader> bicubicShader = BicubicShader::create(context.get()); + if (!bicubicShader) + return 0; + OwnArrayPtr<OwnPtr<ConvolutionShader> > convolutionShaders = adoptArrayPtr(new OwnPtr<ConvolutionShader>[cMaxKernelWidth]); + for (int i = 0; i < cMaxKernelWidth; ++i) { + convolutionShaders[i] = ConvolutionShader::create(context.get(), i + 1); + if (!convolutionShaders[i]) + return 0; + } + return adoptRef(new SharedGraphicsContext3D(context.release(), solidFillShader.release(), texShader.release(), bicubicShader.release(), convolutionShaders.release())); } -SharedGraphicsContext3D::SharedGraphicsContext3D(PassRefPtr<GraphicsContext3D> context, PassOwnPtr<SolidFillShader> solidFillShader, PassOwnPtr<TexShader> texShader) +SharedGraphicsContext3D::SharedGraphicsContext3D(PassRefPtr<GraphicsContext3D> context, PassOwnPtr<SolidFillShader> solidFillShader, PassOwnPtr<TexShader> texShader, PassOwnPtr<BicubicShader> bicubicShader, PassOwnArrayPtr<OwnPtr<ConvolutionShader> > convolutionShaders) : m_context(context) , m_bgraSupported(false) , m_quadVertices(0) , m_solidFillShader(solidFillShader) , m_texShader(texShader) + , m_bicubicShader(bicubicShader) + , m_convolutionShaders(convolutionShaders) , m_oesStandardDerivativesSupported(false) +#if ENABLE(SKIA_GPU) + , m_grContext(0) +#endif { allContexts()->add(this); Extensions3D* extensions = m_context->getExtensions(); @@ -92,6 +118,9 @@ SharedGraphicsContext3D::~SharedGraphicsContext3D() { m_context->deleteBuffer(m_quadVertices); allContexts()->remove(this); +#if ENABLE(SKIA_GPU) + GrSafeUnref(m_grContext); +#endif } void SharedGraphicsContext3D::makeContextCurrent() @@ -369,6 +398,17 @@ void SharedGraphicsContext3D::useTextureProgram(const AffineTransform& transform m_texShader->use(transform, texTransform, 0, alpha); } +void SharedGraphicsContext3D::useBicubicProgram(const AffineTransform& transform, const AffineTransform& texTransform, const float coefficients[16], const float imageIncrement[2], float alpha) +{ + m_bicubicShader->use(transform, texTransform, coefficients, imageIncrement, alpha); +} + +void SharedGraphicsContext3D::useConvolutionProgram(const AffineTransform& transform, const AffineTransform& texTransform, const float* kernel, int kernelWidth, float imageIncrement[2]) +{ + ASSERT(kernelWidth >= 1 && kernelWidth <= cMaxKernelWidth); + m_convolutionShaders[kernelWidth - 1]->use(transform, texTransform, kernel, kernelWidth, imageIncrement); +} + void SharedGraphicsContext3D::bindFramebuffer(Platform3DObject framebuffer) { m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, framebuffer); @@ -411,6 +451,31 @@ void SharedGraphicsContext3D::useLoopBlinnExteriorProgram(unsigned vertexOffset, m_loopBlinnExteriorShader->use(vertexOffset, klmOffset, transform, color); } +DrawingBuffer* SharedGraphicsContext3D::getOffscreenBuffer(unsigned index, const IntSize& size) +{ + if (index >= m_offscreenBuffers.size()) + m_offscreenBuffers.resize(index + 1); + + if (!m_offscreenBuffers[index]) + m_offscreenBuffers[index] = m_context->createDrawingBuffer(size); + + if (size.width() != m_offscreenBuffers[index]->size().width() + || size.height() != m_offscreenBuffers[index]->size().height()) + m_offscreenBuffers[index]->reset(size); + return m_offscreenBuffers[index].get(); +} + +#if ENABLE(SKIA_GPU) +GrContext* SharedGraphicsContext3D::grContext() +{ + if (!m_grContext) { + m_grContext = GrContext::CreateGLShaderContext(); + m_grContext->setTextureCacheLimits(maxTextureCacheCount, maxTextureCacheBytes); + } + return m_grContext; +} +#endif + } // namespace WebCore #endif diff --git a/Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h b/Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h index 707fd24..8fb3d50 100644 --- a/Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h +++ b/Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h @@ -38,14 +38,22 @@ #include <wtf/HashMap.h> #include <wtf/HashSet.h> +#include <wtf/OwnArrayPtr.h> #include <wtf/OwnPtr.h> #include <wtf/RefCounted.h> #include <wtf/RefPtr.h> +#if ENABLE(SKIA_GPU) +class GrContext; +#endif + namespace WebCore { class AffineTransform; +class BicubicShader; class Color; +class ConvolutionShader; +class DrawingBuffer; class FloatRect; class HostWindow; class IntSize; @@ -101,6 +109,8 @@ public: void useFillSolidProgram(const AffineTransform&, const Color&); void useTextureProgram(const AffineTransform&, const AffineTransform&, float alpha); + void useBicubicProgram(const AffineTransform&, const AffineTransform&, const float coefficients[16], const float imageIncrement[2], float alpha); + void useConvolutionProgram(const AffineTransform&, const AffineTransform& texTransform, const float* kernel, int kernelWidth, float imageIncrement[2]); void setActiveTexture(GC3Denum textureUnit); void bindTexture(GC3Denum target, Platform3DObject texture); @@ -127,9 +137,14 @@ public: static bool useLoopBlinnForPathRendering(); void useLoopBlinnInteriorProgram(unsigned vertexOffset, const AffineTransform&, const Color&); void useLoopBlinnExteriorProgram(unsigned vertexOffset, unsigned klmOffset, const AffineTransform&, const Color&); + DrawingBuffer* getOffscreenBuffer(unsigned index, const IntSize&); + +#if ENABLE(SKIA_GPU) + GrContext* grContext(); +#endif private: - SharedGraphicsContext3D(PassRefPtr<GraphicsContext3D>, PassOwnPtr<SolidFillShader>, PassOwnPtr<TexShader>); + SharedGraphicsContext3D(PassRefPtr<GraphicsContext3D>, PassOwnPtr<SolidFillShader>, PassOwnPtr<TexShader>, PassOwnPtr<BicubicShader>, PassOwnArrayPtr<OwnPtr<ConvolutionShader> >); // Used to implement removeTexturesFor(), see the comment above. static HashSet<SharedGraphicsContext3D*>* allContexts(); @@ -142,6 +157,8 @@ private: OwnPtr<SolidFillShader> m_solidFillShader; OwnPtr<TexShader> m_texShader; + OwnPtr<BicubicShader> m_bicubicShader; + OwnArrayPtr<OwnPtr<ConvolutionShader> > m_convolutionShaders; TextureHashMap m_textures; @@ -150,8 +167,17 @@ private: OwnPtr<LoopBlinnSolidFillShader> m_loopBlinnInteriorShader; OwnPtr<LoopBlinnSolidFillShader> m_loopBlinnExteriorShader; bool m_oesStandardDerivativesSupported; + + WTF::Vector<RefPtr<DrawingBuffer> > m_offscreenBuffers; + +#if ENABLE(SKIA_GPU) + GrContext* m_grContext; +#endif }; +const float cMaxSigma = 4.0f; +const int cMaxKernelWidth = 25; + } // namespace WebCore #endif // SharedGraphicsContext3D_h diff --git a/Source/WebCore/platform/graphics/gpu/TilingData.cpp b/Source/WebCore/platform/graphics/gpu/TilingData.cpp index dd540b3..1370543 100644 --- a/Source/WebCore/platform/graphics/gpu/TilingData.cpp +++ b/Source/WebCore/platform/graphics/gpu/TilingData.cpp @@ -66,7 +66,7 @@ void TilingData::setTotalSize(int totalSizeX, int totalSizeY) void TilingData::setMaxTextureSize(int maxTextureSize) { - m_maxTextureSize = m_maxTextureSize; + m_maxTextureSize = maxTextureSize; recomputeNumTiles(); } diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp index 3763ef7..2fb4cef 100644 --- a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp @@ -117,6 +117,13 @@ gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpo || 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) @@ -495,7 +502,7 @@ float MediaPlayerPrivateGStreamer::currentTime() const return 0.0f; if (m_seeking) - return static_cast<float>(m_seekTime); + return m_seekTime; return playbackPosition(m_playBin); @@ -513,17 +520,28 @@ void MediaPlayerPrivateGStreamer::seek(float time) if (m_errorOccured) return; - GstClockTime sec = (GstClockTime)(static_cast<float>(time * GST_SECOND)); - LOG_VERBOSE(Media, "Seek: %" GST_TIME_FORMAT, GST_TIME_ARGS(sec)); + // Extract the integer part of the time (seconds) and the + // fractional part (microseconds). Attempt to round the + // microseconds so no floating point precision is lost and we can + // perform an accurate seek. + float seconds; + float microSeconds = modf(time, &seconds) * 1000000; + GTimeVal timeValue; + timeValue.tv_sec = static_cast<glong>(seconds); + timeValue.tv_usec = static_cast<glong>(roundf(microSeconds / 10000) * 10000); + + GstClockTime clockTime = GST_TIMEVAL_TO_TIME(timeValue); + LOG_VERBOSE(Media, "Seek: %" GST_TIME_FORMAT, GST_TIME_ARGS(clockTime)); + if (!gst_element_seek(m_playBin, m_player->rate(), GST_FORMAT_TIME, - (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), - GST_SEEK_TYPE_SET, sec, + (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE), + GST_SEEK_TYPE_SET, clockTime, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) LOG_VERBOSE(Media, "Seek to %f failed", time); else { m_seeking = true; - m_seekTime = sec; + m_seekTime = time; } } @@ -1046,15 +1064,9 @@ void MediaPlayerPrivateGStreamer::updateStates() if (!m_isStreaming && !m_buffering) return; - // Resume playback if a seek was performed in a live pipeline - // or during progressive download. That second use-case - // happens when the seek is performed to a region of the media - // that hasn't been downloaded yet. if (m_seeking) { shouldUpdateAfterSeek = true; m_seeking = false; - if (m_paused) - gst_element_set_state(m_playBin, GST_STATE_PLAYING); } break; case GST_STATE_CHANGE_FAILURE: diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h index 11eb81b..8003887 100644 --- a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h +++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h @@ -161,7 +161,7 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { GstElement* m_videoSinkBin; GstElement* m_fpsSink; GstElement* m_source; - GstClockTime m_seekTime; + float m_seekTime; bool m_changingRate; float m_endTime; bool m_isEndReached; diff --git a/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp index 86e3e7a..66ea9ba 100644 --- a/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp @@ -352,7 +352,7 @@ static void webKitWebSrcStop(WebKitWebSrc* src, bool seeking) } priv->resourceHandle = 0; - if (priv->frame) + if (priv->frame && !seeking) priv->frame.release(); GST_OBJECT_LOCK(src); diff --git a/Source/WebCore/platform/graphics/gtk/FontGtk.cpp b/Source/WebCore/platform/graphics/gtk/FontGtk.cpp index 216fb56..d14b052 100644 --- a/Source/WebCore/platform/graphics/gtk/FontGtk.cpp +++ b/Source/WebCore/platform/graphics/gtk/FontGtk.cpp @@ -35,6 +35,7 @@ #include "CairoUtilities.h" #include "ContextShadow.h" +#include "PlatformContextCairo.h" #include "GraphicsContext.h" #include "NotImplemented.h" #include "SimpleFontData.h" @@ -44,7 +45,7 @@ #include <pango/pango.h> #include <pango/pangocairo.h> -#if defined(USE_FREETYPE) +#if USE(FREETYPE) #include <pango/pangofc-fontmap.h> #endif @@ -171,13 +172,13 @@ static gchar* convertUniCharToUTF8(const UChar* characters, gint length, int fro static void setPangoAttributes(const Font* font, const TextRun& run, PangoLayout* layout) { -#if defined(USE_FREETYPE) +#if USE(FREETYPE) if (font->primaryFont()->platformData().m_pattern) { PangoFontDescription* desc = pango_fc_font_description_from_pattern(font->primaryFont()->platformData().m_pattern.get(), FALSE); pango_layout_set_font_description(layout, desc); pango_font_description_free(desc); } -#elif defined(USE_PANGO) +#elif USE(PANGO) if (font->primaryFont()->platformData().m_font) { PangoFontDescription* desc = pango_font_describe(font->primaryFont()->platformData().m_font); pango_layout_set_font_description(layout, desc); @@ -220,7 +221,7 @@ bool Font::canExpandAroundIdeographsInComplexText() return false; } -static void drawGlyphsShadow(GraphicsContext* graphicsContext, cairo_t* context, const FloatPoint& point, PangoLayoutLine* layoutLine, PangoRegionType renderRegion) +static void drawGlyphsShadow(GraphicsContext* graphicsContext, const FloatPoint& point, PangoLayoutLine* layoutLine, PangoRegionType renderRegion) { ContextShadow* shadow = graphicsContext->contextShadow(); ASSERT(shadow); @@ -232,6 +233,7 @@ static void drawGlyphsShadow(GraphicsContext* graphicsContext, cairo_t* context, // Optimize non-blurry shadows, by just drawing text without the ContextShadow. if (!shadow->mustUseContextShadow(graphicsContext)) { + cairo_t* context = graphicsContext->platformContext()->cr(); cairo_save(context); cairo_translate(context, totalOffset.x(), totalOffset.y()); @@ -255,6 +257,7 @@ static void drawGlyphsShadow(GraphicsContext* graphicsContext, cairo_t* context, // because we don't want any bits and pieces of characters out of range to be // drawn. Since ContextShadow expects a consistent transform, we have to undo the // translation before calling endShadowLayer as well. + cairo_t* context = graphicsContext->platformContext()->cr(); cairo_save(context); cairo_translate(context, totalOffset.x(), totalOffset.y()); gdk_cairo_region(context, renderRegion); @@ -268,14 +271,14 @@ static void drawGlyphsShadow(GraphicsContext* graphicsContext, cairo_t* context, void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const { -#if defined(USE_FREETYPE) +#if USE(FREETYPE) if (!primaryFont()->platformData().m_pattern) { drawSimpleText(context, run, point, from, to); return; } #endif - cairo_t* cr = context->platformContext(); + cairo_t* cr = context->platformContext()->cr(); PangoLayout* layout = pango_cairo_create_layout(cr); setPangoAttributes(this, run, layout); @@ -294,7 +297,7 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F int ranges[] = {start - utf8, end - utf8}; partialRegion = gdk_pango_layout_line_get_clip_region(layoutLine, 0, 0, ranges, 1); - drawGlyphsShadow(context, cr, point, layoutLine, partialRegion); + drawGlyphsShadow(context, point, layoutLine, partialRegion); cairo_save(cr); cairo_translate(cr, point.x(), point.y()); @@ -348,7 +351,7 @@ static PangoLayout* getDefaultPangoLayout(const TextRun& run) float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* overflow) const { -#if defined(USE_FREETYPE) +#if USE(FREETYPE) if (!primaryFont()->platformData().m_pattern) return floatWidthForSimpleText(run, 0, fallbackFonts, overflow); #endif @@ -373,7 +376,7 @@ float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, bool includePartialGlyphs) const { -#if defined(USE_FREETYPE) +#if USE(FREETYPE) if (!primaryFont()->platformData().m_pattern) return offsetForPositionForSimpleText(run, xFloat, includePartialGlyphs); #endif @@ -401,7 +404,7 @@ int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, bool FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const { -#if defined(USE_FREETYPE) +#if USE(FREETYPE) if (!primaryFont()->platformData().m_pattern) return selectionRectForSimpleText(run, point, h, from, to); #endif diff --git a/Source/WebCore/platform/graphics/gtk/IconGtk.cpp b/Source/WebCore/platform/graphics/gtk/IconGtk.cpp index d56b52d..7fdc1f6 100644 --- a/Source/WebCore/platform/graphics/gtk/IconGtk.cpp +++ b/Source/WebCore/platform/graphics/gtk/IconGtk.cpp @@ -33,9 +33,9 @@ #include "GraphicsContext.h" #include "MIMETypeRegistry.h" #include "PassRefPtr.h" -#include <wtf/text/CString.h> - +#include "PlatformContextCairo.h" #include <gtk/gtk.h> +#include <wtf/text/CString.h> namespace WebCore { @@ -117,7 +117,7 @@ void Icon::paint(GraphicsContext* context, const IntRect& rect) return; // TODO: Scale/clip the image if necessary. - cairo_t* cr = context->platformContext(); + cairo_t* cr = context->platformContext()->cr(); cairo_save(cr); gdk_cairo_set_source_pixbuf(cr, m_icon, rect.x(), rect.y()); cairo_paint(cr); diff --git a/Source/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp b/Source/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp index 2aa016e..3da0f9b 100644 --- a/Source/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp +++ b/Source/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp @@ -54,7 +54,7 @@ String ImageBuffer::toDataURL(const String& mimeType, const double* quality) con GError* error = 0; gboolean success = FALSE; if (type == "jpeg" && quality && *quality >= 0.0 && *quality <= 1.0) { - String qualityString = String::format("%f", *quality); + String qualityString = String::format("%f", *quality * 100.0); success = gdk_pixbuf_save_to_buffer(pixbuf.get(), &buffer.outPtr(), &bufferSize, type.utf8().data(), &error, "quality", qualityString.utf8().data(), NULL); } else { diff --git a/Source/WebCore/platform/graphics/gtk/ImageGtk.cpp b/Source/WebCore/platform/graphics/gtk/ImageGtk.cpp index 623ace6..9dd82a9 100644 --- a/Source/WebCore/platform/graphics/gtk/ImageGtk.cpp +++ b/Source/WebCore/platform/graphics/gtk/ImageGtk.cpp @@ -152,7 +152,10 @@ PassRefPtr<Image> Image::loadPlatformThemeIcon(const char* name, int size) GdkPixbuf* BitmapImage::getGdkPixbuf() { - return cairoImageSurfaceToGdkPixbuf(frameAtIndex(currentFrame())); + cairo_surface_t* frame = frameAtIndex(currentFrame()); + if (!frame) + return 0; + return cairoImageSurfaceToGdkPixbuf(frame); } } diff --git a/Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.cpp b/Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.cpp index 017b1e4..352de67 100644 --- a/Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.cpp +++ b/Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.cpp @@ -31,7 +31,7 @@ FontCustomPlatformData::~FontCustomPlatformData() { } -FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontWidthVariant, FontRenderingMode) +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, TextOrientation, FontWidthVariant, FontRenderingMode) { return FontPlatformData(size, bold, italic); } diff --git a/Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.h index 7ffe89a..a319ce5 100644 --- a/Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.h +++ b/Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.h @@ -24,6 +24,7 @@ #include "FontOrientation.h" #include "FontRenderingMode.h" #include "FontWidthVariant.h" +#include "TextOrientation.h" #include <wtf/Forward.h> namespace WebCore { @@ -39,7 +40,7 @@ namespace WebCore { static bool supportsFormat(const String&); - FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontWidthVariant = RegularWidth, FontRenderingMode = NormalRenderingMode); + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, TextOrientation = TextOrientationVerticalRight, FontWidthVariant = RegularWidth, FontRenderingMode = NormalRenderingMode); }; FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer*); diff --git a/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp b/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp index 1a56664..07bc3ec 100644 --- a/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp +++ b/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp @@ -63,7 +63,8 @@ ComplexTextController::ComplexTextController(const Font* font, const TextRun& ru , m_glyphInCurrentRun(0) , m_characterInCurrentGlyph(0) , m_expansion(run.expansion()) - , m_afterExpansion(true) + , m_leadingExpansion(0) + , m_afterExpansion(!run.allowsLeadingExpansion()) , m_fallbackFonts(fallbackFonts) , m_minGlyphBoundingBoxX(numeric_limits<float>::max()) , m_maxGlyphBoundingBoxX(numeric_limits<float>::min()) @@ -73,7 +74,7 @@ ComplexTextController::ComplexTextController(const Font* font, const TextRun& ru if (!m_expansion) m_expansionPerOpportunity = 0; else { - bool isAfterExpansion = true; + bool isAfterExpansion = m_afterExpansion; unsigned expansionOpportunityCount = Font::expansionOpportunityCount(m_run.characters(), m_end, m_run.ltr() ? LTR : RTL, isAfterExpansion); if (isAfterExpansion && !m_run.allowsTrailingExpansion()) expansionOpportunityCount--; @@ -86,12 +87,16 @@ ComplexTextController::ComplexTextController(const Font* font, const TextRun& ru collectComplexTextRuns(); adjustGlyphsAndAdvances(); + + m_runWidthSoFar = m_leadingExpansion; } int ComplexTextController::offsetForPosition(float h, bool includePartialGlyphs) { if (h >= m_totalWidth) return m_run.ltr() ? m_end : 0; + + h -= m_leadingExpansion; if (h < 0) return m_run.ltr() ? 0 : m_end; @@ -472,16 +477,21 @@ void ComplexTextController::adjustGlyphsAndAdvances() // Handle justification and word-spacing. if (treatAsSpace || Font::isCJKIdeographOrSymbol(ch)) { // Distribute the run's total expansion evenly over all expansion opportunities in the run. - if (m_expansion && (!lastGlyph || m_run.allowsTrailingExpansion())) { + if (m_expansion) { if (!treatAsSpace && !m_afterExpansion) { // Take the expansion opportunity before this ideograph. m_expansion -= m_expansionPerOpportunity; m_totalWidth += m_expansionPerOpportunity; - m_adjustedAdvances.last().width += m_expansionPerOpportunity; + if (m_adjustedAdvances.isEmpty()) + m_leadingExpansion = m_expansionPerOpportunity; + else + m_adjustedAdvances.last().width += m_expansionPerOpportunity; + } + if (!lastGlyph || m_run.allowsTrailingExpansion()) { + m_expansion -= m_expansionPerOpportunity; + advance.width += m_expansionPerOpportunity; + m_afterExpansion = true; } - m_expansion -= m_expansionPerOpportunity; - advance.width += m_expansionPerOpportunity; - m_afterExpansion = true; } else m_afterExpansion = false; diff --git a/Source/WebCore/platform/graphics/mac/ComplexTextController.h b/Source/WebCore/platform/graphics/mac/ComplexTextController.h index 7373bfe..44a7994 100644 --- a/Source/WebCore/platform/graphics/mac/ComplexTextController.h +++ b/Source/WebCore/platform/graphics/mac/ComplexTextController.h @@ -175,6 +175,7 @@ private: unsigned m_characterInCurrentGlyph; float m_expansion; float m_expansionPerOpportunity; + float m_leadingExpansion; bool m_afterExpansion; HashSet<const SimpleFontData*>* m_fallbackFonts; diff --git a/Source/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp b/Source/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp index b367fdf..d965ada 100644 --- a/Source/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp +++ b/Source/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp @@ -264,7 +264,7 @@ static void disableLigatures(const SimpleFontData* fontData, ATSUStyle atsuStyle // Don't be too aggressive: if the font doesn't contain 'a', then assume that any ligatures it contains are // in characters that always go through ATSUI, and therefore allow them. Geeza Pro is an example. // See bugzilla 5166. - if ((typesettingFeatures & Ligatures) || (fontData->orientation() == Horizontal && fontData->platformData().allowsLigatures())) + if ((typesettingFeatures & Ligatures) || (fontData->platformData().orientation() == Horizontal && fontData->platformData().allowsLigatures())) return; ATSUFontFeatureType featureTypes[] = { kLigaturesType }; diff --git a/Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp b/Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp index 239113f..d2fbaf5 100644 --- a/Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp +++ b/Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp @@ -144,17 +144,17 @@ void ComplexTextController::collectComplexTextRunsForCharactersCoreText(const UC static CFDictionaryRef rtlTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, rtlOptionValues, WTF_ARRAY_LENGTH(optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) - ProviderInfo info = { cp, length, fontData->getCFStringAttributes(m_font.typesettingFeatures()) }; + ProviderInfo info = { cp, length, fontData->getCFStringAttributes(m_font.typesettingFeatures(), fontData->platformData().orientation()) }; RetainPtr<CTTypesetterRef> typesetter(AdoptCF, wkCreateCTTypesetterWithUniCharProviderAndOptions(&provideStringAndAttributes, 0, &info, m_run.ltr() ? ltrTypesetterOptions : rtlTypesetterOptions)); #else RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, cp, length, kCFAllocatorNull)); - RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(kCFAllocatorDefault, string.get(), fontData->getCFStringAttributes(m_font.typesettingFeatures()))); + RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(kCFAllocatorDefault, string.get(), fontData->getCFStringAttributes(m_font.typesettingFeatures(), fontData->platformData().orientation()))); RetainPtr<CTTypesetterRef> typesetter(AdoptCF, CTTypesetterCreateWithAttributedStringAndOptions(attributedString.get(), m_run.ltr() ? ltrTypesetterOptions : rtlTypesetterOptions)); #endif line.adoptCF(CTTypesetterCreateLine(typesetter.get(), CFRangeMake(0, 0))); } else { - ProviderInfo info = { cp, length, fontData->getCFStringAttributes(m_font.typesettingFeatures()) }; + ProviderInfo info = { cp, length, fontData->getCFStringAttributes(m_font.typesettingFeatures(), fontData->platformData().orientation()) }; line.adoptCF(wkCreateCTLineWithUniCharProvider(&provideStringAndAttributes, 0, &info)); } diff --git a/Source/WebCore/platform/graphics/mac/FontCacheMac.mm b/Source/WebCore/platform/graphics/mac/FontCacheMac.mm index c254906..f7ae6b7 100644 --- a/Source/WebCore/platform/graphics/mac/FontCacheMac.mm +++ b/Source/WebCore/platform/graphics/mac/FontCacheMac.mm @@ -211,7 +211,7 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD bool syntheticBold = isAppKitFontWeightBold(weight) && !isAppKitFontWeightBold(actualWeight); bool syntheticOblique = (traits & NSFontItalicTrait) && !(actualTraits & NSFontItalicTrait); - return new FontPlatformData(platformFont, size, syntheticBold, syntheticOblique, fontDescription.orientation(), fontDescription.widthVariant()); + return new FontPlatformData(platformFont, size, syntheticBold, syntheticOblique, fontDescription.orientation(), fontDescription.textOrientation(), fontDescription.widthVariant()); } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/mac/FontComplexTextMac.cpp b/Source/WebCore/platform/graphics/mac/FontComplexTextMac.cpp index eed49a5..fe2a22c 100644 --- a/Source/WebCore/platform/graphics/mac/FontComplexTextMac.cpp +++ b/Source/WebCore/platform/graphics/mac/FontComplexTextMac.cpp @@ -111,8 +111,8 @@ float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon { ComplexTextController controller(this, run, true, fallbackFonts); if (glyphOverflow) { - glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-controller.minGlyphBoundingBoxY()) - fontMetrics().ascent()); - glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(controller.maxGlyphBoundingBoxY()) - fontMetrics().descent()); + glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-controller.minGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().ascent())); + glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(controller.maxGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().descent())); glyphOverflow->left = max<int>(0, ceilf(-controller.minGlyphBoundingBoxX())); glyphOverflow->right = max<int>(0, ceilf(controller.maxGlyphBoundingBoxX() - controller.totalWidth())); } diff --git a/Source/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp b/Source/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp index f2bc33d..383adef 100644 --- a/Source/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp +++ b/Source/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp @@ -38,9 +38,9 @@ FontCustomPlatformData::~FontCustomPlatformData() CGFontRelease(m_cgFont); } -FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation orientation, FontWidthVariant widthVariant, FontRenderingMode) +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation orientation, TextOrientation textOrientation, FontWidthVariant widthVariant, FontRenderingMode) { - return FontPlatformData(m_cgFont, size, bold, italic, orientation, widthVariant); + return FontPlatformData(m_cgFont, size, bold, italic, orientation, textOrientation, widthVariant); } FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) diff --git a/Source/WebCore/platform/graphics/mac/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/mac/FontCustomPlatformData.h index c7ae1ca..c625304 100644 --- a/Source/WebCore/platform/graphics/mac/FontCustomPlatformData.h +++ b/Source/WebCore/platform/graphics/mac/FontCustomPlatformData.h @@ -24,6 +24,7 @@ #include "FontOrientation.h" #include "FontRenderingMode.h" #include "FontWidthVariant.h" +#include "TextOrientation.h" #include <CoreFoundation/CFBase.h> #include <wtf/Forward.h> #include <wtf/Noncopyable.h> @@ -48,7 +49,7 @@ public: ~FontCustomPlatformData(); - FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontWidthVariant = RegularWidth, FontRenderingMode = NormalRenderingMode); + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, TextOrientation = TextOrientationVerticalRight, FontWidthVariant = RegularWidth, FontRenderingMode = NormalRenderingMode); static bool supportsFormat(const String&); diff --git a/Source/WebCore/platform/graphics/mac/FontMac.mm b/Source/WebCore/platform/graphics/mac/FontMac.mm index acd7562..4c28ead 100644 --- a/Source/WebCore/platform/graphics/mac/FontMac.mm +++ b/Source/WebCore/platform/graphics/mac/FontMac.mm @@ -52,28 +52,72 @@ bool Font::canExpandAroundIdeographsInComplexText() return true; } -static void showGlyphsWithAdvances(const SimpleFontData* font, CGContextRef context, const CGGlyph* glyphs, const CGSize* advances, size_t count) +// CTFontGetVerticalTranslationsForGlyphs is different on Snow Leopard. It returns values for a font-size of 1 +// without unitsPerEm applied. We have to apply a transform that scales up to the point size and that also +// divides by unitsPerEm. +static bool hasBrokenCTFontGetVerticalTranslationsForGlyphs() { +// Chromium runs the same binary on both Leopard and Snow Leopard, so the check has to happen at runtime. +#if PLATFORM(CHROMIUM) + static bool isCached = false; + static bool result; + + if (!isCached) { + SInt32 majorVersion = 0; + SInt32 minorVersion = 0; + Gestalt(gestaltSystemVersionMajor, &majorVersion); + Gestalt(gestaltSystemVersionMinor, &minorVersion); + result = majorVersion == 10 && minorVersion == 6; + isCached = true; + } + return result; +#elif defined(BUILDING_ON_SNOW_LEOPARD) + return true; +#else + return false; +#endif +} + +static void showGlyphsWithAdvances(const FloatPoint& point, const SimpleFontData* font, CGContextRef context, const CGGlyph* glyphs, const CGSize* advances, size_t count) +{ + CGContextSetTextPosition(context, point.x(), point.y()); + const FontPlatformData& platformData = font->platformData(); if (!platformData.isColorBitmapFont()) { CGAffineTransform savedMatrix; - bool isVertical = font->orientation() == Vertical; - + bool isVertical = font->platformData().orientation() == Vertical; if (isVertical) { CGAffineTransform rotateLeftTransform = CGAffineTransformMake(0, -1, 1, 0, 0, 0); - savedMatrix = CGContextGetTextMatrix(context); CGAffineTransform runMatrix = CGAffineTransformConcat(savedMatrix, rotateLeftTransform); - // Move start point to put glyphs into original region. - runMatrix.tx = savedMatrix.tx + font->fontMetrics().ascent(); - runMatrix.ty = savedMatrix.ty + font->fontMetrics().descent(); CGContextSetTextMatrix(context, runMatrix); - } - - CGContextShowGlyphsWithAdvances(context, glyphs, advances, count); - - if (isVertical) + + CGAffineTransform translationsTransform; + if (hasBrokenCTFontGetVerticalTranslationsForGlyphs()) { + translationsTransform = CGAffineTransformMake(platformData.m_size, 0, 0, platformData.m_size, 0, 0); + translationsTransform = CGAffineTransformConcat(translationsTransform, rotateLeftTransform); + CGFloat unitsPerEm = CGFontGetUnitsPerEm(platformData.cgFont()); + translationsTransform = CGAffineTransformConcat(translationsTransform, CGAffineTransformMakeScale(1 / unitsPerEm, 1 / unitsPerEm)); + } else { + translationsTransform = rotateLeftTransform; + } + Vector<CGSize, 256> translations(count); + CTFontGetVerticalTranslationsForGlyphs(platformData.ctFont(), glyphs, translations.data(), count); + + CGAffineTransform transform = CGAffineTransformInvert(CGContextGetTextMatrix(context)); + + CGPoint position = FloatPoint(point.x(), point.y() + font->fontMetrics().floatAscent(IdeographicBaseline) - font->fontMetrics().floatAscent()); + Vector<CGPoint, 256> positions(count); + for (size_t i = 0; i < count; ++i) { + CGSize translation = CGSizeApplyAffineTransform(translations[i], translationsTransform); + positions[i] = CGPointApplyAffineTransform(CGPointMake(position.x - translation.width, position.y + translation.height), transform); + position.x += advances[i].width; + position.y += advances[i].height; + } + CGContextShowGlyphsAtPositions(context, glyphs, positions.data(), count); CGContextSetTextMatrix(context, savedMatrix); + } else + CGContextShowGlyphsWithAdvances(context, glyphs, advances, count); } #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) else { @@ -188,21 +232,15 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons float shadowTextX = point.x() + shadowOffset.width(); // If shadows are ignoring transforms, then we haven't applied the Y coordinate flip yet, so down is negative. float shadowTextY = point.y() + shadowOffset.height() * (context->shadowsIgnoreTransforms() ? -1 : 1); - CGContextSetTextPosition(cgContext, shadowTextX, shadowTextY); - showGlyphsWithAdvances(font, cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); - if (font->syntheticBoldOffset()) { - CGContextSetTextPosition(cgContext, shadowTextX + font->syntheticBoldOffset(), shadowTextY); - showGlyphsWithAdvances(font, cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); - } + showGlyphsWithAdvances(FloatPoint(shadowTextX, shadowTextY), font, cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); + if (font->syntheticBoldOffset()) + showGlyphsWithAdvances(FloatPoint(shadowTextX + font->syntheticBoldOffset(), shadowTextY), font, cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); context->setFillColor(fillColor, fillColorSpace); } - CGContextSetTextPosition(cgContext, point.x(), point.y()); - showGlyphsWithAdvances(font, cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); - if (font->syntheticBoldOffset()) { - CGContextSetTextPosition(cgContext, point.x() + font->syntheticBoldOffset(), point.y()); - showGlyphsWithAdvances(font, cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); - } + showGlyphsWithAdvances(point, font, cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); + if (font->syntheticBoldOffset()) + showGlyphsWithAdvances(FloatPoint(point.x() + font->syntheticBoldOffset(), point.y()), font, cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); if (hasSimpleShadow) context->setShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace); diff --git a/Source/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp b/Source/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp index fe2b33a..18d0dc5 100644 --- a/Source/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp +++ b/Source/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp @@ -39,7 +39,7 @@ namespace WebCore { #ifndef BUILDING_ON_TIGER static bool shouldUseCoreText(UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) { - if (fontData->platformData().widthVariant() != RegularWidth || (fontData->orientation() == Vertical && !fontData->isBrokenIdeographFont())) { + if (fontData->platformData().widthVariant() != RegularWidth || fontData->hasVerticalGlyphs()) { // Ideographs don't have a vertical variant or width variants. for (unsigned i = 0; i < bufferLength; ++i) { if (!Font::isCJKIdeograph(buffer[i])) @@ -70,7 +70,7 @@ bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned b } else { // We ask CoreText for possible vertical variant glyphs RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, buffer, bufferLength, kCFAllocatorNull)); - RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(kCFAllocatorDefault, string.get(), fontData->getCFStringAttributes(0))); + RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(kCFAllocatorDefault, string.get(), fontData->getCFStringAttributes(0, fontData->hasVerticalGlyphs() ? Vertical : Horizontal))); RetainPtr<CTLineRef> line(AdoptCF, CTLineCreateWithAttributedString(attributedString.get())); CFArrayRef runArray = CTLineGetGlyphRuns(line.get()); diff --git a/Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm b/Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm index aaa250b..997c976 100644 --- a/Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm +++ b/Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm @@ -93,9 +93,14 @@ GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs, HostWi , m_attrs(attrs) , m_contextObj(0) , m_texture(0) + , m_compositorTexture(0) , m_fbo(0) , m_depthStencilBuffer(0) + , m_layerComposited(false) + , m_internalColorFormat(0) , m_boundFBO(0) + , m_activeTexture(0) + , m_boundTexture0(0) , m_multisampleFBO(0) , m_multisampleDepthStencilBuffer(0) , m_multisampleColorBuffer(0) @@ -166,6 +171,12 @@ GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs, HostWi ::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); + ::glGenTextures(1, &m_compositorTexture); + ::glBindTexture(GL_TEXTURE_2D, m_compositorTexture); + ::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 @@ -215,6 +226,7 @@ GraphicsContext3D::~GraphicsContext3D() if (m_contextObj) { CGLSetCurrentContext(m_contextObj); ::glDeleteTextures(1, &m_texture); + ::glDeleteTextures(1, &m_compositorTexture); if (m_attrs.antialias) { ::glDeleteRenderbuffersEXT(1, &m_multisampleColorBuffer); if (m_attrs.stencil || m_attrs.depth) diff --git a/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h b/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h index 80bc94e..7bdc064 100644 --- a/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h +++ b/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h @@ -54,6 +54,8 @@ class WebCoreMovieObserver; #endif namespace WebCore { + +class ApplicationCacheResource; class MediaPlayerPrivateQTKit : public MediaPlayerPrivateInterface { public: @@ -139,6 +141,7 @@ private: void createQTMovie(const String& url); void createQTMovie(NSURL *, NSDictionary *movieAttributes); + void createQTMovie(ApplicationCacheResource*); enum MediaRenderingMode { MediaRenderingNone, MediaRenderingMovieView, MediaRenderingSoftwareRenderer, MediaRenderingMovieLayer }; MediaRenderingMode currentRenderingMode() const; @@ -178,6 +181,8 @@ private: virtual double maximumDurationToCacheMediaTime() const { return 5; } virtual void setPrivateBrowsingMode(bool); + + NSMutableDictionary* commonMovieAttributes(); MediaPlayer* m_player; RetainPtr<QTMovie> m_qtMovie; @@ -211,6 +216,7 @@ private: double m_timeStartedPlaying; double m_timeStoppedPlaying; #endif + mutable FloatSize m_cachedNaturalSize; }; } diff --git a/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm index ecb7d9f..400fdfb 100644 --- a/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm +++ b/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm @@ -29,11 +29,18 @@ #import "MediaPlayerPrivateQTKit.h" +#if ENABLE(OFFLINE_WEB_APPLICATIONS) +#include "ApplicationCacheHost.h" +#include "ApplicationCacheResource.h" +#include "DocumentLoader.h" +#endif + #ifdef BUILDING_ON_TIGER #import "AutodrainedPool.h" #endif #import "BlockExceptions.h" +#import "DocumentLoader.h" #import "FrameView.h" #import "GraphicsContext.h" #import "KURL.h" @@ -83,6 +90,7 @@ SOFT_LINK_POINTER(QTKit, QTMediaTypeText, NSString *) SOFT_LINK_POINTER(QTKit, QTMediaTypeVideo, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieAskUnresolvedDataRefsAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieLoopsAttribute, NSString *) +SOFT_LINK_POINTER(QTKit, QTMovieDataAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieDataSizeAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieDidEndNotification, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieHasVideoAttribute, NSString *) @@ -120,6 +128,7 @@ SOFT_LINK_POINTER(QTKit, QTMovieApertureModeAttribute, NSString *) #define QTMediaTypeVideo getQTMediaTypeVideo() #define QTMovieAskUnresolvedDataRefsAttribute getQTMovieAskUnresolvedDataRefsAttribute() #define QTMovieLoopsAttribute getQTMovieLoopsAttribute() +#define QTMovieDataAttribute getQTMovieDataAttribute() #define QTMovieDataSizeAttribute getQTMovieDataSizeAttribute() #define QTMovieDidEndNotification getQTMovieDidEndNotification() #define QTMovieHasVideoAttribute getQTMovieHasVideoAttribute() @@ -241,21 +250,26 @@ MediaPlayerPrivateQTKit::~MediaPlayerPrivateQTKit() [m_objcObserver.get() disconnect]; } -void MediaPlayerPrivateQTKit::createQTMovie(const String& url) +NSMutableDictionary* MediaPlayerPrivateQTKit::commonMovieAttributes() { - NSURL *cocoaURL = KURL(ParsedURLString, url); - NSMutableDictionary *movieAttributes = [NSMutableDictionary dictionaryWithObjectsAndKeys: - cocoaURL, QTMovieURLAttribute, - [NSNumber numberWithBool:m_player->preservesPitch()], QTMovieRateChangesPreservePitchAttribute, - [NSNumber numberWithBool:YES], QTMoviePreventExternalURLLinksAttribute, - [NSNumber numberWithBool:YES], QTSecurityPolicyNoCrossSiteAttribute, - [NSNumber numberWithBool:NO], QTMovieAskUnresolvedDataRefsAttribute, - [NSNumber numberWithBool:NO], QTMovieLoopsAttribute, - [NSNumber numberWithBool:!m_privateBrowsing], @"QTMovieAllowPersistentCacheAttribute", + return [NSMutableDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:m_player->preservesPitch()], QTMovieRateChangesPreservePitchAttribute, + [NSNumber numberWithBool:YES], QTMoviePreventExternalURLLinksAttribute, + [NSNumber numberWithBool:YES], QTSecurityPolicyNoCrossSiteAttribute, + [NSNumber numberWithBool:NO], QTMovieAskUnresolvedDataRefsAttribute, + [NSNumber numberWithBool:NO], QTMovieLoopsAttribute, + [NSNumber numberWithBool:!m_privateBrowsing], @"QTMovieAllowPersistentCacheAttribute", #ifndef BUILDING_ON_TIGER - QTMovieApertureModeClean, QTMovieApertureModeAttribute, + QTMovieApertureModeClean, QTMovieApertureModeAttribute, #endif - nil]; + nil]; +} + +void MediaPlayerPrivateQTKit::createQTMovie(const String& url) +{ + NSURL *cocoaURL = KURL(ParsedURLString, url); + NSMutableDictionary *movieAttributes = commonMovieAttributes(); + [movieAttributes setValue:cocoaURL forKey:QTMovieURLAttribute]; #if !defined(BUILDING_ON_LEOPARD) CFDictionaryRef proxySettings = CFNetworkCopySystemProxySettings(); @@ -291,6 +305,33 @@ void MediaPlayerPrivateQTKit::createQTMovie(const String& url) createQTMovie(cocoaURL, movieAttributes); } +void MediaPlayerPrivateQTKit::createQTMovie(ApplicationCacheResource* resource) +{ +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + ASSERT(resource); + + NSMutableDictionary *movieAttributes = commonMovieAttributes(); + [movieAttributes setObject:[NSNumber numberWithBool:YES] forKey:@"QTMovieOpenForPlaybackAttribute"]; + + // ApplicationCacheResources can supply either a data pointer, or a path to a locally cached + // flat file. We would prefer the path over the data, but QTKit can handle either: + String localPath = resource->path(); + NSURL* cocoaURL = !localPath.isEmpty() ? [NSURL fileURLWithPath:localPath isDirectory:NO] : nil; + if (cocoaURL) + [movieAttributes setValue:cocoaURL forKey:QTMovieURLAttribute]; + else { + NSData* movieData = resource->data()->createNSData(); + [movieAttributes setValue:movieData forKey:QTMovieDataAttribute]; + [movieData release]; + } + + createQTMovie(cocoaURL, movieAttributes); + +#else + ASSERT_NOT_REACHED(); +#endif +} + static void disableComponentsOnce() { static bool sComponentsDisabled = false; @@ -658,6 +699,14 @@ void MediaPlayerPrivateQTKit::loadInternal(const String& url) [m_objcObserver.get() setDelayCallbacks:YES]; +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + Frame* frame = m_player->frameView() ? m_player->frameView()->frame() : NULL; + ApplicationCacheHost* cacheHost = frame ? frame->loader()->documentLoader()->applicationCacheHost() : NULL; + ApplicationCacheResource* resource = NULL; + if (cacheHost && cacheHost->shouldLoadResourceFromApplicationCache(ResourceRequest(url), resource) && resource) + createQTMovie(resource); + else +#endif createQTMovie(url); [m_objcObserver.get() loadStateChanged:nil]; @@ -827,8 +876,19 @@ IntSize MediaPlayerPrivateQTKit::naturalSize() const // dimensions, aspect ratio, clean aperture, resolution, and so forth, as defined for the // format used by the resource - NSSize naturalSize = [[m_qtMovie.get() attributeForKey:QTMovieNaturalSizeAttribute] sizeValue]; - return IntSize(naturalSize.width * m_scaleFactor.width(), naturalSize.height * m_scaleFactor.height()); + FloatSize naturalSize([[m_qtMovie.get() attributeForKey:QTMovieNaturalSizeAttribute] sizeValue]); + if (naturalSize.isEmpty() && m_isStreaming) { + // HTTP Live Streams will occasionally return {0,0} natural sizes while scrubbing. + // Work around this problem (<rdar://problem/9078563>) by returning the last valid + // cached natural size: + naturalSize = m_cachedNaturalSize; + } else { + // Unfortunately, due to another QTKit bug (<rdar://problem/9082071>) we won't get a sizeChanged + // event when this happens, so we must cache the last valid naturalSize here: + m_cachedNaturalSize = naturalSize; + } + + return IntSize(naturalSize.width() * m_scaleFactor.width(), naturalSize.height() * m_scaleFactor.height()); } bool MediaPlayerPrivateQTKit::hasVideo() const diff --git a/Source/WebCore/platform/graphics/mac/SimpleFontDataCoreText.cpp b/Source/WebCore/platform/graphics/mac/SimpleFontDataCoreText.cpp index 452bd54..832bb9d 100644 --- a/Source/WebCore/platform/graphics/mac/SimpleFontDataCoreText.cpp +++ b/Source/WebCore/platform/graphics/mac/SimpleFontDataCoreText.cpp @@ -39,15 +39,17 @@ using namespace std; namespace WebCore { -CFDictionaryRef SimpleFontData::getCFStringAttributes(TypesettingFeatures typesettingFeatures) const +CFDictionaryRef SimpleFontData::getCFStringAttributes(TypesettingFeatures typesettingFeatures, FontOrientation orientation) const { unsigned key = typesettingFeatures + 1; pair<HashMap<unsigned, RetainPtr<CFDictionaryRef> >::iterator, bool> addResult = m_CFStringAttributes.add(key, RetainPtr<CFDictionaryRef>()); RetainPtr<CFDictionaryRef>& attributesDictionary = addResult.first->second; if (!addResult.second) return attributesDictionary.get(); + + bool treatLineAsVertical = orientation == Vertical; - bool allowLigatures = (orientation() == Horizontal && platformData().allowsLigatures()) || (typesettingFeatures & Ligatures); + bool allowLigatures = (!treatLineAsVertical && platformData().allowsLigatures()) || (typesettingFeatures & Ligatures); static const int ligaturesNotAllowedValue = 0; static CFNumberRef ligaturesNotAllowed = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &ligaturesNotAllowedValue); @@ -60,13 +62,13 @@ CFDictionaryRef SimpleFontData::getCFStringAttributes(TypesettingFeatures typese static CFNumberRef kerningAdjustment = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &kerningAdjustmentValue); static const void* keysWithKerningDisabled[] = { kCTFontAttributeName, kCTKernAttributeName, kCTLigatureAttributeName, kCTVerticalFormsAttributeName }; const void* valuesWithKerningDisabled[] = { platformData().ctFont(), kerningAdjustment, allowLigatures - ? ligaturesAllowed : ligaturesNotAllowed, orientation() == Vertical ? kCFBooleanTrue : kCFBooleanFalse }; + ? ligaturesAllowed : ligaturesNotAllowed, treatLineAsVertical ? kCFBooleanTrue : kCFBooleanFalse }; attributesDictionary.adoptCF(CFDictionaryCreate(0, keysWithKerningDisabled, valuesWithKerningDisabled, WTF_ARRAY_LENGTH(keysWithKerningDisabled), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); } else { // By omitting the kCTKernAttributeName attribute, we get Core Text's standard kerning. static const void* keysWithKerningEnabled[] = { kCTFontAttributeName, kCTLigatureAttributeName, kCTVerticalFormsAttributeName }; - const void* valuesWithKerningEnabled[] = { platformData().ctFont(), allowLigatures ? ligaturesAllowed : ligaturesNotAllowed, orientation() == Vertical ? kCFBooleanTrue : kCFBooleanFalse }; + const void* valuesWithKerningEnabled[] = { platformData().ctFont(), allowLigatures ? ligaturesAllowed : ligaturesNotAllowed, treatLineAsVertical ? kCFBooleanTrue : kCFBooleanFalse }; attributesDictionary.adoptCF(CFDictionaryCreate(0, keysWithKerningEnabled, valuesWithKerningEnabled, WTF_ARRAY_LENGTH(keysWithKerningEnabled), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); } diff --git a/Source/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/Source/WebCore/platform/graphics/mac/SimpleFontDataMac.mm index 3094498..cd34000 100644 --- a/Source/WebCore/platform/graphics/mac/SimpleFontDataMac.mm +++ b/Source/WebCore/platform/graphics/mac/SimpleFontDataMac.mm @@ -259,49 +259,32 @@ void SimpleFontData::platformInit() descent = 3; } - if (m_orientation == Vertical) { - // Ignore vertical orientation when the font doesn't support vertical metrics. + if (platformData().orientation() == Vertical && !isTextOrientationFallback()) { // The check doesn't look neat but this is what AppKit does for vertical writing... RetainPtr<CFArrayRef> tableTags(AdoptCF, CTFontCopyAvailableTables(m_platformData.ctFont(), kCTFontTableOptionExcludeSynthetic)); CFIndex numTables = CFArrayGetCount(tableTags.get()); - bool found = false; for (CFIndex index = 0; index < numTables; ++index) { CTFontTableTag tag = (CTFontTableTag)(uintptr_t)CFArrayGetValueAtIndex(tableTags.get(), index); if (tag == kCTFontTableVhea || tag == kCTFontTableVORG) { - found = true; + m_hasVerticalGlyphs = true; break; } } - - if (found == false) - m_orientation = Horizontal; } float xHeight; - // Measure the actual character "x", because AppKit synthesizes X height rather than getting it from the font. - // Unfortunately, NSFont will round this for us so we don't quite get the right value. - GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); - NSGlyph xGlyph = glyphPageZero ? glyphPageZero->glyphDataForCharacter('x').glyph : 0; - if (xGlyph) { - CGRect xBox = platformBoundsForGlyph(xGlyph); - // Use the maximum of either width or height because "x" is nearly square - // and web pages that foolishly use this metric for width will be laid out - // poorly if we return an accurate height. Classic case is Times 13 point, - // which has an "x" that is 7x6 pixels. - xHeight = static_cast<float>(max(CGRectGetMaxX(xBox), -CGRectGetMinY(xBox))); - } else { -#ifndef BUILDING_ON_TIGER - xHeight = static_cast<float>(CGFontGetXHeight(m_platformData.cgFont())) / unitsPerEm; -#else - xHeight = m_platformData.font() ? [m_platformData.font() xHeight] : 0; -#endif - // CGFontGetXHeight() returns a wrong value for "Apple Symbols" font (a float close to 0, but not strictly 0). - // The following code makes a guess for xHeight in that case. - // The int cast is a workaround for the "almost" zero value returned by CGFontGetXHeight(). - if (!static_cast<int>(xHeight) && ascent) - xHeight = 2 * ascent / 3; - } + if (platformData().orientation() == Horizontal) { + // Measure the actual character "x", since it's possible for it to extend below the baseline, and we need the + // reported x-height to only include the portion of the glyph that is above the baseline. + GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); + NSGlyph xGlyph = glyphPageZero ? glyphPageZero->glyphDataForCharacter('x').glyph : 0; + if (xGlyph) + xHeight = -CGRectGetMinY(platformBoundsForGlyph(xGlyph)); + else + xHeight = scaleEmToUnits(CGFontGetXHeight(m_platformData.cgFont()), unitsPerEm) * pointSize; + } else + xHeight = verticalRightOrientationFontData()->fontMetrics().xHeight(); m_fontMetrics.setUnitsPerEm(unitsPerEm); m_fontMetrics.setAscent(ascent); @@ -474,17 +457,8 @@ void SimpleFontData::determinePitch() FloatRect SimpleFontData::platformBoundsForGlyph(Glyph glyph) const { FloatRect boundingBox; -#ifndef BUILDING_ON_TIGER - boundingBox = CTFontGetBoundingRectsForGlyphs(m_platformData.ctFont(), - orientation() == Vertical ? kCTFontVerticalOrientation : kCTFontHorizontalOrientation, &glyph, 0, 1); + boundingBox = CTFontGetBoundingRectsForGlyphs(m_platformData.ctFont(), platformData().orientation() == Vertical ? kCTFontVerticalOrientation : kCTFontHorizontalOrientation, &glyph, 0, 1); boundingBox.setY(-boundingBox.maxY()); -#else - // FIXME: Custom fonts don't have NSFonts, so this function doesn't compute correct bounds for these on Tiger. - if (!m_platformData.font()) - return boundingBox; - boundingBox = [m_platformData.font() boundingRectForGlyph:glyph]; - boundingBox.setY(-boundingBox.maxY()); -#endif if (m_syntheticBoldOffset) boundingBox.setWidth(boundingBox.width() + m_syntheticBoldOffset); @@ -494,7 +468,7 @@ FloatRect SimpleFontData::platformBoundsForGlyph(Glyph glyph) const float SimpleFontData::platformWidthForGlyph(Glyph glyph) const { CGSize advance; - if (orientation() == Horizontal || m_isBrokenIdeographFont) { + if (platformData().orientation() == Horizontal || m_isBrokenIdeographFallback) { NSFont* font = platformData().font(); float pointSize = platformData().m_size; CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSize); diff --git a/Source/WebCore/platform/graphics/mac/WebLayer.h b/Source/WebCore/platform/graphics/mac/WebLayer.h index 30bf55b..2e9bea0 100644 --- a/Source/WebCore/platform/graphics/mac/WebLayer.h +++ b/Source/WebCore/platform/graphics/mac/WebLayer.h @@ -32,6 +32,7 @@ namespace WebCore { class GraphicsLayer; + class PlatformCALayer; class PlatformCALayerClient; } @@ -48,7 +49,7 @@ namespace WebCore { @end // Functions allows us to share implementation across WebTiledLayer and WebLayer -void drawLayerContents(CGContextRef, CALayer *, WebCore::PlatformCALayerClient*); +void drawLayerContents(CGContextRef, CALayer *, WebCore::PlatformCALayer*); void setLayerNeedsDisplayInRect(CALayer *, WebCore::PlatformCALayerClient*, CGRect); #endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/mac/WebLayer.mm b/Source/WebCore/platform/graphics/mac/WebLayer.mm index 414a75f..c9705d0 100644 --- a/Source/WebCore/platform/graphics/mac/WebLayer.mm +++ b/Source/WebCore/platform/graphics/mac/WebLayer.mm @@ -40,8 +40,9 @@ using namespace WebCore; @implementation WebLayer -void drawLayerContents(CGContextRef context, CALayer *layer, WebCore::PlatformCALayerClient* layerContents) +void drawLayerContents(CGContextRef context, CALayer *layer, WebCore::PlatformCALayer* platformLayer) { + WebCore::PlatformCALayerClient* layerContents = platformLayer->owner(); if (!layerContents) return; @@ -62,6 +63,7 @@ void drawLayerContents(CGContextRef context, CALayer *layer, WebCore::PlatformCA GraphicsContext graphicsContext(context); graphicsContext.setIsCALayerContext(true); + graphicsContext.setIsAcceleratedContext(platformLayer->acceleratesDrawing()); if (!layerContents->platformCALayerContentsOpaque()) { // Turn off font smoothing to improve the appearance of text rendered onto a transparent background. @@ -167,7 +169,7 @@ void setLayerNeedsDisplayInRect(CALayer *layer, WebCore::PlatformCALayerClient* { PlatformCALayer* layer = PlatformCALayer::platformCALayer(self); if (layer) - drawLayerContents(context, self, layer->owner()); + drawLayerContents(context, self, layer); } @end // implementation WebLayer diff --git a/Source/WebCore/platform/graphics/mac/WebTiledLayer.mm b/Source/WebCore/platform/graphics/mac/WebTiledLayer.mm index e9fa5b7..9bcdd54 100644 --- a/Source/WebCore/platform/graphics/mac/WebTiledLayer.mm +++ b/Source/WebCore/platform/graphics/mac/WebTiledLayer.mm @@ -83,7 +83,7 @@ using namespace WebCore; { PlatformCALayer* layer = PlatformCALayer::platformCALayer(self); if (layer) - drawLayerContents(context, self, layer->owner()); + drawLayerContents(context, self, layer); } @end // implementation WebTiledLayer diff --git a/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp b/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp index c224e20..f831550 100644 --- a/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp +++ b/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp @@ -38,6 +38,7 @@ #include "GraphicsContext.h" #include "HTMLCanvasElement.h" #include "ImageBuffer.h" +#include "ImageData.h" #include "Int32Array.h" #include "NotImplemented.h" #include "Uint8Array.h" @@ -53,11 +54,12 @@ namespace WebCore { void GraphicsContext3D::validateAttributes() { - const char* extensions = reinterpret_cast<const char*>(::glGetString(GL_EXTENSIONS)); + Extensions3D* extensions = getExtensions(); if (m_attrs.stencil) { - if (std::strstr(extensions, "GL_EXT_packed_depth_stencil")) { - if (!m_attrs.depth) - m_attrs.depth = true; + if (extensions->supports("GL_EXT_packed_depth_stencil")) { + extensions->ensureEnabled("GL_EXT_packed_depth_stencil"); + // Force depth if stencil is true. + m_attrs.depth = true; } else m_attrs.stencil = false; } @@ -67,24 +69,16 @@ void GraphicsContext3D::validateAttributes() const char* vendor = reinterpret_cast<const char*>(::glGetString(GL_VENDOR)); if (!std::strstr(vendor, "NVIDIA")) isValidVendor = false; - if (!isValidVendor || !std::strstr(extensions, "GL_EXT_framebuffer_multisample")) + if (!isValidVendor || !extensions->supports("GL_ANGLE_framebuffer_multisample")) m_attrs.antialias = false; + else + extensions->ensureEnabled("GL_ANGLE_framebuffer_multisample"); } - // FIXME: instead of enforcing premultipliedAlpha = true, implement the - // correct behavior when premultipliedAlpha = false is requested. - m_attrs.premultipliedAlpha = true; } -void GraphicsContext3D::paintRenderingResultsToCanvas(CanvasRenderingContext* context) +void GraphicsContext3D::readRenderingResults(unsigned char *pixels, int pixelsSize) { - HTMLCanvasElement* canvas = context->canvas(); - ImageBuffer* imageBuffer = canvas->buffer(); - - int rowBytes = m_currentWidth * 4; - int totalBytes = rowBytes * m_currentHeight; - - OwnArrayPtr<unsigned char> pixels = adoptArrayPtr(new unsigned char[totalBytes]); - if (!pixels) + if (pixelsSize < m_currentWidth * m_currentHeight * 4) return; makeContextCurrent(); @@ -111,18 +105,62 @@ void GraphicsContext3D::paintRenderingResultsToCanvas(CanvasRenderingContext* co mustRestorePackAlignment = true; } - ::glReadPixels(0, 0, m_currentWidth, m_currentHeight, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixels.get()); + ::glReadPixels(0, 0, m_currentWidth, m_currentHeight, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixels); if (mustRestorePackAlignment) ::glPixelStorei(GL_PACK_ALIGNMENT, packAlignment); if (mustRestoreFBO) ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_boundFBO); +} + +void GraphicsContext3D::paintRenderingResultsToCanvas(CanvasRenderingContext* context) +{ + HTMLCanvasElement* canvas = context->canvas(); + ImageBuffer* imageBuffer = canvas->buffer(); + + int rowBytes = m_currentWidth * 4; + int totalBytes = rowBytes * m_currentHeight; + + OwnArrayPtr<unsigned char> pixels = adoptArrayPtr(new unsigned char[totalBytes]); + if (!pixels) + return; + + readRenderingResults(pixels.get(), totalBytes); + + if (!m_attrs.premultipliedAlpha) { + for (int i = 0; i < totalBytes; i += 4) { + // Premultiply alpha + pixels[i + 0] = std::min(255, pixels[i + 0] * pixels[i + 3] / 255); + pixels[i + 1] = std::min(255, pixels[i + 1] * pixels[i + 3] / 255); + pixels[i + 2] = std::min(255, pixels[i + 2] * pixels[i + 3] / 255); + } + } paintToCanvas(pixels.get(), m_currentWidth, m_currentHeight, canvas->width(), canvas->height(), imageBuffer->context()->platformContext()); } +PassRefPtr<ImageData> GraphicsContext3D::paintRenderingResultsToImageData() +{ + // Reading premultiplied alpha would involve unpremultiplying, which is + // lossy + if (m_attrs.premultipliedAlpha) + return 0; + + RefPtr<ImageData> imageData = ImageData::create(IntSize(m_currentWidth, m_currentHeight)); + unsigned char* pixels = imageData->data()->data()->data(); + int totalBytes = 4 * m_currentWidth * m_currentHeight; + + readRenderingResults(pixels, totalBytes); + + // Convert to RGBA + for (int i = 0; i < totalBytes; i += 4) + std::swap(pixels[i], pixels[i + 2]); + + return imageData.release(); +} + void GraphicsContext3D::reshape(int width, int height) { if (!m_contextObj) @@ -135,19 +173,23 @@ void GraphicsContext3D::reshape(int width, int height) m_currentHeight = height; makeContextCurrent(); - - GLuint internalColorFormat, colorFormat, internalDepthStencilFormat = 0; + validateAttributes(); + + GLuint colorFormat, internalDepthStencilFormat = 0; if (m_attrs.alpha) { - internalColorFormat = GL_RGBA8; + m_internalColorFormat = GL_RGBA8; colorFormat = GL_RGBA; } else { - internalColorFormat = GL_RGB8; + m_internalColorFormat = GL_RGB8; colorFormat = GL_RGB; } if (m_attrs.stencil || m_attrs.depth) { // We don't allow the logic where stencil is required and depth is not. - // See GraphicsContext3D constructor. - if (m_attrs.stencil && m_attrs.depth) + // See GraphicsContext3D::validateAttributes. + + Extensions3D* extensions = getExtensions(); + // Use a 24 bit depth buffer where we know we have it + if (extensions->supports("GL_EXT_packed_depth_stencil")) internalDepthStencilFormat = GL_DEPTH24_STENCIL8_EXT; else internalDepthStencilFormat = GL_DEPTH_COMPONENT; @@ -167,7 +209,7 @@ void GraphicsContext3D::reshape(int width, int height) mustRestoreFBO = true; } ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_multisampleColorBuffer); - ::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, sampleCount, internalColorFormat, width, height); + ::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, sampleCount, m_internalColorFormat, width, height); ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_multisampleColorBuffer); if (m_attrs.stencil || m_attrs.depth) { ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer); @@ -190,8 +232,10 @@ void GraphicsContext3D::reshape(int width, int height) ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); } ::glBindTexture(GL_TEXTURE_2D, m_texture); - ::glTexImage2D(GL_TEXTURE_2D, 0, internalColorFormat, width, height, 0, colorFormat, GL_UNSIGNED_BYTE, 0); + ::glTexImage2D(GL_TEXTURE_2D, 0, m_internalColorFormat, width, height, 0, colorFormat, GL_UNSIGNED_BYTE, 0); ::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_texture, 0); + ::glBindTexture(GL_TEXTURE_2D, m_compositorTexture); + ::glTexImage2D(GL_TEXTURE_2D, 0, m_internalColorFormat, width, height, 0, colorFormat, GL_UNSIGNED_BYTE, 0); ::glBindTexture(GL_TEXTURE_2D, 0); if (!m_attrs.antialias && (m_attrs.stencil || m_attrs.depth)) { ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthStencilBuffer); @@ -278,19 +322,29 @@ IntSize GraphicsContext3D::getInternalFramebufferSize() void GraphicsContext3D::prepareTexture() { + if (m_layerComposited) + return; makeContextCurrent(); if (m_attrs.antialias) { ::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_multisampleFBO); ::glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_fbo); ::glBlitFramebufferEXT(0, 0, m_currentWidth, m_currentHeight, 0, 0, m_currentWidth, m_currentHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); - ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_boundFBO); } + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); + ::glActiveTexture(0); + ::glBindTexture(GL_TEXTURE_2D, m_compositorTexture); + ::glCopyTexImage2D(GL_TEXTURE_2D, 0, m_internalColorFormat, 0, 0, m_currentWidth, m_currentHeight, 0); + ::glBindTexture(GL_TEXTURE_2D, m_boundTexture0); + ::glActiveTexture(m_activeTexture); + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_boundFBO); ::glFinish(); + m_layerComposited = true; } void GraphicsContext3D::activeTexture(GC3Denum texture) { makeContextCurrent(); + m_activeTexture = texture; ::glActiveTexture(texture); } @@ -340,6 +394,8 @@ void GraphicsContext3D::bindRenderbuffer(GC3Denum target, Platform3DObject rende void GraphicsContext3D::bindTexture(GC3Denum target, Platform3DObject texture) { makeContextCurrent(); + if (m_activeTexture && target == GL_TEXTURE_2D) + m_boundTexture0 = texture; ::glBindTexture(target, texture); } @@ -1442,6 +1498,21 @@ void GraphicsContext3D::synthesizeGLError(GC3Denum error) m_syntheticErrors.add(error); } +void GraphicsContext3D::markContextChanged() +{ + m_layerComposited = false; +} + +void GraphicsContext3D::markLayerComposited() +{ + m_layerComposited = true; +} + +bool GraphicsContext3D::layerComposited() const +{ + return m_layerComposited; +} + Extensions3D* GraphicsContext3D::getExtensions() { if (!m_extensions) diff --git a/Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp b/Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp index 2e2082d..9765937 100644 --- a/Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp +++ b/Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp @@ -21,11 +21,11 @@ #include "TextureMapperGL.h" #include "GraphicsContext.h" -#include "HashMap.h" #include "Image.h" -#include "PassRefPtr.h" -#include "RefCounted.h" #include "Timer.h" +#include <wtf/HashMap.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> #if defined(TEXMAP_OPENGL_ES_2) #include <GLES2/gl2.h> diff --git a/Source/WebCore/platform/graphics/opengl/TextureMapperGL.h b/Source/WebCore/platform/graphics/opengl/TextureMapperGL.h index 8035abf..92c5198 100644 --- a/Source/WebCore/platform/graphics/opengl/TextureMapperGL.h +++ b/Source/WebCore/platform/graphics/opengl/TextureMapperGL.h @@ -24,8 +24,8 @@ #include "FloatQuad.h" #include "IntSize.h" +#include "TextureMapper.h" #include "TransformationMatrix.h" -#include "texmap/TextureMapper.h" namespace WebCore { diff --git a/Source/WebCore/platform/graphics/openvg/PathOpenVG.cpp b/Source/WebCore/platform/graphics/openvg/PathOpenVG.cpp index 39a4b06..95df242 100644 --- a/Source/WebCore/platform/graphics/openvg/PathOpenVG.cpp +++ b/Source/WebCore/platform/graphics/openvg/PathOpenVG.cpp @@ -169,7 +169,7 @@ FloatRect Path::boundingRect() const return FloatRect(FloatPoint(minX, minY), FloatSize(width, height)); } -FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) +FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) const { notImplemented(); @@ -464,7 +464,7 @@ void Path::transform(const AffineTransform& transformation) // functions and Path::apply() doesn't really work as long as we rely on VGPath // as primary path storage. -float Path::length() +float Path::length() const { m_path->makeCompatibleContextCurrent(); VGfloat length = vgPathLength(m_path->vgPath(), 0, vgGetParameteri(m_path->vgPath(), VG_PATH_NUM_SEGMENTS)); @@ -472,7 +472,7 @@ float Path::length() return length; } -FloatPoint Path::pointAtLength(float length, bool& ok) +FloatPoint Path::pointAtLength(float length, bool& ok) const { VGfloat x = 0, y = 0; m_path->makeCompatibleContextCurrent(); @@ -483,7 +483,7 @@ FloatPoint Path::pointAtLength(float length, bool& ok) return FloatPoint(x, y); } -float Path::normalAngleAtLength(float length, bool& ok) +float Path::normalAngleAtLength(float length, bool& ok) const { VGfloat tangentX, tangentY; m_path->makeCompatibleContextCurrent(); diff --git a/Source/WebCore/platform/graphics/pango/FontCustomPlatformDataPango.cpp b/Source/WebCore/platform/graphics/pango/FontCustomPlatformDataPango.cpp index f9d36d3..deff9f7 100644 --- a/Source/WebCore/platform/graphics/pango/FontCustomPlatformDataPango.cpp +++ b/Source/WebCore/platform/graphics/pango/FontCustomPlatformDataPango.cpp @@ -30,7 +30,7 @@ FontCustomPlatformData::~FontCustomPlatformData() { } -FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontWidthVariant, FontRenderingMode) +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, TextOrientation, FontWidthVariant, FontRenderingMode) { return FontPlatformData(m_fontFace, size, bold, italic); } diff --git a/Source/WebCore/platform/graphics/pango/FontPlatformData.h b/Source/WebCore/platform/graphics/pango/FontPlatformData.h index 2929a3f..180d23b 100644 --- a/Source/WebCore/platform/graphics/pango/FontPlatformData.h +++ b/Source/WebCore/platform/graphics/pango/FontPlatformData.h @@ -74,7 +74,7 @@ public: unsigned hash() const { uintptr_t hashCodes[1] = { reinterpret_cast<uintptr_t>(m_scaledFont) }; - return WTF::StringHasher::createBlobHash<sizeof(hashCodes)>(hashCodes); + return StringHasher::hashMemory<sizeof(hashCodes)>(hashCodes); } bool operator==(const FontPlatformData&) const; diff --git a/Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp b/Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp index dcea72f..3adc93f 100644 --- a/Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp +++ b/Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp @@ -30,6 +30,7 @@ #include "Extensions3DQt.h" #include "GraphicsContext3D.h" +#include <QGLContext> namespace WebCore { diff --git a/Source/WebCore/platform/graphics/qt/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/qt/FontCustomPlatformData.h index e8441d2..3996d22 100644 --- a/Source/WebCore/platform/graphics/qt/FontCustomPlatformData.h +++ b/Source/WebCore/platform/graphics/qt/FontCustomPlatformData.h @@ -25,6 +25,7 @@ #include "FontOrientation.h" #include "FontRenderingMode.h" #include "FontWidthVariant.h" +#include "TextOrientation.h" #include <wtf/FastAllocBase.h> #include <wtf/Forward.h> #include <wtf/Noncopyable.h> @@ -43,7 +44,8 @@ public: // for use with QFontDatabase::addApplicationFont/removeApplicationFont int m_handle; - FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontWidthVariant = RegularWidth, FontRenderingMode = NormalRenderingMode); + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, TextOrientation = TextOrientationVerticalRight, + FontWidthVariant = RegularWidth, FontRenderingMode = NormalRenderingMode); static bool supportsFormat(const String&); }; diff --git a/Source/WebCore/platform/graphics/qt/FontCustomPlatformDataQt.cpp b/Source/WebCore/platform/graphics/qt/FontCustomPlatformDataQt.cpp index ec8747d..20f161a 100644 --- a/Source/WebCore/platform/graphics/qt/FontCustomPlatformDataQt.cpp +++ b/Source/WebCore/platform/graphics/qt/FontCustomPlatformDataQt.cpp @@ -34,7 +34,7 @@ FontCustomPlatformData::~FontCustomPlatformData() QFontDatabase::removeApplicationFont(m_handle); } -FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontWidthVariant, FontRenderingMode) +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, TextOrientation, FontWidthVariant, FontRenderingMode) { QFont font; font.setFamily(QFontDatabase::applicationFontFamilies(m_handle)[0]); diff --git a/Source/WebCore/platform/graphics/qt/FontPlatformData.h b/Source/WebCore/platform/graphics/qt/FontPlatformData.h index 32e8a2d..4a92acf 100644 --- a/Source/WebCore/platform/graphics/qt/FontPlatformData.h +++ b/Source/WebCore/platform/graphics/qt/FontPlatformData.h @@ -141,6 +141,7 @@ public: } FontOrientation orientation() const { return Horizontal; } // FIXME: Implement. + void setOrientation(FontOrientation) { } // FIXME: Implement. unsigned hash() const; diff --git a/Source/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp b/Source/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp index 185ae85..95dabd5 100644 --- a/Source/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp +++ b/Source/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp @@ -73,9 +73,7 @@ FontPlatformData::FontPlatformData(const FontDescription& description, const Ato font.setLetterSpacing(QFont::AbsoluteSpacing, letterSpacing); const bool smallCaps = description.smallCaps(); font.setCapitalization(smallCaps ? QFont::SmallCaps : QFont::MixedCase); -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) font.setStyleStrategy(QFont::ForceIntegerMetrics); -#endif m_data->bold = font.bold(); // WebKit allows font size zero but QFont does not. We will return diff --git a/Source/WebCore/platform/graphics/qt/FontQt.cpp b/Source/WebCore/platform/graphics/qt/FontQt.cpp index 646cd0e..3fe90a4 100644 --- a/Source/WebCore/platform/graphics/qt/FontQt.cpp +++ b/Source/WebCore/platform/graphics/qt/FontQt.cpp @@ -169,21 +169,16 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float p->restore(); return; } -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) int skipWidth = QFontMetrics(font).width(string, from, Qt::TextBypassShaping); pt.setX(pt.x() + skipWidth); string = fromRawDataWithoutRef(sanitized, from, to - from); -#endif } p->setFont(font); int flags = run.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight; -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) - // See QWebPagePrivate::QWebPagePrivate() where the default path is set to Complex for Qt 4.6 and earlier. if (!isComplexText && !(ctx->textDrawingMode() & TextModeStroke)) flags |= Qt::TextBypassShaping; -#endif QPainterPath textStrokePath; if (ctx->textDrawingMode() & TextModeStroke) @@ -200,11 +195,7 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float p->restore(); } else { QFontMetrics fm(font); -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) QRectF boundingRect(pt.x(), point.y() - fm.ascent(), fm.width(string, -1, flags), fm.height()); -#else - QRectF boundingRect(pt.x(), point.y() - fm.ascent(), fm.width(string), fm.height()); -#endif QPainter* shadowPainter = ctxShadow->beginShadowLayer(ctx, boundingRect); if (shadowPainter) { // Since it will be blurred anyway, we don't care about render hints. @@ -221,11 +212,7 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float p->translate(-ctxShadow->offset()); } else { QFontMetrics fm(font); -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) QRectF boundingRect(pt.x(), point.y() - fm.ascent(), fm.width(string, -1, flags), fm.height()); -#else - QRectF boundingRect(pt.x(), point.y() - fm.ascent(), fm.width(string), fm.height()); -#endif QPainter* shadowPainter = ctxShadow->beginShadowLayer(ctx, boundingRect); if (shadowPainter) { // Since it will be blurred anyway, we don't care about render hints. @@ -250,11 +237,7 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float void Font::drawSimpleText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const { -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) drawTextCommon(ctx, run, point, from, to, font(), /* isComplexText = */false); -#else - Q_ASSERT(false); -#endif } void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const @@ -295,7 +278,6 @@ float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer if (!primaryFont()->platformData().size()) return 0; -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) if (!run.length()) return 0; @@ -309,10 +291,6 @@ float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer w -= m_wordSpacing; return w + run.expansion(); -#else - Q_ASSERT(false); - return 0; -#endif } float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*, GlyphOverflow*) const @@ -339,7 +317,6 @@ float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon int Font::offsetForPositionForSimpleText(const TextRun& run, float position, bool includePartialGlyphs) const { -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) String sanitized = Font::normalizeSpaces(run.characters(), run.length()); QString string = fromRawDataWithoutRef(sanitized); @@ -359,10 +336,6 @@ int Font::offsetForPositionForSimpleText(const TextRun& run, float position, boo } while (++curPos < string.size()); return curPos; -#else - Q_ASSERT(false); - return 0; -#endif } int Font::offsetForPositionForComplexText(const TextRun& run, float position, bool) const @@ -377,7 +350,6 @@ int Font::offsetForPositionForComplexText(const TextRun& run, float position, bo FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& pt, int h, int from, int to) const { -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) String sanitized = Font::normalizeSpaces(run.characters(), run.length()); QString wholeText = fromRawDataWithoutRef(sanitized); QString selectedText = fromRawDataWithoutRef(sanitized, from, qMin(to - from, wholeText.length() - from)); @@ -386,10 +358,6 @@ FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& int width = QFontMetrics(font()).width(selectedText, -1, Qt::TextBypassShaping); return FloatRect(pt.x() + startX, pt.y(), width, h); -#else - Q_ASSERT(false); - return FloatRect(); -#endif } FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& pt, int h, int from, int to) const diff --git a/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp b/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp index b849214..4daa4dc 100644 --- a/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp +++ b/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp @@ -27,10 +27,14 @@ #include "HTMLCanvasElement.h" #include "HostWindow.h" #include "ImageBuffer.h" +#include "ImageData.h" #include "NotImplemented.h" #include "QWebPageClient.h" +#include "qwebpage.h" #include <QAbstractScrollArea> +#include <QGraphicsObject> #include <QGLContext> +#include <QStyleOptionGraphicsItem> #include <wtf/UnusedParam.h> #include <wtf/text/CString.h> @@ -42,6 +46,10 @@ namespace WebCore { typedef char GLchar; #endif +#if !defined(GL_DEPTH24_STENCIL8) +#define GL_DEPTH24_STENCIL8 0x88F0 +#endif + #if !defined(APIENTRY) #define APIENTRY #endif @@ -145,13 +153,17 @@ typedef void (APIENTRY* glVertexAttrib4fType) (GLuint, const GLfloat, const GLfl typedef void (APIENTRY* glVertexAttrib4fvType) (GLuint, const GLfloat*); typedef void (APIENTRY* glVertexAttribPointerType) (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid*); -class GraphicsContext3DInternal { +class GraphicsContext3DInternal : public QGraphicsObject { public: GraphicsContext3DInternal(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow); ~GraphicsContext3DInternal(); - bool isContextValid() { return m_contextValid; } - QGLWidget* getOwnerGLWidget(QWebPageClient* webPageClient); + bool isValid() { return m_valid; } + + QGLWidget* getViewportGLWidget(); + void reshape(int width, int height); + void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*); + QRectF boundingRect() const; glActiveTextureType activeTexture; glAttachShaderType attachShader; @@ -247,11 +259,13 @@ public: GraphicsContext3D::Attributes m_attrs; HostWindow* m_hostWindow; QGLWidget* m_glWidget; + QGLWidget* m_viewportGLWidget; + QRectF m_boundingRect; GLuint m_texture; - GLuint m_mainFbo; + GLuint m_canvasFbo; GLuint m_currentFbo; GLuint m_depthBuffer; - QImage m_pixels; + bool m_layerComposited; ListHashSet<unsigned int> m_syntheticErrors; OwnPtr<Extensions3DQt> m_extensions; @@ -259,7 +273,7 @@ public: private: void* getProcAddress(const String& proc); - bool m_contextValid; + bool m_valid; }; #if defined (QT_OPENGL_ES_2) @@ -281,39 +295,37 @@ GraphicsContext3DInternal::GraphicsContext3DInternal(GraphicsContext3D::Attribut : m_attrs(attrs) , m_hostWindow(hostWindow) , m_glWidget(0) + , m_viewportGLWidget(0) , m_texture(0) - , m_mainFbo(0) + , m_canvasFbo(0) , m_currentFbo(0) , m_depthBuffer(0) - , m_contextValid(true) + , m_layerComposited(false) + , m_valid(true) { - QWebPageClient* webPageClient = hostWindow->platformPageClient(); - QGLWidget* ownerGLWidget = getOwnerGLWidget(webPageClient); + m_viewportGLWidget = getViewportGLWidget(); - if (ownerGLWidget) - m_glWidget = new QGLWidget(0, ownerGLWidget); - else { - QGLFormat format; - format.setDepth(true); - format.setSampleBuffers(true); - format.setStencil(false); - - m_glWidget = new QGLWidget(format); - } + if (m_viewportGLWidget) + m_glWidget = new QGLWidget(0, m_viewportGLWidget); + else + m_glWidget = new QGLWidget(); if (!m_glWidget->isValid()) { - LOG_ERROR("GraphicsContext3D: QGLWidget does not have a valid context"); - m_contextValid = false; + LOG_ERROR("GraphicsContext3D: QGLWidget initialization failed."); + m_valid = false; return; } - - QGLFormat format = m_glWidget->format(); - m_attrs.alpha = format.alpha(); - m_attrs.depth = format.depth(); - m_attrs.stencil = format.stencil(); + // Geometry can be set to zero because m_glWidget is used only for its QGLContext. + m_glWidget->setGeometry(0, 0, 0, 0); + +#if defined(QT_OPENGL_ES_2) + m_attrs.stencil = false; +#else + if (m_attrs.stencil) + m_attrs.depth = true; +#endif m_attrs.antialias = false; - m_attrs.premultipliedAlpha = true; m_glWidget->makeCurrent(); @@ -408,60 +420,165 @@ GraphicsContext3DInternal::GraphicsContext3DInternal(GraphicsContext3D::Attribut vertexAttrib4fv = GET_PROC_ADDRESS(glVertexAttrib4fv); vertexAttribPointer = GET_PROC_ADDRESS(glVertexAttribPointer); - if (!m_contextValid) { + if (!m_valid) { LOG_ERROR("GraphicsContext3D: All needed OpenGL extensions are not available"); - m_contextValid = false; return; } + // Create buffers for the canvas FBO. + genFramebuffers(/* count */ 1, &m_canvasFbo); + glGenTextures(1, &m_texture); glBindTexture(GraphicsContext3D::TEXTURE_2D, m_texture); glTexParameterf(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR); glTexParameterf(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR); glTexParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE); glTexParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE); - glTexImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, 1, 1, 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, 0); glBindTexture(GraphicsContext3D::TEXTURE_2D, 0); - genFramebuffers(/* count */ 1, &m_mainFbo); - m_currentFbo = m_mainFbo; + if (m_attrs.depth) + genRenderbuffers(/* count */ 1, &m_depthBuffer); + + // Bind canvas FBO and set initial clear color to black. + m_currentFbo = m_canvasFbo; + bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_canvasFbo); + glClearColor(0.0, 0.0, 0.0, 0.0); +} + +GraphicsContext3DInternal::~GraphicsContext3DInternal() +{ + delete m_glWidget; + m_glWidget = 0; +} + +QGLWidget* GraphicsContext3DInternal::getViewportGLWidget() +{ + QWebPageClient* webPageClient = m_hostWindow->platformPageClient(); + if (!webPageClient) + return 0; + + QAbstractScrollArea* scrollArea = qobject_cast<QAbstractScrollArea*>(webPageClient->ownerWidget()); + if (scrollArea) + return qobject_cast<QGLWidget*>(scrollArea->viewport()); + + return 0; +} + +static inline quint32 swapBgrToRgb(quint32 pixel) +{ + return ((pixel << 16) & 0xff0000) | ((pixel >> 16) & 0xff) | (pixel & 0xff00ff00); +} + +void GraphicsContext3DInternal::reshape(int width, int height) +{ + if (width == m_boundingRect.width() && height == m_boundingRect.height()) + return; + + m_boundingRect = QRectF(QPointF(0, 0), QSizeF(width, height)); + + m_glWidget->makeCurrent(); - bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_mainFbo); + // Create color buffer + glBindTexture(GraphicsContext3D::TEXTURE_2D, m_texture); + if (m_attrs.alpha) + glTexImage2D(GraphicsContext3D::TEXTURE_2D, /* level */ 0, GraphicsContext3D::RGBA, width, height, /* border */ 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, /* data */ 0); + else + glTexImage2D(GraphicsContext3D::TEXTURE_2D, /* level */ 0, GraphicsContext3D::RGB, width, height, /* border */ 0, GraphicsContext3D::RGB, GraphicsContext3D::UNSIGNED_BYTE, /* data */ 0); + glBindTexture(GraphicsContext3D::TEXTURE_2D, 0); - genRenderbuffers(/* count */ 1, &m_depthBuffer); - bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_depthBuffer); + if (m_attrs.depth) { + // Create depth and stencil buffers. + bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_depthBuffer); #if defined(QT_OPENGL_ES_2) - renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT16, /* width */ 1, /* height */ 1); + renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT16, width, height); #else - renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT, /* width */ 1, /* height */ 1); + if (m_attrs.stencil) + renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); + else + renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT, width, height); #endif + bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0); + } - bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0); - + // Construct canvas FBO. + bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_canvasFbo); framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_texture, 0); - framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_depthBuffer); - glClearColor(/* red */ 0, /* green */ 0, /* blue */ 0, /* alpha */ 0); + if (m_attrs.depth) + framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_depthBuffer); +#if !defined(QT_OPENGL_ES_2) + if (m_attrs.stencil) + framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_depthBuffer); +#endif - if (checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) { - LOG_ERROR("GraphicsContext3D: Wasn't able to create the main framebuffer"); - m_contextValid = false; + GLenum status = checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER); + if (status != GraphicsContext3D::FRAMEBUFFER_COMPLETE) { + LOG_ERROR("GraphicsContext3D: Canvas FBO initialization failed."); + return; } -} -GraphicsContext3DInternal::~GraphicsContext3DInternal() -{ - delete m_glWidget; - m_glWidget = 0; + int clearFlags = GraphicsContext3D::COLOR_BUFFER_BIT; + if (m_attrs.depth) + clearFlags |= GraphicsContext3D::DEPTH_BUFFER_BIT; + if (m_attrs.stencil) + clearFlags |= GraphicsContext3D::STENCIL_BUFFER_BIT; + + glClear(clearFlags); + glFlush(); } -QGLWidget* GraphicsContext3DInternal::getOwnerGLWidget(QWebPageClient* webPageClient) +void GraphicsContext3DInternal::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { - QAbstractScrollArea* scrollArea = qobject_cast<QAbstractScrollArea*>(webPageClient->ownerWidget()); + Q_UNUSED(widget); - if (scrollArea) - return qobject_cast<QGLWidget*>(scrollArea->viewport()); + QRectF rect = option ? option->rect : boundingRect(); - return 0; + // Use direct texture mapping if WebGL canvas has a shared OpenGL context + // with browsers OpenGL context. + QGLWidget* viewportGLWidget = getViewportGLWidget(); + if (viewportGLWidget && viewportGLWidget == m_viewportGLWidget && viewportGLWidget == painter->device()) { + viewportGLWidget->drawTexture(rect, m_texture); + return; + } + + // Alternatively read pixels to a memory buffer. + QImage offscreenImage(rect.width(), rect.height(), QImage::Format_ARGB32); + quint32* imagePixels = reinterpret_cast<quint32*>(offscreenImage.bits()); + + m_glWidget->makeCurrent(); + bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_canvasFbo); + glReadPixels(/* x */ 0, /* y */ 0, rect.width(), rect.height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, imagePixels); + + bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_currentFbo); + + // OpenGL gives us ABGR on 32 bits, and with the origin at the bottom left + // We need RGB32 or ARGB32_PM, with the origin at the top left. + quint32* pixelsSrc = imagePixels; + const int height = static_cast<int>(rect.height()); + const int width = static_cast<int>(rect.width()); + const int halfHeight = height / 2; + for (int row = 0; row < halfHeight; ++row) { + const int targetIdx = (height - 1 - row) * width; + quint32* pixelsDst = imagePixels + targetIdx; + for (int column = 0; column < width; ++column) { + quint32 tempPixel = *pixelsSrc; + *pixelsSrc = swapBgrToRgb(*pixelsDst); + *pixelsDst = swapBgrToRgb(tempPixel); + ++pixelsSrc; + ++pixelsDst; + } + } + if (static_cast<int>(height) % 2) { + for (int column = 0; column < width; ++column) { + *pixelsSrc = swapBgrToRgb(*pixelsSrc); + ++pixelsSrc; + } + } + painter->drawImage(/* x */ 0, /* y */ 0, offscreenImage); +} + +QRectF GraphicsContext3DInternal::boundingRect() const +{ + return m_boundingRect; } void* GraphicsContext3DInternal::getProcAddress(const String& proc) @@ -477,7 +594,7 @@ void* GraphicsContext3DInternal::getProcAddress(const String& proc) } LOG_ERROR("GraphicsContext3D: Did not find GL function %s", proc.utf8().data()); - m_contextValid = false; + m_valid = false; return 0; } @@ -493,7 +610,7 @@ PassRefPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attri GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow, bool) : m_internal(new GraphicsContext3DInternal(attrs, hostWindow)) { - if (!m_internal->isContextValid()) + if (!m_internal->isValid()) m_internal = 0; } @@ -511,6 +628,11 @@ Platform3DObject GraphicsContext3D::platformTexture() const return m_internal->m_texture; } +PlatformLayer* GraphicsContext3D::platformLayer() const +{ + return m_internal.get(); +} + void GraphicsContext3D::makeContextCurrent() { m_internal->m_glWidget->makeCurrent(); @@ -522,62 +644,25 @@ void GraphicsContext3D::paintRenderingResultsToCanvas(CanvasRenderingContext* co HTMLCanvasElement* canvas = context->canvas(); ImageBuffer* imageBuffer = canvas->buffer(); QPainter* painter = imageBuffer->context()->platformContext(); - paint(painter, QRect(QPoint(0, 0), QSize(m_currentWidth, m_currentHeight))); + m_internal->paint(painter, 0, 0); } -void GraphicsContext3D::paint(QPainter* painter, const QRect& rect) const +PassRefPtr<ImageData> GraphicsContext3D::paintRenderingResultsToImageData() { -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) - QWebPageClient* webPageClient = m_internal->m_hostWindow->platformPageClient(); - QGLWidget* ownerGLWidget = m_internal->getOwnerGLWidget(webPageClient); - if (ownerGLWidget) { - ownerGLWidget->drawTexture(rect, m_internal->m_texture); - return; - } -#endif - m_internal->m_glWidget->makeCurrent(); - m_internal->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_internal->m_mainFbo); - glReadPixels(/* x */ 0, /* y */ 0, m_currentWidth, m_currentHeight, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, m_internal->m_pixels.bits()); - painter->drawImage(/* x */ 0, /* y */ 0, m_internal->m_pixels.rgbSwapped().transformed(QMatrix().rotate(180))); - m_internal->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_internal->m_currentFbo); + // FIXME: This needs to be implemented for proper non-premultiplied-alpha + // support. + return 0; } 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; m_currentHeight = height; - m_internal->m_pixels = QImage(m_currentWidth, m_currentHeight, QImage::Format_ARGB32); - - m_internal->m_glWidget->makeCurrent(); - - glBindTexture(GraphicsContext3D::TEXTURE_2D, m_internal->m_texture); - glTexImage2D(GraphicsContext3D::TEXTURE_2D, /* level */ 0, GraphicsContext3D::RGBA, width, height, /* border */ 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, /* data */ 0); - glBindTexture(GraphicsContext3D::TEXTURE_2D, 0); - - m_internal->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_internal->m_mainFbo); - m_internal->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_internal->m_depthBuffer); -#if defined(QT_OPENGL_ES_2) - renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT16, width, height); -#else - renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT, width, height); -#endif - m_internal->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0); - - m_internal->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_internal->m_texture, 0); - m_internal->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_internal->m_depthBuffer); - - GLenum status = m_internal->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER); - if (status != GraphicsContext3D::FRAMEBUFFER_COMPLETE) { - LOG_ERROR("GraphicsContext3D: Wasn't able to reshape the main framebuffer"); - notImplemented(); - } - - glClear(GraphicsContext3D::COLOR_BUFFER_BIT); - glFlush(); + m_internal->reshape(width, height); } IntSize GraphicsContext3D::getInternalFramebufferSize() @@ -626,7 +711,7 @@ void GraphicsContext3D::bindBuffer(GC3Denum target, Platform3DObject buffer) void GraphicsContext3D::bindFramebuffer(GC3Denum target, Platform3DObject buffer) { m_internal->m_glWidget->makeCurrent(); - m_internal->m_currentFbo = buffer ? buffer : m_internal->m_mainFbo; + m_internal->m_currentFbo = buffer ? buffer : m_internal->m_canvasFbo; m_internal->bindFramebuffer(target, m_internal->m_currentFbo); } @@ -1064,6 +1149,23 @@ void GraphicsContext3D::releaseShaderCompiler() void GraphicsContext3D::renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height) { m_internal->m_glWidget->makeCurrent(); +#if !defined(QT_OPENGL_ES_2) + switch (internalformat) { + case DEPTH_STENCIL: + internalformat = GL_DEPTH24_STENCIL8; + break; + case DEPTH_COMPONENT16: + internalformat = DEPTH_COMPONENT; + break; + case RGBA4: + case RGB5_A1: + internalformat = RGBA; + break; + case RGB565: + internalformat = RGB; + break; + } +#endif m_internal->renderbufferStorage(target, internalformat, width, height); } @@ -1598,6 +1700,22 @@ void GraphicsContext3D::synthesizeGLError(GC3Denum error) m_internal->m_syntheticErrors.add(error); } +void GraphicsContext3D::markLayerComposited() +{ + m_internal->m_layerComposited = true; +} + +void GraphicsContext3D::markContextChanged() +{ + // FIXME: Any accelerated compositor needs to be told to re-read from here. + m_internal->m_layerComposited = false; +} + +bool GraphicsContext3D::layerComposited() const +{ + return m_internal->m_layerComposited; +} + Extensions3D* GraphicsContext3D::getExtensions() { if (!m_internal->m_extensions) diff --git a/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp index 9742755..e3e0fa6 100644 --- a/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp +++ b/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -9,6 +9,7 @@ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). * Copyright (C) 2008 Dirk Schulze <vbs85@gmx.de> * Copyright (C) 2010, 2011 Sencha, Inc. + * Copyright (C) 2011 Andreas Kling <kling@webkit.org> * * All rights reserved. * @@ -672,8 +673,6 @@ void GraphicsContext::fillRect(const FloatRect& rect) ContextShadow* shadow = contextShadow(); if (m_state.fillPattern) { - AffineTransform affine; - QBrush brush(m_state.fillPattern->createPlatformPattern(affine)); QPixmap* image = m_state.fillPattern->tileImage()->nativeImageForCurrentFrame(); QPainter* shadowPainter = hasShadow() ? shadow->beginShadowLayer(this, normalizedRect) : 0; if (shadowPainter) { diff --git a/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp b/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp index f3cfc47..1f77fc2 100644 --- a/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp +++ b/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp @@ -310,10 +310,6 @@ public: } } m_state; -#if ENABLE(WEBGL) - const GraphicsContext3D* m_gc3D; -#endif - #ifndef QT_NO_ANIMATION friend class AnimationQtBase; #endif @@ -340,9 +336,6 @@ GraphicsLayerQtImpl::GraphicsLayerQtImpl(GraphicsLayerQt* newLayer) #if ENABLE(TILED_BACKING_STORE) , m_tiledBackingStore(0) #endif -#if ENABLE(WEBGL) - , m_gc3D(0) -#endif { // We use graphics-view for compositing-only, not for interactivity. setAcceptedMouseButtons(Qt::NoButton); @@ -665,11 +658,6 @@ void GraphicsLayerQtImpl::paint(QPainter* painter, const QStyleOptionGraphicsIte case MediaContentType: // we don't need to paint anything: we have a QGraphicsItem from the media element break; -#if ENABLE(WEBGL) - case Canvas3DContentType: - m_gc3D->paint(painter, option->rect); - break; -#endif } } @@ -808,16 +796,6 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform setFlag(ItemHasNoContents, !m_layer->drawsContent()); break; - -#if ENABLE(WEBGL) - case Canvas3DContentType: - if (m_pendingContent.contentType != m_currentContent.contentType) - update(); - - setCacheMode(NoCache); - setFlag(ItemHasNoContents, false); - break; -#endif } } @@ -1268,23 +1246,6 @@ void GraphicsLayerQt::setContentsBackgroundColor(const Color& color) GraphicsLayer::setContentsBackgroundColor(color); } -#if ENABLE(WEBGL) -void GraphicsLayerQt::setContentsToGraphicsContext3D(const GraphicsContext3D* ctx) -{ - if (ctx == m_impl->m_gc3D) - return; - - m_impl->m_pendingContent.contentType = GraphicsLayerQtImpl::Canvas3DContentType; - m_impl->m_gc3D = ctx; - m_impl->notifyChange(GraphicsLayerQtImpl::ContentChange); -} - -void GraphicsLayerQt::setGraphicsContext3DNeedsDisplay() -{ - setNeedsDisplay(); -} -#endif - void GraphicsLayerQt::setContentsToMedia(PlatformLayer* media) { if (media) { @@ -1297,6 +1258,11 @@ void GraphicsLayerQt::setContentsToMedia(PlatformLayer* media) GraphicsLayer::setContentsToMedia(media); } +void GraphicsLayerQt::setContentsToCanvas(PlatformLayer* canvas) +{ + setContentsToMedia(canvas); +} + /* \reimp (GraphicsLayer.h) */ void GraphicsLayerQt::setContentsOrientation(CompositingCoordinatesOrientation orientation) diff --git a/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.h b/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.h index 569bd8d..2af98fd 100644 --- a/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.h +++ b/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.h @@ -20,9 +20,6 @@ #ifndef GraphicsLayerQt_h #define GraphicsLayerQt_h -#if ENABLE(WEBGL) -#include "GraphicsContext3D.h" -#endif #include "GraphicsLayer.h" #include "GraphicsLayerClient.h" @@ -78,11 +75,8 @@ public: virtual void setContentsToImage(Image*); virtual void setContentsNeedsDisplay(); virtual void setContentsToMedia(PlatformLayer*); + virtual void setContentsToCanvas(PlatformLayer*); virtual void setContentsBackgroundColor(const Color&); -#if ENABLE(WEBGL) - virtual void setContentsToGraphicsContext3D(const GraphicsContext3D*); - virtual void setGraphicsContext3DNeedsDisplay(); -#endif virtual void setContentsOrientation(CompositingCoordinatesOrientation orientation); virtual void distributeOpacity(float); virtual float accumulatedOpacity() const; diff --git a/Source/WebCore/platform/graphics/qt/ImageBufferData.h b/Source/WebCore/platform/graphics/qt/ImageBufferData.h index aa32253..602197e 100644 --- a/Source/WebCore/platform/graphics/qt/ImageBufferData.h +++ b/Source/WebCore/platform/graphics/qt/ImageBufferData.h @@ -42,6 +42,8 @@ class ImageBufferData { public: ImageBufferData(const IntSize&); + QImage toQImage() const; + QPixmap m_pixmap; OwnPtr<QPainter> m_painter; RefPtr<Image> m_image; diff --git a/Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp index 62f5c3e..f7d63ca 100644 --- a/Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp +++ b/Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp @@ -80,6 +80,21 @@ ImageBufferData::ImageBufferData(const IntSize& size) m_image = StillImage::createForRendering(&m_pixmap); } +QImage ImageBufferData::toQImage() const +{ + QPaintEngine* paintEngine = m_pixmap.paintEngine(); + if (!paintEngine || paintEngine->type() != QPaintEngine::Raster) + return m_pixmap.toImage(); + + // QRasterPixmapData::toImage() will deep-copy the backing QImage if there's an active QPainter on it. + // For performance reasons, we don't want that here, so we temporarily redirect the paint engine. + QPaintDevice* currentPaintDevice = paintEngine->paintDevice(); + paintEngine->setPaintDevice(0); + QImage image = m_pixmap.toImage(); + paintEngine->setPaintDevice(currentPaintDevice); + return image; +} + ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode, bool& success) : m_data(size) , m_size(size) @@ -159,7 +174,7 @@ void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) if (isPainting) m_data.m_painter->end(); - QImage image = m_data.m_pixmap.toImage().convertToFormat(QImage::Format_ARGB32); + QImage image = m_data.toQImage().convertToFormat(QImage::Format_ARGB32); ASSERT(!image.isNull()); uchar* bits = image.bits(); @@ -214,16 +229,12 @@ PassRefPtr<ByteArray> getImageData(const IntRect& rect, const ImageBufferData& i int numRows = endy - originy; // NOTE: For unmultiplied data, we undo the premultiplication below. - QImage image = imageData.m_pixmap.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied); + QImage image = imageData.toQImage().convertToFormat(QImage::Format_ARGB32_Premultiplied); ASSERT(!image.isNull()); const int bytesPerLine = image.bytesPerLine(); -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) const uchar* bits = image.constBits(); -#else - const uchar* bits = image.bits(); -#endif quint32* destRows = reinterpret_cast_ptr<quint32*>(&data[desty * rect.width() * 4 + destx * 4]); diff --git a/Source/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/Source/WebCore/platform/graphics/qt/ImageDecoderQt.cpp index 3540994..8cda231 100644 --- a/Source/WebCore/platform/graphics/qt/ImageDecoderQt.cpp +++ b/Source/WebCore/platform/graphics/qt/ImageDecoderQt.cpp @@ -194,15 +194,7 @@ void ImageDecoderQt::internalReadImage(size_t frameIndex) bool ImageDecoderQt::internalHandleCurrentImage(size_t frameIndex) { - QPixmap pixmap; - -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) - pixmap = QPixmap::fromImageReader(m_reader.get()); -#else - QImage img; - if (m_reader->read(&img)) - pixmap = QPixmap::fromImage(img); -#endif + QPixmap pixmap = QPixmap::fromImageReader(m_reader.get()); if (pixmap.isNull()) { frameCount(); diff --git a/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp index 001d45b..bc43acf 100644 --- a/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp +++ b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp @@ -74,7 +74,7 @@ void MediaPlayerPrivateQt::getSupportedTypes(HashSet<String> &supported) for (int i = 0; i < types.size(); i++) { QString mime = types.at(i); - if (mime.startsWith("audio/") || mime.startsWith("video/")) + if (mime.startsWith(QString::fromLatin1("audio/")) || mime.startsWith(QString::fromLatin1("video/"))) supported.add(mime); } } @@ -103,7 +103,6 @@ MediaPlayerPrivateQt::MediaPlayerPrivateQt(MediaPlayer* player) , m_isVisible(false) , m_isSeeking(false) , m_composited(false) - , m_queuedSeek(-1) , m_preload(MediaPlayer::Auto) , m_suppressNextPlaybackChanged(false) { @@ -195,7 +194,7 @@ void MediaPlayerPrivateQt::commitLoad(const String& url) HTMLMediaElement* element = static_cast<HTMLMediaElement*>(m_webCorePlayer->mediaPlayerClient()); // Construct the media content with a network request if the resource is http[s] - if (scheme == "http" || scheme == "https") { + if (scheme == QString::fromLatin1("http") || scheme == QString::fromLatin1("https")) { QNetworkRequest request = QNetworkRequest(rUrl); // Grab the current document @@ -220,7 +219,7 @@ void MediaPlayerPrivateQt::commitLoad(const String& url) // Set the refferer, but not when requesting insecure content from a secure page QUrl documentUrl = QUrl(QString(document->documentURI())); - if (documentUrl.scheme().toLower() == "http" || scheme == "https") + if (documentUrl.scheme().toLower() == QString::fromLatin1("http") || scheme == QString::fromLatin1("https")) request.setRawHeader("Referer", documentUrl.toEncoded()); // Set the user agent @@ -296,32 +295,8 @@ void MediaPlayerPrivateQt::seek(float position) if (m_mediaPlayerControl && !m_mediaPlayerControl->availablePlaybackRanges().contains(position * 1000)) return; - if (m_isSeeking) - return; - - if (position > duration()) - position = duration(); - - // Seeking is most reliable when we're paused. - // Webkit will try to pause before seeking, but due to the asynchronous nature - // of the backend, the player may not actually be paused yet. - // In this case, we should queue the seek and wait until pausing has completed - // before attempting to seek. - if (m_mediaPlayer->state() == QMediaPlayer::PlayingState) { - m_mediaPlayer->pause(); - m_isSeeking = true; - m_queuedSeek = static_cast<qint64>(position * 1000); - - // Set a timeout, so that in the event that we don't get a state changed - // signal, we still attempt the seek. - QTimer::singleShot(1000, this, SLOT(queuedSeekTimeout())); - } else { - m_isSeeking = true; - m_mediaPlayer->setPosition(static_cast<qint64>(position * 1000)); - - // Set a timeout, in case we don't get a position changed signal - QTimer::singleShot(10000, this, SLOT(seekTimeout())); - } + m_isSeeking = true; + m_mediaPlayer->setPosition(static_cast<qint64>(position * 1000)); } bool MediaPlayerPrivateQt::seeking() const @@ -443,13 +418,8 @@ void MediaPlayerPrivateQt::handleError(QMediaPlayer::Error) updateStates(); } -void MediaPlayerPrivateQt::stateChanged(QMediaPlayer::State state) +void MediaPlayerPrivateQt::stateChanged(QMediaPlayer::State) { - if (state != QMediaPlayer::PlayingState && m_isSeeking && m_queuedSeek >= 0) { - m_mediaPlayer->setPosition(m_queuedSeek); - m_queuedSeek = -1; - } - if (!m_suppressNextPlaybackChanged) m_webCorePlayer->playbackStateChanged(); else @@ -468,34 +438,12 @@ void MediaPlayerPrivateQt::nativeSizeChanged(const QSizeF& size) m_webCorePlayer->sizeChanged(); } -void MediaPlayerPrivateQt::queuedSeekTimeout() -{ - // If we haven't heard anything, assume the player is now paused - // and we can attempt the seek - if (m_isSeeking && m_queuedSeek >= 0) { - m_mediaPlayer->setPosition(m_queuedSeek); - m_queuedSeek = -1; - - // Set a timeout, in case we don't get a position changed signal - QTimer::singleShot(10000, this, SLOT(seekTimeout())); - } -} - -void MediaPlayerPrivateQt::seekTimeout() -{ - // If we haven't heard anything, assume the seek succeeded - if (m_isSeeking) { - m_webCorePlayer->timeChanged(); - m_isSeeking = false; - } -} - void MediaPlayerPrivateQt::positionChanged(qint64) { // Only propagate this event if we are seeking - if (m_isSeeking && m_queuedSeek == -1) { - m_webCorePlayer->timeChanged(); + if (m_isSeeking) { m_isSeeking = false; + m_webCorePlayer->timeChanged(); } } @@ -649,7 +597,7 @@ void MediaPlayerPrivateQt::repaint() #if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) -class TextureMapperVideoLayerQt : public virtual TextureMapperVideoLayer { +class TextureMapperVideoLayerQt : public virtual TextureMapperMediaLayer { public: TextureMapperVideoLayerQt(QGraphicsVideoItem* videoItem) : m_videoItem(videoItem) diff --git a/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h index 81cdd79..c6398c9 100644 --- a/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h +++ b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h @@ -33,7 +33,7 @@ QT_END_NAMESPACE namespace WebCore { -class TextureMapperVideoLayer; +class TextureMapperMediaLayer; class MediaPlayerPrivateQt : public QObject, public MediaPlayerPrivateInterface { @@ -120,8 +120,6 @@ private slots: void handleError(QMediaPlayer::Error); void stateChanged(QMediaPlayer::State); void nativeSizeChanged(const QSizeF&); - void queuedSeekTimeout(); - void seekTimeout(); void positionChanged(qint64); void durationChanged(qint64); void bufferStatusChanged(int); @@ -141,7 +139,7 @@ private: QGraphicsVideoItem* m_videoItem; QGraphicsScene* m_videoScene; #if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) - OwnPtr<TextureMapperVideoLayer> m_platformLayer; + OwnPtr<TextureMapperMediaLayer> m_platformLayer; #endif mutable MediaPlayer::NetworkState m_networkState; @@ -153,7 +151,6 @@ private: bool m_isVisible; bool m_isSeeking; bool m_composited; - qint64 m_queuedSeek; MediaPlayer::Preload m_preload; bool m_delayingLoad; String m_mediaUrl; diff --git a/Source/WebCore/platform/graphics/qt/PathQt.cpp b/Source/WebCore/platform/graphics/qt/PathQt.cpp index ad482f7..ccc7f3d 100644 --- a/Source/WebCore/platform/graphics/qt/PathQt.cpp +++ b/Source/WebCore/platform/graphics/qt/PathQt.cpp @@ -154,7 +154,7 @@ FloatRect Path::boundingRect() const return m_path.boundingRect(); } -FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) +FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) const { GraphicsContext* context = scratchContext(); QPainterPathStroker stroke; @@ -398,23 +398,15 @@ void Path::apply(void* info, PathApplierFunction function) const void Path::transform(const AffineTransform& transform) { QTransform qTransform(transform); -#if QT_VERSION < QT_VERSION_CHECK(4, 7, 0) - // Workaround for http://bugreports.qt.nokia.com/browse/QTBUG-11264 - // QTransform.map doesn't handle the MoveTo element because of the isEmpty issue - if (m_path.isEmpty() && m_path.elementCount()) { - QPointF point = qTransform.map(m_path.currentPosition()); - moveTo(point); - } else -#endif - m_path = qTransform.map(m_path); -} - -float Path::length() + m_path = qTransform.map(m_path); +} + +float Path::length() const { return m_path.length(); } -FloatPoint Path::pointAtLength(float length, bool& ok) +FloatPoint Path::pointAtLength(float length, bool& ok) const { ok = (length >= 0 && length <= m_path.length()); @@ -424,7 +416,7 @@ FloatPoint Path::pointAtLength(float length, bool& ok) return point; } -float Path::normalAngleAtLength(float length, bool& ok) +float Path::normalAngleAtLength(float length, bool& ok) const { ok = (length >= 0 && length <= m_path.length()); diff --git a/Source/WebCore/platform/graphics/qt/TileQt.cpp b/Source/WebCore/platform/graphics/qt/TileQt.cpp index 096ce14..8723cd4 100644 --- a/Source/WebCore/platform/graphics/qt/TileQt.cpp +++ b/Source/WebCore/platform/graphics/qt/TileQt.cpp @@ -91,10 +91,10 @@ void Tile::invalidate(const IntRect& dirtyRect) *m_dirtyRegion += tileDirtyRect; } -void Tile::updateBackBuffer() +Vector<IntRect> Tile::updateBackBuffer() { if (m_buffer && !isDirty()) - return; + return Vector<IntRect>(); if (!m_backBuffer) { if (!m_buffer) { @@ -115,15 +115,19 @@ void Tile::updateBackBuffer() GraphicsContext context(&painter); context.translate(-m_rect.x(), -m_rect.y()); + Vector<IntRect> updatedRects; int size = dirtyRects.size(); for (int n = 0; n < size; ++n) { context.save(); IntRect rect = dirtyRects[n]; + updatedRects.append(rect); context.clip(FloatRect(rect)); context.scale(FloatSize(m_backingStore->m_contentsScale, m_backingStore->m_contentsScale)); m_backingStore->m_client->tiledBackingStorePaint(&context, m_backingStore->mapToContents(rect)); context.restore(); } + + return updatedRects; } void Tile::swapBackBufferToFront() diff --git a/Source/WebCore/platform/graphics/skia/FontCustomPlatformData.cpp b/Source/WebCore/platform/graphics/skia/FontCustomPlatformData.cpp index 0e68c21..cc695a5 100644 --- a/Source/WebCore/platform/graphics/skia/FontCustomPlatformData.cpp +++ b/Source/WebCore/platform/graphics/skia/FontCustomPlatformData.cpp @@ -65,7 +65,8 @@ FontCustomPlatformData::~FontCustomPlatformData() #endif } -FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation orientation, FontWidthVariant, FontRenderingMode mode) +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation orientation, + TextOrientation textOrientation, FontWidthVariant, FontRenderingMode mode) { #if OS(WINDOWS) ASSERT(m_fontReference); @@ -102,7 +103,7 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b return FontPlatformData(hfont, size); #elif OS(LINUX) || OS(FREEBSD) || PLATFORM(BREWMP) ASSERT(m_fontReference); - return FontPlatformData(m_fontReference, "", size, bold && !m_fontReference->isBold(), italic && !m_fontReference->isItalic(), orientation); + return FontPlatformData(m_fontReference, "", size, bold && !m_fontReference->isBold(), italic && !m_fontReference->isItalic(), orientation, textOrientation); #else notImplemented(); return FontPlatformData(); diff --git a/Source/WebCore/platform/graphics/skia/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/skia/FontCustomPlatformData.h index 2dee3ab..b68722b 100644 --- a/Source/WebCore/platform/graphics/skia/FontCustomPlatformData.h +++ b/Source/WebCore/platform/graphics/skia/FontCustomPlatformData.h @@ -35,6 +35,7 @@ #include "FontOrientation.h" #include "FontRenderingMode.h" #include "FontWidthVariant.h" +#include "TextOrientation.h" #include <wtf/Forward.h> #include <wtf/Noncopyable.h> @@ -66,8 +67,8 @@ public: ~FontCustomPlatformData(); - FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontWidthVariant = RegularWidth, - FontRenderingMode = NormalRenderingMode); + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, TextOrientation = TextOrientationVerticalRight, + FontWidthVariant = RegularWidth, FontRenderingMode = NormalRenderingMode); static bool supportsFormat(const String&); diff --git a/Source/WebCore/platform/graphics/skia/GlyphPageTreeNodeSkia.cpp b/Source/WebCore/platform/graphics/skia/GlyphPageTreeNodeSkia.cpp index 66e6839..f362fa3 100644 --- a/Source/WebCore/platform/graphics/skia/GlyphPageTreeNodeSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/GlyphPageTreeNodeSkia.cpp @@ -91,7 +91,7 @@ bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned b return false; } - if ((fontData->orientation() == Vertical) && (!fontData->isBrokenIdeographFont())) { + if (fontData->hasVerticalGlyphs()) { bool lookVariants = false; for (unsigned i = 0; i < bufferLength; ++i) { if (!Font::isCJKIdeograph(buffer[i])) { diff --git a/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp index 00afd07..df680eb 100644 --- a/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp @@ -1025,6 +1025,14 @@ void GraphicsContext::setPlatformShadow(const FloatSize& size, if (paintingDisabled()) return; + if (platformContext()->useGPU()) { + GLES2Canvas* canvas = platformContext()->gpuCanvas(); + canvas->setShadowOffset(size); + canvas->setShadowBlur(blurFloat); + canvas->setShadowColor(color, colorSpace); + canvas->setShadowsIgnoreTransforms(m_state.shadowsIgnoreTransforms); + } + // Detect when there's no effective shadow and clear the looper. if (!size.width() && !size.height() && !blurFloat) { platformContext()->setDrawLooper(0); @@ -1035,14 +1043,15 @@ void GraphicsContext::setPlatformShadow(const FloatSize& size, double height = size.height(); double blur = blurFloat; - SkBlurDrawLooper::BlurFlags blurFlags = SkBlurDrawLooper::kNone_BlurFlag; + uint32_t blurFlags = SkBlurDrawLooper::kHighQuality_BlurFlag | + SkBlurDrawLooper::kOverrideColor_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; + blurFlags |= SkBlurDrawLooper::kIgnoreTransform_BlurFlag; // CG uses natural orientation for Y axis, but the HTML5 canvas spec // does not. diff --git a/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp index 2721523..b89c68d 100644 --- a/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp @@ -341,6 +341,28 @@ void ImageBuffer::putPremultipliedImageData(ByteArray* source, const IntSize& so putImageData<Premultiplied>(source, sourceSize, sourceRect, destPoint, context()->platformContext()->canvas()->getDevice(), m_size); } +template <typename T> +static String ImageToDataURL(T& source, const String& mimeType, const double* quality) +{ + Vector<unsigned char> encodedImage; + if (mimeType == "image/jpeg") { + int compressionQuality = JPEGImageEncoder::DefaultCompressionQuality; + if (quality && *quality >= 0.0 && *quality <= 1.0) + compressionQuality = static_cast<int>(*quality * 100 + 0.5); + if (!JPEGImageEncoder::encode(source, compressionQuality, &encodedImage)) + return "data:,"; + } else { + if (!PNGImageEncoder::encode(source, &encodedImage)) + return "data:,"; + ASSERT(mimeType == "image/png"); + } + + Vector<char> base64Data; + base64Encode(*reinterpret_cast<Vector<char>*>(&encodedImage), base64Data); + + return makeString("data:", mimeType, ";base64,", base64Data); +} + String ImageBuffer::toDataURL(const String& mimeType, const double* quality) const { ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType)); @@ -358,23 +380,13 @@ String ImageBuffer::toDataURL(const String& mimeType, const double* quality) con if (!device->readPixels(bounds, &bitmap)) return "data:,"; } - - if (mimeType == "image/jpeg") { - int compressionQuality = JPEGImageEncoder::DefaultCompressionQuality; - if (quality && *quality >= 0.0 && *quality <= 1.0) - compressionQuality = static_cast<int>(*quality * 100 + 0.5); - if (!JPEGImageEncoder::encode(bitmap, compressionQuality, &encodedImage)) - return "data:,"; - } else { - if (!PNGImageEncoder::encode(bitmap, &encodedImage)) - return "data:,"; - ASSERT(mimeType == "image/png"); - } - Vector<char> base64Data; - base64Encode(*reinterpret_cast<Vector<char>*>(&encodedImage), base64Data); + return ImageToDataURL(bitmap, mimeType, quality); +} - return makeString("data:", mimeType, ";base64,", base64Data); +String ImageDataToDataURL(const ImageData& source, const String& mimeType, const double* quality) +{ + return ImageToDataURL(source, mimeType, quality); } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/skia/ImageSkia.cpp b/Source/WebCore/platform/graphics/skia/ImageSkia.cpp index 91a4e4f..72bec29 100644 --- a/Source/WebCore/platform/graphics/skia/ImageSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/ImageSkia.cpp @@ -260,6 +260,7 @@ static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImag paint.setXfermodeMode(compOp); paint.setFilterBitmap(true); paint.setAlpha(platformContext->getNormalizedAlpha()); + paint.setLooper(platformContext->getDrawLooper()); skia::PlatformCanvas* canvas = platformContext->canvas(); diff --git a/Source/WebCore/platform/graphics/skia/PathSkia.cpp b/Source/WebCore/platform/graphics/skia/PathSkia.cpp index 0344086..b037a0d 100644 --- a/Source/WebCore/platform/graphics/skia/PathSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/PathSkia.cpp @@ -228,7 +228,7 @@ void Path::transform(const AffineTransform& xform) m_path->transform(xform); } -FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) +FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) const { GraphicsContext* scratch = scratchContext(); scratch->save(); diff --git a/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp index eac5e4a..8e1937f 100644 --- a/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp @@ -68,18 +68,6 @@ namespace WebCore { -#if ENABLE(SKIA_GPU) -GrContext* GetGlobalGrContext() -{ - static GrContext* gGR; - if (!gGR) { - gGR = GrContext::CreateGLShaderContext(); - gGR->setTextureCacheLimits(512, 50 * 1024 * 1024); - } - return gGR; -} -#endif - extern bool isPathSkiaSafe(const SkMatrix& transform, const SkPath& path); // State ----------------------------------------------------------------------- @@ -241,8 +229,14 @@ PlatformContextSkia::PlatformContextSkia(skia::PlatformCanvas* canvas) PlatformContextSkia::~PlatformContextSkia() { #if ENABLE(ACCELERATED_2D_CANVAS) - if (m_gpuCanvas) + 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); +#endif m_gpuCanvas->drawingBuffer()->setWillPublishCallback(0); + } #endif } @@ -697,8 +691,7 @@ void PlatformContextSkia::applyAntiAliasedClipPaths(WTF::Vector<SkPath>& paths) bool PlatformContextSkia::canAccelerate() const { - return !m_state->m_fillShader // Can't accelerate with a fill gradient or pattern. - && !m_state->m_looper; // Can't accelerate with a shadow. + return !m_state->m_fillShader; // Can't accelerate with a fill gradient or pattern. } bool PlatformContextSkia::canvasClipApplied() const @@ -741,8 +734,10 @@ void PlatformContextSkia::setSharedGraphicsContext3D(SharedGraphicsContext3D* co context->makeContextCurrent(); m_gpuCanvas->bindFramebuffer(); - GrContext* gr = GetGlobalGrContext(); + GrContext* gr = context->grContext(); gr->resetContext(); + drawingBuffer->setGrContext(gr); + SkDeviceFactory* factory = new SkGpuDeviceFactory(gr, SkGpuDevice::Current3DApiRenderTarget()); SkDevice* device = factory->newDevice(m_canvas, SkBitmap::kARGB_8888_Config, drawingBuffer->size().width(), drawingBuffer->size().height(), false, false); m_canvas->setDevice(device)->unref(); diff --git a/Source/WebCore/platform/graphics/skia/SkiaFontWin.cpp b/Source/WebCore/platform/graphics/skia/SkiaFontWin.cpp index 54aa35e..b0cb0c7 100644 --- a/Source/WebCore/platform/graphics/skia/SkiaFontWin.cpp +++ b/Source/WebCore/platform/graphics/skia/SkiaFontWin.cpp @@ -380,6 +380,11 @@ 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 (didFill) { // If there is a shadow and we filled above, there will already be // a shadow. We don't want to draw it again or it will be too dark @@ -390,7 +395,7 @@ bool paintSkiaText(GraphicsContext* context, // thing would be to draw to a new layer and then draw that layer // with a shadow. But this is a lot of extra work for something // that isn't normally an issue. - SkSafeUnref(paint.setLooper(0)); + paint.setLooper(0); } if (!skiaDrawText(hfont, dc, platformContext->canvas(), *origin, &paint, diff --git a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp index 4698239..760ba6c 100644 --- a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp +++ b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp @@ -336,7 +336,7 @@ void GraphicsLayerTextureMapper::setContentsToMedia(PlatformLayer* media) notifyChange(TextureMapperNode::ContentChange); m_pendingContent.contentType = media ? TextureMapperNode::MediaContentType : TextureMapperNode::HTMLContentType; if (media) - m_pendingContent.media = static_cast<TextureMapperVideoLayer*>(media); + m_pendingContent.media = static_cast<TextureMapperMediaLayer*>(media); else m_pendingContent.media = 0; } @@ -366,13 +366,6 @@ void GraphicsLayerTextureMapper::syncCompositingState() } /* \reimp (GraphicsLayer.h) - */ -NativeLayer GraphicsLayerTextureMapper::nativeLayer() const -{ - return m_node.get(); -} - -/* \reimp (GraphicsLayer.h) */ PlatformLayer* GraphicsLayerTextureMapper::platformLayer() const { diff --git a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h index 47a27c6..dcf4938 100644 --- a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h +++ b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h @@ -81,7 +81,6 @@ public: virtual void syncCompositingState(); virtual void syncCompositingStateForThisLayerOnly(); virtual void setName(const String& name); - virtual NativeLayer nativeLayer() const; virtual PlatformLayer* platformLayer() const; virtual bool addAnimation(const KeyframeValueList&, const IntSize& /*boxSize*/, const Animation*, const String& /*keyframesName*/, double /*timeOffset*/) { return false; } diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapper.h b/Source/WebCore/platform/graphics/texmap/TextureMapper.h index 589fda1..8e46e3c 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapper.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapper.h @@ -31,6 +31,7 @@ #include "IntRect.h" #include "IntSize.h" #include "TransformationMatrix.h" +#include <wtf/UnusedParam.h> /* TextureMapper is a mechanism that enables hardware acceleration of CSS animations (accelerated compositing) without @@ -68,7 +69,7 @@ public: return beginPaint(IntRect(0, 0, size().width(), size().height())); } virtual void setContentsToImage(Image*) = 0; - virtual bool save(const String& filename) { return false; } + virtual bool save(const String&) { return false; } inline void lock() { ++m_lockCount; } inline void unlock() { --m_lockCount; } @@ -101,6 +102,7 @@ public: virtual void bindSurface(BitmapTexture* surface) = 0; virtual void paintToTarget(const BitmapTexture& texture, const IntSize&, const TransformationMatrix& matrix, float opacity, const IntRect& visibleRect) { + UNUSED_PARAM(visibleRect); drawTexture(texture, IntRect(0, 0, texture.contentSize().width(), texture.contentSize().height()), matrix, opacity, 0); } diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperNode.h b/Source/WebCore/platform/graphics/texmap/TextureMapperNode.h index 9694043..c5decc1 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperNode.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperNode.h @@ -20,19 +20,19 @@ #ifndef TextureMapperNode_h #define TextureMapperNode_h -#include "CurrentTime.h" #include "FloatRect.h" #include "GraphicsContext.h" #include "GraphicsLayer.h" -#include "HashMap.h" #include "Image.h" -#include "RefCounted.h" #include "TextureMapper.h" #include "TextureMapperPlatformLayer.h" #include "Timer.h" #include "TransformOperations.h" #include "TranslateTransformOperation.h" #include "UnitBezier.h" +#include <wtf/CurrentTime.h> +#include <wtf/HashMap.h> +#include <wtf/RefCounted.h> namespace WebCore { @@ -94,7 +94,7 @@ public: ContentType contentType; RefPtr<Image> image; - TextureMapperVideoLayer* media; + TextureMapperMediaLayer* media; ContentData() : needsDisplay(false) diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h b/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h index 2a38b90..d2d646a 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h @@ -43,7 +43,7 @@ class TextureMapperPlatformLayer { public: enum Type { ContentLayer, - VideoLayer + MediaLayer }; virtual Type layerType() const = 0; @@ -66,13 +66,11 @@ public: virtual Type layerType() const { return ContentLayer; } }; -#if ENABLE(VIDEO) -class TextureMapperVideoLayer : public TextureMapperPlatformLayer { +class TextureMapperMediaLayer : public TextureMapperPlatformLayer { public: virtual void paint(GraphicsContext*) = 0; - virtual Type layerType() const { return VideoLayer; } + virtual Type layerType() const { return MediaLayer; } }; -#endif } diff --git a/Source/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp b/Source/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp index a8ad131..b1ea99b 100644 --- a/Source/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp +++ b/Source/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp @@ -21,6 +21,7 @@ #include "config.h" #include "TranslateTransformOperation.h" +#include "FloatConversion.h" namespace WebCore { @@ -30,15 +31,15 @@ PassRefPtr<TransformOperation> TranslateTransformOperation::blend(const Transfor return this; if (blendToIdentity) - return TranslateTransformOperation::create(Length(m_x.type()).blend(m_x, progress), - Length(m_y.type()).blend(m_y, progress), - Length(m_z.type()).blend(m_z, progress), m_type); + return TranslateTransformOperation::create(Length(m_x.type()).blend(m_x, narrowPrecisionToFloat(progress)), + Length(m_y.type()).blend(m_y, narrowPrecisionToFloat(progress)), + Length(m_z.type()).blend(m_z, narrowPrecisionToFloat(progress)), m_type); const TranslateTransformOperation* fromOp = static_cast<const TranslateTransformOperation*>(from); Length fromX = fromOp ? fromOp->m_x : Length(m_x.type()); Length fromY = fromOp ? fromOp->m_y : Length(m_y.type()); Length fromZ = fromOp ? fromOp->m_z : Length(m_z.type()); - return TranslateTransformOperation::create(m_x.blend(fromX, progress), m_y.blend(fromY, progress), m_z.blend(fromZ, progress), m_type); + return TranslateTransformOperation::create(m_x.blend(fromX, narrowPrecisionToFloat(progress)), m_y.blend(fromY, narrowPrecisionToFloat(progress)), m_z.blend(fromZ, narrowPrecisionToFloat(progress)), m_type); } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/win/FontCacheWin.cpp b/Source/WebCore/platform/graphics/win/FontCacheWin.cpp index e800245..5382ef7 100644 --- a/Source/WebCore/platform/graphics/win/FontCacheWin.cpp +++ b/Source/WebCore/platform/graphics/win/FontCacheWin.cpp @@ -584,7 +584,7 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD #if PLATFORM(CG) bool fontCreationFailed = !result->cgFont(); #elif PLATFORM(CAIRO) - bool fontCreationFailed = !result->fontFace(); + bool fontCreationFailed = !result->scaledFont(); #endif if (fontCreationFailed) { diff --git a/Source/WebCore/platform/graphics/win/FontCustomPlatformData.cpp b/Source/WebCore/platform/graphics/win/FontCustomPlatformData.cpp index 4aee6cd..8348acb 100644 --- a/Source/WebCore/platform/graphics/win/FontCustomPlatformData.cpp +++ b/Source/WebCore/platform/graphics/win/FontCustomPlatformData.cpp @@ -59,7 +59,7 @@ FontCustomPlatformData::~FontCustomPlatformData() } } -FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontWidthVariant, FontRenderingMode renderingMode) +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, TextOrientation, FontWidthVariant, FontRenderingMode renderingMode) { ASSERT(m_fontReference); ASSERT(T2embedLibrary()); diff --git a/Source/WebCore/platform/graphics/win/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/win/FontCustomPlatformData.h index abdb356..65388d8 100644 --- a/Source/WebCore/platform/graphics/win/FontCustomPlatformData.h +++ b/Source/WebCore/platform/graphics/win/FontCustomPlatformData.h @@ -25,6 +25,7 @@ #include "FontRenderingMode.h" #include "FontWidthVariant.h" #include "PlatformString.h" +#include "TextOrientation.h" #include <wtf/Forward.h> #include <wtf/Noncopyable.h> @@ -46,7 +47,8 @@ public: ~FontCustomPlatformData(); - FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontWidthVariant = RegularWidth, FontRenderingMode = NormalRenderingMode); + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, TextOrientation = TextOrientationVerticalRight, + FontWidthVariant = RegularWidth, FontRenderingMode = NormalRenderingMode); static bool supportsFormat(const String&); diff --git a/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp b/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp index fd30a6d..6f9bbf0 100644 --- a/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp +++ b/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp @@ -23,8 +23,11 @@ #include "SharedBuffer.h" #include "FontPlatformData.h" + +#include <cairo-win32.h> #include <wtf/RetainPtr.h> + namespace WebCore { FontCustomPlatformData::~FontCustomPlatformData() @@ -32,7 +35,7 @@ FontCustomPlatformData::~FontCustomPlatformData() cairo_font_face_destroy(m_fontFace); } -FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontWidthVariant) +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, TextOrientation, FontWidthVariant) { return FontPlatformData(m_fontFace, size, bold, italic); } diff --git a/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h b/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h index ea3ae38..bd90f18 100644 --- a/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h +++ b/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h @@ -42,7 +42,7 @@ public: } ~FontCustomPlatformData(); - FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontWidthVariant = RegularWidth); + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, TextOrientation = TextOrientationVerticalRight, FontWidthVariant = RegularWidth); static bool supportsFormat(const String&); diff --git a/Source/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp b/Source/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp index 9234229..287121b 100644 --- a/Source/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp +++ b/Source/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp @@ -115,11 +115,15 @@ void FontPlatformData::platformDataInit(HFONT font, float size, HDC hdc, WCHAR* } FontPlatformData::FontPlatformData(HFONT hfont, CGFontRef font, float size, bool bold, bool oblique, bool useGDI) - : m_font(RefCountedGDIHandle<HFONT>::create(hfont)) + : m_syntheticBold(bold) + , m_syntheticOblique(oblique) + , m_orientation(Horizontal) + , m_textOrientation(TextOrientationVerticalRight) , m_size(size) + , m_widthVariant(RegularWidth) + , m_font(RefCountedGDIHandle<HFONT>::create(hfont)) , m_cgFont(font) - , m_syntheticBold(bold) - , m_syntheticOblique(oblique) + , m_isColorBitmapFont(false) , m_useGDI(useGDI) { } @@ -128,4 +132,27 @@ FontPlatformData::~FontPlatformData() { } +void FontPlatformData::platformDataInit(const FontPlatformData& source) +{ + m_font = source.m_font; + m_cgFont = source.m_cgFont; + m_useGDI = source.m_useGDI; +} + +const FontPlatformData& FontPlatformData::platformDataAssign(const FontPlatformData& other) +{ + m_font = other.m_font; + m_cgFont = other.m_cgFont; + m_useGDI = other.m_useGDI; + + return *this; +} + +bool FontPlatformData::platformIsEqual(const FontPlatformData& other) const +{ + return m_font == other.m_font + && m_cgFont == other.m_cgFont + && m_useGDI == other.m_useGDI; +} + } diff --git a/Source/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp b/Source/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp index 0f5c365..e60b69b 100644 --- a/Source/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp +++ b/Source/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp @@ -4,7 +4,7 @@ * * Copyright (C) 2006, 2007, 2008 Apple Inc. * Copyright (C) 2007 Alp Toker - * Copyright (C) 2008, 2010 Brent Fulgham + * Copyright (C) 2008, 2010, 2011 Brent Fulgham * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -40,7 +40,7 @@ namespace WebCore { void FontPlatformData::platformDataInit(HFONT font, float size, HDC hdc, WCHAR* faceName) { - m_fontFace = cairo_win32_font_face_create_for_hfont(font); + cairo_font_face_t* fontFace = cairo_win32_font_face_create_for_hfont(font); cairo_matrix_t sizeMatrix, ctm; cairo_matrix_init_identity(&ctm); @@ -52,14 +52,18 @@ void FontPlatformData::platformDataInit(HFONT font, float size, HDC hdc, WCHAR* cairo_font_options_set_antialias(fontOptions, CAIRO_ANTIALIAS_SUBPIXEL); } - m_scaledFont = cairo_scaled_font_create(m_fontFace, &sizeMatrix, &ctm, fontOptions); + m_scaledFont = cairo_scaled_font_create(fontFace, &sizeMatrix, &ctm, fontOptions); + cairo_font_face_destroy(fontFace); } FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, float size, bool bold, bool oblique) : m_font(0) , m_size(size) - , m_fontFace(fontFace) + , m_orientation(Horizontal) + , m_textOrientation(TextOrientationVerticalRight) + , m_widthVariant(RegularWidth) , m_scaledFont(0) + , m_isColorBitmapFont(false) , m_syntheticBold(bold) , m_syntheticOblique(oblique) , m_useGDI(false) @@ -79,64 +83,39 @@ FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, float size, bool cairo_font_options_destroy(options); } -FontPlatformData::FontPlatformData(const FontPlatformData& source) - : m_font(source.m_font) - , m_size(source.m_size) - , m_fontFace(0) - , m_scaledFont(0) - , m_syntheticBold(source.m_syntheticBold) - , m_syntheticOblique(source.m_syntheticOblique) - , m_useGDI(source.m_useGDI) +FontPlatformData::~FontPlatformData() { - if (source.m_fontFace) - m_fontFace = cairo_font_face_reference(source.m_fontFace); - - if (source.m_scaledFont) - m_scaledFont = cairo_scaled_font_reference(source.m_scaledFont); + if (m_scaledFont && m_scaledFont != hashTableDeletedFontValue()) + cairo_scaled_font_destroy(m_scaledFont); } - -FontPlatformData::~FontPlatformData() +void FontPlatformData::platformDataInit(const FontPlatformData& source) { - cairo_scaled_font_destroy(m_scaledFont); - cairo_font_face_destroy(m_fontFace); + m_font = source.m_font; + m_useGDI = source.m_useGDI; + m_scaledFont = 0; + + if (source.m_scaledFont) + m_scaledFont = cairo_scaled_font_reference(source.m_scaledFont); } -FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other) +const FontPlatformData& FontPlatformData::platformDataAssign(const FontPlatformData& other) { - // Check for self-assignment. - if (this == &other) - return *this; - m_font = other.m_font; - m_size = other.m_size; - m_syntheticBold = other.m_syntheticBold; - m_syntheticOblique = other.m_syntheticOblique; m_useGDI = other.m_useGDI; - if (other.m_fontFace) - cairo_font_face_reference(other.m_fontFace); - if (m_fontFace) - cairo_font_face_destroy(m_fontFace); - m_fontFace = other.m_fontFace; - - if (other.m_scaledFont) - cairo_scaled_font_reference(other.m_scaledFont); - if (m_scaledFont) + if (m_scaledFont && m_scaledFont != hashTableDeletedFontValue()) cairo_scaled_font_destroy(m_scaledFont); - m_scaledFont = other.m_scaledFont; + + m_scaledFont = cairo_scaled_font_reference(other.m_scaledFont); return *this; } -bool FontPlatformData::operator==(const FontPlatformData& other) const -{ +bool FontPlatformData::platformIsEqual(const FontPlatformData& other) const +{ return m_font == other.m_font - && m_fontFace == other.m_fontFace && m_scaledFont == other.m_scaledFont - && m_size == other.m_size - && m_syntheticBold == other.m_syntheticBold - && m_syntheticOblique == other.m_syntheticOblique && m_useGDI == other.m_useGDI; } diff --git a/Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp b/Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp index 09ed4a6..301198d 100644 --- a/Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp +++ b/Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp @@ -38,12 +38,15 @@ namespace WebCore { FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool oblique, bool useGDI) : m_font(RefCountedGDIHandle<HFONT>::create(font)) , m_size(size) + , m_orientation(Horizontal) + , m_textOrientation(TextOrientationVerticalRight) + , m_widthVariant(RegularWidth) #if PLATFORM(CG) , m_cgFont(0) #elif PLATFORM(CAIRO) - , m_fontFace(0) , m_scaledFont(0) #endif + , m_isColorBitmapFont(false) , m_syntheticBold(bold) , m_syntheticOblique(oblique) , m_useGDI(useGDI) @@ -71,20 +74,6 @@ FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool obliq ReleaseDC(0, hdc); } -FontPlatformData::FontPlatformData(float size, bool bold, bool oblique) - : m_size(size) -#if PLATFORM(CG) - , m_cgFont(0) -#elif PLATFORM(CAIRO) - , m_fontFace(0) - , m_scaledFont(0) -#endif - , m_syntheticBold(bold) - , m_syntheticOblique(oblique) - , m_useGDI(false) -{ -} - #ifndef NDEBUG String FontPlatformData::description() const { diff --git a/Source/WebCore/platform/graphics/win/FontWin.cpp b/Source/WebCore/platform/graphics/win/FontWin.cpp index 47c44bc..9e31f56 100644 --- a/Source/WebCore/platform/graphics/win/FontWin.cpp +++ b/Source/WebCore/platform/graphics/win/FontWin.cpp @@ -127,8 +127,8 @@ float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon UniscribeController controller(this, run, fallbackFonts); controller.advance(run.length()); if (glyphOverflow) { - glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-controller.minGlyphBoundingBoxY()) - fontMetrics().ascent()); - glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(controller.maxGlyphBoundingBoxY()) - fontMetrics().descent()); + glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-controller.minGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().ascent())); + glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(controller.maxGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().descent())); glyphOverflow->left = max<int>(0, ceilf(-controller.minGlyphBoundingBoxX())); glyphOverflow->right = max<int>(0, ceilf(controller.maxGlyphBoundingBoxX() - controller.runWidthSoFar())); } diff --git a/Source/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/Source/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp index b2c702f..7ce7ee9 100644 --- a/Source/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp +++ b/Source/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp @@ -72,18 +72,15 @@ GraphicsContext::GraphicsContext(HDC dc, bool hasAlpha) void GraphicsContext::platformInit(HDC dc, bool hasAlpha) { - m_data = new GraphicsContextPlatformPrivate; - - if (dc) { - m_data->cr = createCairoContextWithHDC(dc, hasAlpha); - m_data->m_hdc = dc; - } else { + cairo_t* cr = 0; + if (dc) + cr = createCairoContextWithHDC(dc, hasAlpha); + else setPaintingDisabled(true); - m_data->cr = 0; - m_data->m_hdc = 0; - } - if (m_data->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. setPlatformFillColor(fillColor(), fillColorSpace()); setPlatformStrokeColor(strokeColor(), strokeColorSpace()); @@ -131,24 +128,25 @@ void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, boo // 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_save(m_data->cr); - cairo_translate(m_data->cr, dstRect.x(), dstRect.height() + dstRect.y()); - cairo_scale(m_data->cr, 1.0, -1.0); - cairo_set_source_surface(m_data->cr, image, 0, 0); + 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); if (m_data->layers.size()) - cairo_paint_with_alpha(m_data->cr, m_data->layers.last()); + cairo_paint_with_alpha(cr, m_data->layers.last()); else - cairo_paint(m_data->cr); + cairo_paint(cr); // Delete all our junk. cairo_surface_destroy(image); ::DeleteDC(hdc); ::DeleteObject(bitmap); - cairo_restore(m_data->cr); + cairo_restore(cr); } -void GraphicsContextPlatformPrivate::syncContext(PlatformGraphicsContext* cr) +void GraphicsContextPlatformPrivate::syncContext(cairo_t* cr) { if (!cr) return; diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp index 40fe1d1..bac85f7 100644 --- a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp +++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp @@ -28,8 +28,11 @@ #if ENABLE(VIDEO) #include "MediaPlayerPrivateQuickTimeVisualContext.h" +#include "ApplicationCacheHost.h" +#include "ApplicationCacheResource.h" #include "Cookie.h" #include "CookieJar.h" +#include "DocumentLoader.h" #include "Frame.h" #include "FrameView.h" #include "GraphicsContext.h" @@ -369,7 +372,16 @@ void MediaPlayerPrivateQuickTimeVisualContext::loadInternal(const String& url) setUpCookiesForQuickTime(url); m_movie = adoptRef(new QTMovie(m_movieClient.get())); - m_movie->load(url.characters(), url.length(), m_player->preservesPitch()); + +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + Frame* frame = m_player->frameView() ? m_player->frameView()->frame() : 0; + ApplicationCacheHost* cacheHost = frame ? frame->loader()->documentLoader()->applicationCacheHost() : 0; + ApplicationCacheResource* resource = 0; + if (cacheHost && cacheHost->shouldLoadResourceFromApplicationCache(ResourceRequest(url), resource) && resource && !resource->path().isEmpty()) + m_movie->load(resource->path().characters(), resource->path().length(), m_player->preservesPitch()); + else +#endif + m_movie->load(url.characters(), url.length(), m_player->preservesPitch()); m_movie->setVolume(m_player->volume()); } diff --git a/Source/WebCore/platform/graphics/win/QTMovie.cpp b/Source/WebCore/platform/graphics/win/QTMovie.cpp index 05fbb86..6f9c668 100644 --- a/Source/WebCore/platform/graphics/win/QTMovie.cpp +++ b/Source/WebCore/platform/graphics/win/QTMovie.cpp @@ -442,6 +442,17 @@ void QTMovie::getNaturalSize(int& width, int& height) height = (rect.bottom - rect.top) * m_private->m_heightScaleFactor; } +void QTMovie::loadPath(const UChar* url, int len, bool preservesPitch) +{ + CFStringRef urlStringRef = CFStringCreateWithCharacters(kCFAllocatorDefault, reinterpret_cast<const UniChar*>(url), len); + CFURLRef cfURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, urlStringRef, kCFURLWindowsPathStyle, false); + + load(cfURL, preservesPitch); + + CFRelease(cfURL); + CFRelease(urlStringRef); +} + void QTMovie::load(const UChar* url, int len, bool preservesPitch) { CFStringRef urlStringRef = CFStringCreateWithCharacters(kCFAllocatorDefault, reinterpret_cast<const UniChar*>(url), len); diff --git a/Source/WebCore/platform/graphics/win/QTMovie.h b/Source/WebCore/platform/graphics/win/QTMovie.h index e97d16d..38b3473 100644 --- a/Source/WebCore/platform/graphics/win/QTMovie.h +++ b/Source/WebCore/platform/graphics/win/QTMovie.h @@ -70,6 +70,7 @@ public: void addClient(QTMovieClient*); void removeClient(QTMovieClient*); + void loadPath(const UChar* url, int len, bool preservesPitch); void load(const UChar* url, int len, bool preservesPitch); void load(CFURLRef, bool preservesPitch); diff --git a/Source/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp b/Source/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp index 30a931e..12f1127 100644 --- a/Source/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp +++ b/Source/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp @@ -97,18 +97,14 @@ void SimpleFontData::platformInit() m_fontMetrics.setLineGap(fLineGap); m_fontMetrics.setLineSpacing(lroundf(fAscent) + lroundf(fDescent) + lroundf(fLineGap)); - // Measure the actual character "x", because AppKit synthesizes X height rather than getting it from the font. - // Unfortunately, NSFont will round this for us so we don't quite get the right value. GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); Glyph xGlyph = glyphPageZero ? glyphPageZero->glyphDataForCharacter('x').glyph : 0; if (xGlyph) { + // Measure the actual character "x", since it's possible for it to extend below the baseline, and we need the + // reported x-height to only include the portion of the glyph that is above the baseline. CGRect xBox; CGFontGetGlyphBBoxes(font, &xGlyph, 1, &xBox); - // Use the maximum of either width or height because "x" is nearly square - // and web pages that foolishly use this metric for width will be laid out - // poorly if we return an accurate height. Classic case is Times 13 point, - // which has an "x" that is 7x6 pixels. - m_fontMetrics.setXHeight(scaleEmToUnits(max(CGRectGetMaxX(xBox), CGRectGetMaxY(xBox)), unitsPerEm) * pointSize); + m_fontMetrics.setXHeight(scaleEmToUnits(CGRectGetMaxY(xBox), unitsPerEm) * pointSize); } else { int iXHeight = CGFontGetXHeight(font); m_fontMetrics.setXHeight(scaleEmToUnits(iXHeight, unitsPerEm) * pointSize); diff --git a/Source/WebCore/platform/graphics/win/cairo/FontPlatformData.h b/Source/WebCore/platform/graphics/win/cairo/FontPlatformData.h deleted file mode 100644 index d8f538a..0000000 --- a/Source/WebCore/platform/graphics/win/cairo/FontPlatformData.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2006, 2007, 2008 Apple Inc. - * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com - * Copyright (C) 2007 Holger Hans Peter Freyther - * Copyright (C) 2007 Pioneer Research Center USA, Inc. - * Copyright (C) 2010 Brent Fulgham <bfulgham@webkit.org> - * 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 FontPlatformDataCairoWin_h -#define FontPlatformDataCairoWin_h - -#include "FontOrientation.h" -#include "GlyphBuffer.h" -#include "RefCountedGDIHandle.h" -#include "StringImpl.h" -#include <cairo-win32.h> -#include <cairo.h> -#include <wtf/Forward.h> - -typedef struct HFONT__* HFONT; - -namespace WebCore { - -class FontDescription; - -class FontPlatformData { -public: - FontPlatformData(WTF::HashTableDeletedValueType) - : m_fontFace(0) - , m_useGDI(false) - , m_font(WTF::HashTableDeletedValue) - , m_size(0) - , m_syntheticBold(false) - , m_syntheticOblique(false) - , m_scaledFont(0) - { } - - FontPlatformData() - : m_fontFace(0) - , m_useGDI(false) - , m_size(0) - , m_syntheticBold(false) - , m_syntheticOblique(false) - , m_scaledFont(0) - { } - - FontPlatformData(HFONT, float size, bool bold, bool oblique, bool useGDI); - FontPlatformData(cairo_font_face_t* fontFace, float size, bool bold, bool italic); - FontPlatformData(float size, bool bold, bool italic); - FontPlatformData(const FontPlatformData&); - ~FontPlatformData(); - - HFONT hfont() const { return m_font->handle(); } - bool useGDI() const { return m_useGDI; } - cairo_font_face_t* fontFace() const { return m_fontFace; } - - bool isFixedPitch(); - float size() const { return m_size; } - void setSize(float size) { m_size = size; } - bool syntheticBold() const { return m_syntheticBold; } - bool syntheticOblique() const { return m_syntheticOblique; } - - FontOrientation orientation() const { return Horizontal; } // FIXME: Implement. - - cairo_scaled_font_t* scaledFont() const { return m_scaledFont; } - - unsigned hash() const - { - return m_font->hash(); - } - - bool operator==(const FontPlatformData&) const; - FontPlatformData& operator=(const FontPlatformData&); - bool isHashTableDeletedValue() const - { - return m_font.isHashTableDeletedValue(); - } - -#ifndef NDEBUG - String description() const; -#endif - -private: - void platformDataInit(HFONT, float size, HDC, WCHAR* faceName); - - RefPtr<RefCountedGDIHandle<HFONT> > m_font; - cairo_font_face_t* m_fontFace; - bool m_useGDI; - float m_size; - bool m_syntheticBold; - bool m_syntheticOblique; - cairo_scaled_font_t* m_scaledFont; -}; - -} - -#endif // FontPlatformDataCairoWin_h diff --git a/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp b/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp index fb97fe1..07a8756 100644 --- a/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp +++ b/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp @@ -45,7 +45,7 @@ FontCustomPlatformData::~FontCustomPlatformData() g_customFontCache->unregisterFont(m_name); } -FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontWidthVariant, FontRenderingMode renderingMode) +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, TextOrientation, FontWidthVariant, FontRenderingMode renderingMode) { FontDescription fontDesc; fontDesc.setComputedSize(size); diff --git a/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.h index fe7ee94..12a86e9 100644 --- a/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.h +++ b/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.h @@ -24,6 +24,7 @@ #include "FontDescription.h" #include "FontRenderingMode.h" #include "FontWidthVariant.h" +#include "TextOrientation.h" #include "PlatformString.h" #include <wtf/Noncopyable.h> @@ -48,7 +49,7 @@ namespace WebCore { ~FontCustomPlatformData(); - FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontWidthVariant = RegularWidth, FontRenderingMode = NormalRenderingMode); + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, TextOrientation = TextOrientationVerticalRight, FontWidthVariant = RegularWidth, FontRenderingMode = NormalRenderingMode); static bool supportsFormat(const String&); diff --git a/Source/WebCore/platform/graphics/wince/FontPlatformData.cpp b/Source/WebCore/platform/graphics/wince/FontPlatformData.cpp index d9d8a72..d767ac7 100644 --- a/Source/WebCore/platform/graphics/wince/FontPlatformData.cpp +++ b/Source/WebCore/platform/graphics/wince/FontPlatformData.cpp @@ -148,7 +148,7 @@ struct FixedSizeFontDataKeyHash { font.m_weight, // static_cast<unsigned>(font.m_italic); }; - return WTF::StringHasher::createBlobHash<sizeof(hashCodes)>(hashCodes); + return StringHasher::hashMemory<sizeof(hashCodes)>(hashCodes); } static bool equal(const FixedSizeFontDataKey& a, const FixedSizeFontDataKey& b) diff --git a/Source/WebCore/platform/graphics/wince/FontPlatformData.h b/Source/WebCore/platform/graphics/wince/FontPlatformData.h index e73a7b2..9c3f733 100644 --- a/Source/WebCore/platform/graphics/wince/FontPlatformData.h +++ b/Source/WebCore/platform/graphics/wince/FontPlatformData.h @@ -79,6 +79,7 @@ namespace WebCore { static LONG adjustedGDIFontWeight(LONG gdiFontWeight, const String& family); FontOrientation orientation() const { return Horizontal; } // FIXME: Implement. + void setOrientation(FontOrientation) { } // FIXME: Implement. #ifndef NDEBUG String description() const; diff --git a/Source/WebCore/platform/graphics/wince/PathWinCE.cpp b/Source/WebCore/platform/graphics/wince/PathWinCE.cpp index fa4c8fb..9c9112b 100644 --- a/Source/WebCore/platform/graphics/wince/PathWinCE.cpp +++ b/Source/WebCore/platform/graphics/wince/PathWinCE.cpp @@ -133,7 +133,7 @@ void Path::transform(const AffineTransform& t) m_path->transform(t); } -FloatRect Path::strokeBoundingRect(StrokeStyleApplier *) +FloatRect Path::strokeBoundingRect(StrokeStyleApplier*) const { notImplemented(); return FloatRect(); diff --git a/Source/WebCore/platform/graphics/wx/FontPlatformData.h b/Source/WebCore/platform/graphics/wx/FontPlatformData.h index 3ef0179..8a2c4a0 100644 --- a/Source/WebCore/platform/graphics/wx/FontPlatformData.h +++ b/Source/WebCore/platform/graphics/wx/FontPlatformData.h @@ -150,6 +150,7 @@ public: bool allowsLigatures() const { return false; } FontOrientation orientation() const { return Horizontal; } // FIXME: Implement. + void setOrientation(FontOrientation) { } // FIXME: Implement. // We don't support this yet, so just return the default value for now. FontWidthVariant widthVariant() const { return RegularWidth; } diff --git a/Source/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp b/Source/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp index c125b7c..830cd05 100644 --- a/Source/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp +++ b/Source/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp @@ -126,10 +126,10 @@ unsigned FontPlatformData::computeHash() const thisFont->GetStyle(), thisFont->GetWeight(), thisFont->GetUnderlined(), - WTF::StringHasher::createHash(thisFont->GetFaceName().utf8_str().data()) + StringHasher::computeHash(thisFont->GetFaceName().utf8_str().data()) }; - return WTF::StringHasher::createBlobHash<sizeof(hashCodes)>(hashCodes); + return StringHasher::hashMemory<sizeof(hashCodes)>(hashCodes); } FontPlatformData::~FontPlatformData() diff --git a/Source/WebCore/platform/graphics/wx/PathWx.cpp b/Source/WebCore/platform/graphics/wx/PathWx.cpp index f5355f2..a95cc1c 100644 --- a/Source/WebCore/platform/graphics/wx/PathWx.cpp +++ b/Source/WebCore/platform/graphics/wx/PathWx.cpp @@ -105,7 +105,7 @@ FloatRect Path::boundingRect() const return FloatRect(); } -FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) +FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) const { notImplemented(); return FloatRect(); diff --git a/Source/WebCore/platform/gtk/FileSystemGtk.cpp b/Source/WebCore/platform/gtk/FileSystemGtk.cpp index b3c4c9f..e2b1642 100644 --- a/Source/WebCore/platform/gtk/FileSystemGtk.cpp +++ b/Source/WebCore/platform/gtk/FileSystemGtk.cpp @@ -227,16 +227,16 @@ Vector<String> listDirectory(const String& path, const String& filter) return entries; } -CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle) +String openTemporaryFile(const String& prefix, PlatformFileHandle& handle) { - GOwnPtr<gchar> filename(g_strdup_printf("%s%s", prefix, createCanonicalUUIDString().utf8().data())); + GOwnPtr<gchar> filename(g_strdup_printf("%s%s", prefix.utf8().data(), createCanonicalUUIDString().utf8().data())); GOwnPtr<gchar> tempPath(g_build_filename(g_get_tmp_dir(), filename.get(), NULL)); GRefPtr<GFile> file = adoptGRef(g_file_new_for_path(tempPath.get())); handle = g_file_create_readwrite(file.get(), G_FILE_CREATE_NONE, 0, 0); if (!isHandleValid(handle)) - return CString(); - return tempPath.get(); + return String(); + return String::fromUTF8(tempPath.get()); } PlatformFileHandle openFile(const String& path, FileOpenMode mode) diff --git a/Source/WebCore/platform/gtk/LocalizedStringsGtk.cpp b/Source/WebCore/platform/gtk/LocalizedStringsGtk.cpp index eab0ac6..02f6c47 100644 --- a/Source/WebCore/platform/gtk/LocalizedStringsGtk.cpp +++ b/Source/WebCore/platform/gtk/LocalizedStringsGtk.cpp @@ -259,7 +259,7 @@ String contextMenuItemTagSearchWeb() return String::fromUTF8(_("_Search the Web")); } -String contextMenuItemTagLookUpInDictionary() +String contextMenuItemTagLookUpInDictionary(const String&) { return String::fromUTF8(_("_Look Up in Dictionary")); } diff --git a/Source/WebCore/platform/gtk/RenderThemeGtk.cpp b/Source/WebCore/platform/gtk/RenderThemeGtk.cpp index 1e9f159..9b11c27 100644 --- a/Source/WebCore/platform/gtk/RenderThemeGtk.cpp +++ b/Source/WebCore/platform/gtk/RenderThemeGtk.cpp @@ -34,6 +34,7 @@ #include "HTMLNames.h" #include "MediaControlElements.h" #include "PaintInfo.h" +#include "PlatformContextCairo.h" #include "RenderBox.h" #include "RenderObject.h" #include "TimeRanges.h" @@ -234,7 +235,7 @@ static void paintGdkPixbuf(GraphicsContext* context, const GdkPixbuf* icon, cons icon = scaledIcon.get(); } - cairo_t* cr = context->platformContext(); + cairo_t* cr = context->platformContext()->cr(); cairo_save(cr); gdk_cairo_set_source_pixbuf(cr, icon, iconRect.x(), iconRect.y()); cairo_paint(cr); diff --git a/Source/WebCore/platform/gtk/RenderThemeGtk.h b/Source/WebCore/platform/gtk/RenderThemeGtk.h index f5e03a9..191a34b 100644 --- a/Source/WebCore/platform/gtk/RenderThemeGtk.h +++ b/Source/WebCore/platform/gtk/RenderThemeGtk.h @@ -214,6 +214,7 @@ private: GtkWidget* gtkComboBoxButton() const; GtkWidget* gtkComboBoxArrow() const; GtkWidget* gtkComboBoxSeparator() const; + GtkWidget* gtkSpinButton() const; GdkColormap* m_colormap; mutable GtkWidget* m_gtkWindow; @@ -232,6 +233,7 @@ private: mutable GtkWidget* m_gtkComboBoxSeparator; mutable GtkWidget* m_gtkVScrollbar; mutable GtkWidget* m_gtkHScrollbar; + mutable GtkWidget* m_gtkSpinButton; bool m_themePartsHaveRGBAColormap; friend class WidgetRenderingContext; #endif diff --git a/Source/WebCore/platform/gtk/RenderThemeGtk2.cpp b/Source/WebCore/platform/gtk/RenderThemeGtk2.cpp index 534aa97..5149bea 100644 --- a/Source/WebCore/platform/gtk/RenderThemeGtk2.cpp +++ b/Source/WebCore/platform/gtk/RenderThemeGtk2.cpp @@ -46,6 +46,9 @@ namespace WebCore { +// This is the default value defined by GTK+, where it was defined as MIN_ARROW_WIDTH in gtkspinbutton.c. +static const int minSpinButtonArrowSize = 6; + // This is not a static method, because we want to avoid having GTK+ headers in RenderThemeGtk.h. extern GtkTextDirection gtkTextDirection(TextDirection); @@ -68,6 +71,7 @@ void RenderThemeGtk::platformInit() m_gtkComboBoxSeparator = 0; m_gtkVScrollbar = 0; m_gtkHScrollbar = 0; + m_gtkSpinButton = 0; m_colormap = gdk_screen_get_rgba_colormap(gdk_screen_get_default()); if (!m_colormap) { @@ -117,6 +121,10 @@ void RenderThemeGtk::adjustRepaintRect(const RenderObject* renderObject, IntRect adjustRectForFocus(part == CheckboxPart ? gtkCheckButton() : gtkRadioButton(), rect, true); return; } + case InnerSpinButtonPart: + // See paintInnerSpinButton for an explanation of why we expand the painting rect. + rect.inflateY(2); + rect.setWidth(rect.width() + 2); default: return; } @@ -566,13 +574,84 @@ bool RenderThemeGtk::paintProgressBar(RenderObject* renderObject, const PaintInf } #endif -void RenderThemeGtk::adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const +void RenderThemeGtk::adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const { + GtkStyle* gtkStyle = gtk_widget_get_style(gtkSpinButton()); + const PangoFontDescription* fontDescription = gtkStyle->font_desc; + gint fontSize = pango_font_description_get_size(fontDescription); + + // Force an odd arrow size here. GTK+ 3.x forces even in this case, but + // Nodoka-based themes look incorrect with an even arrow size. + int width = max(PANGO_PIXELS(fontSize), minSpinButtonArrowSize); + width += -((width % 2) - 1) + gtkStyle->xthickness; + + style->setWidth(Length(width, Fixed)); + style->setMinWidth(Length(width, Fixed)); } -bool RenderThemeGtk::paintInnerSpinButton(RenderObject*, const PaintInfo&, const IntRect&) +bool RenderThemeGtk::paintInnerSpinButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) { - return true; + // We expand the painted area by 2 pixels on the top and bottom and 2 pixels on the right. This + // is because GTK+ themes want to draw over the text box borders, but WebCore renders the inner + // spin button inside the text box. + IntRect expandedRect(rect); + expandedRect.inflateY(2); + expandedRect.setWidth(rect.width() + 2); + + WidgetRenderingContext widgetContext(paintInfo.context, expandedRect); + GtkWidget* widget = gtkSpinButton(); + gtk_widget_set_direction(widget, gtkTextDirection(renderObject->style()->direction())); + + IntRect fullSpinButtonRect(IntPoint(), expandedRect.size()); + widgetContext.gtkPaintBox(fullSpinButtonRect, widget, GTK_STATE_NORMAL, GTK_SHADOW_IN, "spinbutton"); + + bool upPressed = isSpinUpButtonPartPressed(renderObject); + bool upHovered = isSpinUpButtonPartHovered(renderObject); + bool controlActive = isEnabled(renderObject) && !isReadOnlyControl(renderObject); + GtkShadowType shadowType = upPressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT; + + GtkStateType stateType = GTK_STATE_INSENSITIVE; + if (controlActive) { + if (isPressed(renderObject) && upPressed) + stateType = GTK_STATE_ACTIVE; + else if (isHovered(renderObject) && upHovered) + stateType = GTK_STATE_PRELIGHT; + else + stateType = GTK_STATE_NORMAL; + } + IntRect topRect(IntPoint(), expandedRect.size()); + topRect.setHeight(expandedRect.height() / 2); + widgetContext.gtkPaintBox(topRect, widget, stateType, shadowType, "spinbutton_up"); + + // The arrow size/position calculation here is based on the arbitrary gymnastics that happen + // in gtkspinbutton.c. It isn't pretty there and it isn't pretty here. This manages to make + // the button look native for many themes though. + IntRect arrowRect; + int arrowSize = (expandedRect.width() - 3) / 2; + arrowSize -= (arrowSize % 2) - 1; // Force odd. + arrowRect.setWidth(arrowSize); + arrowRect.setHeight(arrowSize); + arrowRect.move((expandedRect.width() - arrowRect.width()) / 2, + (topRect.height() - arrowRect.height()) / 2 + 1); + widgetContext.gtkPaintArrow(arrowRect, widget, stateType, shadowType, GTK_ARROW_UP, "spinbutton"); + + shadowType = isPressed(renderObject) && !upPressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT; + if (controlActive) { + if (isPressed(renderObject) && !upPressed) + stateType = GTK_STATE_ACTIVE; + else if (isHovered(renderObject) && !upHovered) + stateType = GTK_STATE_PRELIGHT; + else + stateType = GTK_STATE_NORMAL; + } + IntRect bottomRect(IntPoint(0, expandedRect.height() / 2), expandedRect.size()); + bottomRect.setHeight(expandedRect.height() - bottomRect.y()); + widgetContext.gtkPaintBox(bottomRect, widget, stateType, shadowType, "spinbutton_down"); + + arrowRect.setY(arrowRect.y() + bottomRect.y() - 1); + widgetContext.gtkPaintArrow(arrowRect, widget, stateType, shadowType, GTK_ARROW_DOWN, "spinbutton"); + + return false; } GRefPtr<GdkPixbuf> RenderThemeGtk::getStockIcon(GType widgetType, const char* iconName, gint direction, gint state, gint iconSize) @@ -867,6 +946,15 @@ GtkWidget* RenderThemeGtk::gtkVScrollbar() const return m_gtkVScrollbar; } +GtkWidget* RenderThemeGtk::gtkSpinButton() const +{ + if (m_gtkSpinButton) + return m_gtkSpinButton; + m_gtkSpinButton = gtk_spin_button_new_with_range(0, 10, 1); + setupWidgetAndAddToContainer(m_gtkSpinButton, gtkContainer()); + return m_gtkSpinButton; +} + } // namespace WebCore #endif // GTK_API_VERSION_2 diff --git a/Source/WebCore/platform/gtk/RenderThemeGtk3.cpp b/Source/WebCore/platform/gtk/RenderThemeGtk3.cpp index 7fa0f04..527de1a 100644 --- a/Source/WebCore/platform/gtk/RenderThemeGtk3.cpp +++ b/Source/WebCore/platform/gtk/RenderThemeGtk3.cpp @@ -483,14 +483,14 @@ bool RenderThemeGtk::paintMenuList(RenderObject* renderObject, const PaintInfo& gtk_style_context_get_style(arrowStyleContext, "arrow-scaling", &arrowScaling, NULL); IntSize arrowSize(minArrowSize, innerRect.height()); - IntPoint arrowPosition = innerRect.location(); + FloatPoint arrowPosition(innerRect.location()); if (direction == GTK_TEXT_DIR_LTR) arrowPosition.move(innerRect.width() - arrowSize.width(), 0); // GTK+ actually fetches the xalign and valign values from the widget, but since we // don't have a widget here, we are just using the default xalign and valign values of 0.5. gint extent = std::min(arrowSize.width(), arrowSize.height()) * arrowScaling; - arrowPosition.move(std::floor((arrowSize.width() - extent) / 2), std::floor((arrowSize.height() - extent) / 2)); + arrowPosition.move((arrowSize.width() - extent) / 2, (arrowSize.height() - extent) / 2); gtk_style_context_set_state(arrowStyleContext, state); gtk_render_arrow(arrowStyleContext, cairoContext, G_PI, arrowPosition.x(), arrowPosition.y(), extent); diff --git a/Source/WebCore/platform/gtk/ScrollViewGtk.cpp b/Source/WebCore/platform/gtk/ScrollViewGtk.cpp index c5f32f3..53cacf7 100644 --- a/Source/WebCore/platform/gtk/ScrollViewGtk.cpp +++ b/Source/WebCore/platform/gtk/ScrollViewGtk.cpp @@ -31,6 +31,8 @@ #include "config.h" #include "ScrollView.h" +#if USE(NATIVE_GTK_MAIN_FRAME_SCROLLBAR) + #include "ChromeClient.h" #include "FloatRect.h" #include "Frame.h" @@ -44,7 +46,6 @@ #include "PlatformMouseEvent.h" #include "PlatformWheelEvent.h" #include "ScrollbarTheme.h" - #include <gtk/gtk.h> using namespace std; @@ -228,3 +229,5 @@ void ScrollView::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode v } } + +#endif // USE(NATIVE_GTK_MAIN_FRAME_SCROLLBAR) diff --git a/Source/WebCore/platform/gtk/ScrollbarThemeGtk3.cpp b/Source/WebCore/platform/gtk/ScrollbarThemeGtk3.cpp index d000063..b0b5146 100644 --- a/Source/WebCore/platform/gtk/ScrollbarThemeGtk3.cpp +++ b/Source/WebCore/platform/gtk/ScrollbarThemeGtk3.cpp @@ -135,40 +135,16 @@ void ScrollbarThemeGtk::paintButton(GraphicsContext* context, Scrollbar* scrollb flags |= GTK_STATE_FLAG_INSENSITIVE; gtk_style_context_set_state(m_context, static_cast<GtkStateFlags>(flags)); - guint sides = gtk_style_context_get_junction_sides(m_context); - if (scrollbar->orientation() == VerticalScrollbar) - sides &= ~(GTK_JUNCTION_TOP | GTK_JUNCTION_BOTTOM); - else - sides &= ~(GTK_JUNCTION_LEFT | GTK_JUNCTION_RIGHT); - - switch (part) { - case BackButtonStartPart: - sides |= (scrollbar->orientation() == VerticalScrollbar) ? GTK_JUNCTION_BOTTOM : GTK_JUNCTION_RIGHT; - break; - case BackButtonEndPart: - case ForwardButtonEndPart: - sides |= (scrollbar->orientation() == VerticalScrollbar) ? - GTK_JUNCTION_TOP | GTK_JUNCTION_BOTTOM : GTK_JUNCTION_RIGHT | GTK_JUNCTION_LEFT; - break; - case ForwardButtonStartPart: - sides |= (scrollbar->orientation() == VerticalScrollbar) ? GTK_JUNCTION_TOP : GTK_JUNCTION_LEFT; - break; - default: - ASSERT_NOT_REACHED(); - } - gtk_style_context_set_junction_sides(m_context, static_cast<GtkJunctionSides>(sides)); 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()); gfloat arrowScaling; gtk_style_context_get_style(m_context, "arrow-scaling", &arrowScaling, NULL); - IntSize arrowSize = rect.size(); - arrowSize.scale(arrowScaling); - IntPoint arrowPoint(rect.x() + (rect.width() - arrowSize.width()) / 2, - rect.y() + (rect.height() - arrowSize.height()) / 2); + double arrowSize = std::min(rect.width(), rect.height()) * arrowScaling; + FloatPoint arrowPoint(rect.x() + (rect.width() - arrowSize) / 2, + rect.y() + (rect.height() - arrowSize) / 2); if (flags & GTK_STATE_FLAG_ACTIVE) { gint arrowDisplacementX, arrowDisplacementY; @@ -179,16 +155,14 @@ void ScrollbarThemeGtk::paintButton(GraphicsContext* context, Scrollbar* scrollb arrowPoint.move(arrowDisplacementX, arrowDisplacementY); } - gdouble angle, size; + gdouble angle; if (scrollbar->orientation() == VerticalScrollbar) { - size = arrowSize.width(); angle = (part == ForwardButtonEndPart || part == ForwardButtonStartPart) ? G_PI : 0; } else { - size = arrowSize.height(); angle = (part == ForwardButtonEndPart || part == ForwardButtonStartPart) ? G_PI / 2 : 3 * (G_PI / 2); } - gtk_render_arrow(m_context, context->platformContext(), angle, arrowPoint.x(), arrowPoint.y(), size); + gtk_render_arrow(m_context, context->platformContext(), angle, arrowPoint.x(), arrowPoint.y(), arrowSize); gtk_style_context_restore(m_context); } diff --git a/Source/WebCore/platform/gtk/WidgetGtk.cpp b/Source/WebCore/platform/gtk/WidgetGtk.cpp index f251772..0ab3940 100644 --- a/Source/WebCore/platform/gtk/WidgetGtk.cpp +++ b/Source/WebCore/platform/gtk/WidgetGtk.cpp @@ -41,8 +41,6 @@ namespace WebCore { -static GdkCursor* lastSetCursor; - Widget::Widget(PlatformWidget widget) { init(widget); @@ -60,11 +58,6 @@ void Widget::setFocus(bool focused) gtk_widget_grab_focus(platformWidget() ? platformWidget() : GTK_WIDGET(root()->hostWindow()->platformPageClient())); } -static GdkWindow* gdkWindow(PlatformWidget widget) -{ - return widget ? gtk_widget_get_window(widget) : 0; -} - void Widget::setCursor(const Cursor& cursor) { ScrollView* view = root(); diff --git a/Source/WebCore/platform/gtk/WidgetRenderingContext.cpp b/Source/WebCore/platform/gtk/WidgetRenderingContext.cpp index 9e640f6..6f7389d 100644 --- a/Source/WebCore/platform/gtk/WidgetRenderingContext.cpp +++ b/Source/WebCore/platform/gtk/WidgetRenderingContext.cpp @@ -33,6 +33,7 @@ #include "GraphicsContext.h" #include "GtkVersioning.h" +#include "PlatformContextCairo.h" #include "RefPtrCairo.h" #include "RenderThemeGtk.h" #include "Timer.h" @@ -128,7 +129,7 @@ WidgetRenderingContext::~WidgetRenderingContext() } // FIXME: It's unclear if it is necessary to preserve the current source here. - cairo_t* cairoContext = m_graphicsContext->platformContext(); + cairo_t* cairoContext = m_graphicsContext->platformContext()->cr(); RefPtr<cairo_pattern_t> previousSource(cairo_get_source(cairoContext)); // The blit rectangle is the original target rectangle adjusted for any extra space. diff --git a/Source/WebCore/platform/haiku/FileSystemHaiku.cpp b/Source/WebCore/platform/haiku/FileSystemHaiku.cpp index b0d34f2..7985c54 100644 --- a/Source/WebCore/platform/haiku/FileSystemHaiku.cpp +++ b/Source/WebCore/platform/haiku/FileSystemHaiku.cpp @@ -56,11 +56,11 @@ String homeDirectoryPath() return String(path.Path()); } -CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle) +String openTemporaryFile(const String&, PlatformFileHandle& handle) { notImplemented(); handle = invalidPlatformFileHandle; - return CString(); + return String(); } void closeFile(PlatformFileHandle&) diff --git a/Source/WebCore/platform/haiku/LocalizedStringsHaiku.cpp b/Source/WebCore/platform/haiku/LocalizedStringsHaiku.cpp index 63b9b91..c1f3641 100644 --- a/Source/WebCore/platform/haiku/LocalizedStringsHaiku.cpp +++ b/Source/WebCore/platform/haiku/LocalizedStringsHaiku.cpp @@ -213,7 +213,7 @@ String contextMenuItemTagSearchWeb() return "Search web"; } -String contextMenuItemTagLookUpInDictionary() +String contextMenuItemTagLookUpInDictionary(const String&) { return "Lookup in dictionary"; } diff --git a/Source/WebCore/platform/image-decoders/ImageDecoder.h b/Source/WebCore/platform/image-decoders/ImageDecoder.h index 2a307c5..801daf3 100644 --- a/Source/WebCore/platform/image-decoders/ImageDecoder.h +++ b/Source/WebCore/platform/image-decoders/ImageDecoder.h @@ -62,7 +62,7 @@ namespace WebCore { DisposeNotSpecified, // Leave frame in framebuffer DisposeKeep, // Leave frame in framebuffer DisposeOverwriteBgcolor, // Clear frame to transparent - DisposeOverwritePrevious, // Clear frame to previous framebuffer + DisposeOverwritePrevious // Clear frame to previous framebuffer // contents }; #if USE(SKIA) || PLATFORM(QT) diff --git a/Source/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp b/Source/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp index 8edfe36..8419a97 100644 --- a/Source/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp +++ b/Source/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp @@ -241,11 +241,11 @@ void PNGImageDecoder::headerAvailable() { png_structp png = m_reader->pngPtr(); png_infop info = m_reader->infoPtr(); - png_uint_32 width = png->width; - png_uint_32 height = png->height; + png_uint_32 width = png_get_image_width(png, info); + png_uint_32 height = png_get_image_height(png, info); // Protect against large images. - if (png->width > cMaxPNGSize || png->height > cMaxPNGSize) { + if (width > cMaxPNGSize || height > cMaxPNGSize) { longjmp(JMPBUF(png), 1); return; } @@ -318,9 +318,14 @@ void PNGImageDecoder::headerAvailable() m_reader->setHasAlpha(channels == 4); if (m_reader->decodingSizeOnly()) { - // If we only needed the size, halt the reader. + // If we only needed the size, halt the reader. +#if defined(PNG_LIBPNG_VER_MAJOR) && defined(PNG_LIBPNG_VER_MINOR) && (PNG_LIBPNG_VER_MAJOR > 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 5)) + // '0' argument to png_process_data_pause means: Do not cache unprocessed data. + m_reader->setReadOffset(m_reader->currentBufferSize() - png_process_data_pause(png, 0)); +#else m_reader->setReadOffset(m_reader->currentBufferSize() - png->buffer_size); png->buffer_size = 0; +#endif } } @@ -343,7 +348,7 @@ void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex, // For PNGs, the frame always fills the entire image. buffer.setOriginalFrameRect(IntRect(IntPoint(), size())); - if (m_reader->pngPtr()->interlaced) + if (png_get_interlace_type(m_reader->pngPtr(), m_reader->infoPtr()) != PNG_INTERLACE_NONE) m_reader->createInterlaceBuffer((m_reader->hasAlpha() ? 4 : 3) * size().width() * size().height()); } diff --git a/Source/WebCore/platform/image-encoders/skia/JPEGImageEncoder.cpp b/Source/WebCore/platform/image-encoders/skia/JPEGImageEncoder.cpp index be3c92a..f0ac601 100644 --- a/Source/WebCore/platform/image-encoders/skia/JPEGImageEncoder.cpp +++ b/Source/WebCore/platform/image-encoders/skia/JPEGImageEncoder.cpp @@ -31,6 +31,7 @@ #include "config.h" #include "JPEGImageEncoder.h" +#include "ImageData.h" #include "IntSize.h" #include "SkBitmap.h" #include "SkColorPriv.h" @@ -79,22 +80,29 @@ static void handleError(j_common_ptr common) longjmp(*jumpBufferPtr, -1); } -static void preMultipliedBGRAtoRGB(const SkPMColor* input, unsigned int pixels, unsigned char* output) +static void preMultipliedBGRAtoRGB(const void* pixels, unsigned int pixelCount, unsigned char* output) { - for (; pixels-- > 0; ++input) { + const SkPMColor* input = static_cast<const SkPMColor*>(pixels); + for (; pixelCount-- > 0; ++input) { *output++ = SkGetPackedR32(*input); *output++ = SkGetPackedG32(*input); *output++ = SkGetPackedB32(*input); } } -bool JPEGImageEncoder::encode(const SkBitmap& bitmap, int quality, Vector<unsigned char>* output) +static void RGBAtoRGB(const unsigned char* input, unsigned int pixels, unsigned char* output) { - if (bitmap.config() != SkBitmap::kARGB_8888_Config) - return false; // Only support ARGB 32 bpp skia bitmaps. + for (; pixels-- > 0; input += 4) { + *output++ = input[0]; + *output++ = input[1]; + *output++ = input[2]; + } +} - SkAutoLockPixels bitmapLock(bitmap); - IntSize imageSize(bitmap.width(), bitmap.height()); +static bool encodePixels(const IntSize& inputSize, unsigned char* inputPixels, + bool premultiplied, int quality, Vector<unsigned char>* output) +{ + IntSize imageSize(inputSize); imageSize.clampNegativeToZero(); JPEGOutputBuffer destination; destination.output = output; @@ -126,12 +134,15 @@ bool JPEGImageEncoder::encode(const SkBitmap& bitmap, int quality, Vector<unsign jpeg_set_quality(&cinfo, quality, TRUE); jpeg_start_compress(&cinfo, TRUE); - const SkPMColor* pixels = static_cast<SkPMColor*>(bitmap.getPixels()); + unsigned char* pixels = inputPixels; row.resize(cinfo.image_width * cinfo.input_components); while (cinfo.next_scanline < cinfo.image_height) { - preMultipliedBGRAtoRGB(pixels, cinfo.image_width, row.data()); + if (premultiplied) + preMultipliedBGRAtoRGB(pixels, cinfo.image_width, row.data()); + else + RGBAtoRGB(pixels, cinfo.image_width, row.data()); jpeg_write_scanlines(&cinfo, row.dataSlot(), 1); - pixels += cinfo.image_width; + pixels += cinfo.image_width * 4; } jpeg_finish_compress(&cinfo); @@ -139,4 +150,22 @@ bool JPEGImageEncoder::encode(const SkBitmap& bitmap, int quality, Vector<unsign return true; } +bool JPEGImageEncoder::encode(const SkBitmap& bitmap, int quality, Vector<unsigned char>* output) +{ + if (bitmap.config() != SkBitmap::kARGB_8888_Config) + return false; // Only support ARGB 32 bpp skia bitmaps. + + SkAutoLockPixels bitmapLock(bitmap); + IntSize imageSize(bitmap.width(), bitmap.height()); + + return encodePixels(imageSize, static_cast<unsigned char *>(bitmap.getPixels()), + true, quality, output); +} + +bool JPEGImageEncoder::encode(const ImageData& imageData, int quality, Vector<unsigned char>* output) +{ + return encodePixels(imageData.size(), imageData.data()->data()->data(), + false, quality, output); +} + } // namespace WebCore diff --git a/Source/WebCore/platform/image-encoders/skia/JPEGImageEncoder.h b/Source/WebCore/platform/image-encoders/skia/JPEGImageEncoder.h index f2ac52d..122725d 100644 --- a/Source/WebCore/platform/image-encoders/skia/JPEGImageEncoder.h +++ b/Source/WebCore/platform/image-encoders/skia/JPEGImageEncoder.h @@ -31,16 +31,19 @@ #ifndef JPEGImageEncoder_h #define JPEGImageEncoder_h -#include "Vector.h" +#include <wtf/Vector.h> class SkBitmap; namespace WebCore { +class ImageData; + class JPEGImageEncoder { public: - // Encode the input bitmap with a compression quality in [0-100]. + // Encode the input data with a compression quality in [0-100]. static bool encode(const SkBitmap&, int quality, Vector<unsigned char>*); + static bool encode(const ImageData&, int quality, Vector<unsigned char>*); // For callers: provide a reasonable compression quality default. enum Quality { DefaultCompressionQuality = 92 }; diff --git a/Source/WebCore/platform/image-encoders/skia/PNGImageEncoder.cpp b/Source/WebCore/platform/image-encoders/skia/PNGImageEncoder.cpp index 78f737e..2fc758e 100644 --- a/Source/WebCore/platform/image-encoders/skia/PNGImageEncoder.cpp +++ b/Source/WebCore/platform/image-encoders/skia/PNGImageEncoder.cpp @@ -31,6 +31,7 @@ #include "config.h" #include "PNGImageEncoder.h" +#include "ImageData.h" #include "IntSize.h" #include "SkBitmap.h" #include "SkColorPriv.h" @@ -46,11 +47,12 @@ static void writeOutput(png_structp png, png_bytep data, png_size_t size) static_cast<Vector<unsigned char>*>(png->io_ptr)->append(data, size); } -static void preMultipliedBGRAtoRGBA(const SkPMColor* input, int pixels, unsigned char* output) +static void preMultipliedBGRAtoRGBA(const void* pixels, int pixelCount, unsigned char* output) { static const SkUnPreMultiply::Scale* scale = SkUnPreMultiply::GetScaleTable(); + const SkPMColor* input = static_cast<const SkPMColor*>(pixels); - for (; pixels-- > 0; ++input) { + for (; pixelCount-- > 0; ++input) { const unsigned alpha = SkGetPackedA32(*input); if ((alpha != 0) && (alpha != 255)) { *output++ = SkUnPreMultiply::ApplyScale(scale[alpha], SkGetPackedR32(*input)); @@ -66,13 +68,10 @@ static void preMultipliedBGRAtoRGBA(const SkPMColor* input, int pixels, unsigned } } -bool PNGImageEncoder::encode(const SkBitmap& bitmap, Vector<unsigned char>* output) +static bool encodePixels(const IntSize& inputSize, unsigned char* inputPixels, + bool premultiplied, Vector<unsigned char>* output) { - if (bitmap.config() != SkBitmap::kARGB_8888_Config) - return false; // Only support ARGB 32 bpp skia bitmaps. - - SkAutoLockPixels bitmapLock(bitmap); - IntSize imageSize(bitmap.width(), bitmap.height()); + IntSize imageSize(inputSize); imageSize.clampNegativeToZero(); Vector<unsigned char> row; @@ -100,12 +99,15 @@ bool PNGImageEncoder::encode(const SkBitmap& bitmap, Vector<unsigned char>* outp 8, PNG_COLOR_TYPE_RGB_ALPHA, 0, 0, 0); png_write_info(png, info); - const SkPMColor* pixels = static_cast<SkPMColor*>(bitmap.getPixels()); - row.resize(imageSize.width() * bitmap.bytesPerPixel()); + unsigned char* pixels = inputPixels; + row.resize(imageSize.width() * sizeof(SkPMColor)); for (int y = 0; y < imageSize.height(); ++y) { - preMultipliedBGRAtoRGBA(pixels, imageSize.width(), row.data()); - png_write_row(png, row.data()); - pixels += imageSize.width(); + if (premultiplied) { + preMultipliedBGRAtoRGBA(pixels, imageSize.width(), row.data()); + png_write_row(png, row.data()); + } else + png_write_row(png, pixels); + pixels += imageSize.width() * 4; } png_write_end(png, info); @@ -113,4 +115,19 @@ bool PNGImageEncoder::encode(const SkBitmap& bitmap, Vector<unsigned char>* outp return true; } +bool PNGImageEncoder::encode(const SkBitmap& bitmap, Vector<unsigned char>* output) +{ + if (bitmap.config() != SkBitmap::kARGB_8888_Config) + return false; // Only support ARGB 32 bpp skia bitmaps. + + SkAutoLockPixels bitmapLock(bitmap); + IntSize imageSize(bitmap.width(), bitmap.height()); + return encodePixels(imageSize, static_cast<unsigned char*>(bitmap.getPixels()), true, output); +} + +bool PNGImageEncoder::encode(const ImageData& bitmap, Vector<unsigned char>* output) +{ + return encodePixels(bitmap.size(), bitmap.data()->data()->data(), false, output); +} + } // namespace WebCore diff --git a/Source/WebCore/platform/image-encoders/skia/PNGImageEncoder.h b/Source/WebCore/platform/image-encoders/skia/PNGImageEncoder.h index b8dfec3..31edad3 100644 --- a/Source/WebCore/platform/image-encoders/skia/PNGImageEncoder.h +++ b/Source/WebCore/platform/image-encoders/skia/PNGImageEncoder.h @@ -31,16 +31,19 @@ #ifndef PNGImageEncoder_h #define PNGImageEncoder_h -#include "Vector.h" +#include <wtf/Vector.h> class SkBitmap; namespace WebCore { +class ImageData; + // Interface for encoding PNG data. This is a wrapper around libpng. class PNGImageEncoder { public: static bool encode(const SkBitmap&, Vector<unsigned char>* output); + static bool encode(const ImageData&, Vector<unsigned char>* output); }; } // namespace WebCore diff --git a/Source/WebCore/platform/mac/FileSystemMac.mm b/Source/WebCore/platform/mac/FileSystemMac.mm index 8cdd382..a9cbcf4 100644 --- a/Source/WebCore/platform/mac/FileSystemMac.mm +++ b/Source/WebCore/platform/mac/FileSystemMac.mm @@ -41,28 +41,29 @@ String homeDirectoryPath() return NSHomeDirectory(); } -CString openTemporaryFile(const char* prefix, PlatformFileHandle& platformFileHandle) +String openTemporaryFile(const String& prefix, PlatformFileHandle& platformFileHandle) { platformFileHandle = invalidPlatformFileHandle; Vector<char> temporaryFilePath(PATH_MAX); if (!confstr(_CS_DARWIN_USER_TEMP_DIR, temporaryFilePath.data(), temporaryFilePath.size())) - return CString(); + return String(); // Shrink the vector. temporaryFilePath.shrink(strlen(temporaryFilePath.data())); ASSERT(temporaryFilePath.last() == '/'); - // Append the file name. - temporaryFilePath.append(prefix, strlen(prefix)); + // Append the file name. + CString prefixUtf8 = prefix.utf8(); + temporaryFilePath.append(prefixUtf8.data(), prefixUtf8.length()); temporaryFilePath.append("XXXXXX", 6); temporaryFilePath.append('\0'); platformFileHandle = mkstemp(temporaryFilePath.data()); if (platformFileHandle == invalidPlatformFileHandle) - return CString(); + return String(); - return CString(temporaryFilePath.data()); + return String::fromUTF8(temporaryFilePath.data()); } bool canExcludeFromBackup() diff --git a/Source/WebCore/platform/mac/HTMLConverter.h b/Source/WebCore/platform/mac/HTMLConverter.h new file mode 100644 index 0000000..645c1d7 --- /dev/null +++ b/Source/WebCore/platform/mac/HTMLConverter.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "DOM.h" +#import "DOMDocument.h" +#import "DOMRange.h" + +namespace WebCore { +class DocumentLoader; +} + +@interface WebHTMLConverter : NSObject { + NSMutableAttributedString *_attrStr; + NSURL *_baseURL; + DOMDocument *_document; + DOMRange *_domRange; + NSMutableArray *_domStartAncestors; + WebCore::DocumentLoader *_dataSource; + NSString *_standardFontFamily; + CGFloat _textSizeMultiplier; + CGFloat _webViewTextSizeMultiplier; + CGFloat _defaultTabInterval; + CGFloat _defaultFontSize; + CGFloat _minimumFontSize; + NSMutableArray *_textLists; + NSMutableArray *_textBlocks; + NSMutableArray *_textTables; + NSMutableDictionary *_textTableFooters; + NSMutableArray *_textTableSpacings; + NSMutableArray *_textTablePaddings; + NSMutableArray *_textTableRows; + NSMutableArray *_textTableRowArrays; + NSMutableArray *_textTableRowBackgroundColors; + NSMutableDictionary *_computedStylesForElements; + NSMutableDictionary *_specifiedStylesForElements; + NSMutableDictionary *_stringsForNodes; + NSMutableDictionary *_floatsForNodes; + NSMutableDictionary *_colorsForNodes; + NSMutableDictionary *_attributesForElements; + NSMutableDictionary *_elementIsBlockLevel; + NSMutableDictionary *_fontCache; + NSMutableArray *_writingDirectionArray; + NSUInteger _domRangeStartIndex; + NSInteger _indexingLimit; + NSUInteger _thumbnailLimit; + NSInteger _errorCode; + NSInteger _quoteLevel; + + struct { + unsigned int isSoft:1; + unsigned int reachedStart:1; + unsigned int reachedEnd:1; + unsigned int isIndexing:1; + unsigned int isTesting:1; + unsigned int hasTrailingNewline:1; + unsigned int pad:26; + } _flags; +} + +- (id)init; +- (id)initWithDOMRange:(DOMRange *)domRange; + +- (NSAttributedString *)attributedString; + +@end + diff --git a/Source/WebCore/platform/mac/HTMLConverter.mm b/Source/WebCore/platform/mac/HTMLConverter.mm new file mode 100644 index 0000000..a4864c2 --- /dev/null +++ b/Source/WebCore/platform/mac/HTMLConverter.mm @@ -0,0 +1,1682 @@ +/* + * 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. + */ + +#import "config.h" +#import "HTMLConverter.h" + +#import "ArchiveResource.h" +#import "Document.h" +#import "DocumentLoader.h" +#import "DOMDocumentInternal.h" +#import "DOMElementInternal.h" +#import "DOMHTMLTableCellElement.h" +#import "DOMPrivate.h" +#import "Element.h" +#import "Frame.h" +#import "HTMLNames.h" +#import "HTMLParserIdioms.h" +#import <wtf/ASCIICType.h> + +using namespace WebCore; +using namespace HTMLNames; + +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +// Additional control Unicode characters +const unichar WebNextLineCharacter = 0x0085; + +@interface NSTextList (TextListPrivate) ++ (NSDictionary *)_standardMarkerAttributesForAttributes:(NSDictionary *)attrs; +@end + +@interface NSTextAttachment (NSIgnoreOrientation) +- (void)setIgnoresOrientation:(BOOL)flag; +- (BOOL)ignoresOrientation; +@end + +@interface NSURL (WebDataURL) ++ (NSURL *)_web_uniqueWebDataURL; ++ (NSURL *)_web_uniqueWebDataURLWithRelativeString:(NSString *)string; ++ (NSURL *)_web_URLWithString:(NSString *)string relativeToURL:(NSURL *)baseURL; +- (NSString *)_web_suggestedFilenameWithMIMEType:(NSString *)MIMEType; +@end + +@interface WebHTMLConverter(WebHTMLConverterPrivate) + +- (NSString *)_stringForNode:(DOMNode *)node property:(NSString *)key; +- (NSColor *)_colorForNode:(DOMNode *)node property:(NSString *)key; +- (BOOL)_getFloat:(CGFloat *)val forNode:(DOMNode *)node property:(NSString *)key; +- (void)_traverseNode:(DOMNode *)node depth:(NSInteger)depth embedded:(BOOL)embedded; +- (void)_traverseFooterNode:(DOMNode *)node depth:(NSInteger)depth; + +@end + +// Returns the font to be used if the NSFontAttributeName doesn't exist +static NSFont *WebDefaultFont() +{ + static NSFont *defaultFont = nil; + + if (defaultFont) + return defaultFont; + + NSFont *font = [NSFont fontWithName:@"Helvetica" size:12]; + if (!font) + font = [NSFont systemFontOfSize:12]; + + defaultFont = [font retain]; + + return defaultFont; +} + +@implementation WebHTMLConverter + +static NSFont *_fontForNameAndSize(NSString *fontName, CGFloat size, NSMutableDictionary *cache) +{ + NSFontManager *fontManager = [NSFontManager sharedFontManager]; + NSFont *font = [cache objectForKey:fontName]; + + if (font) { + font = [fontManager convertFont:font toSize:size]; + return font; + } + font = [fontManager fontWithFamily:fontName traits:0 weight:0 size:size]; + if (!font) { + NSArray *availableFamilyNames = [fontManager availableFontFamilies]; + NSRange dividingRange, dividingSpaceRange = [fontName rangeOfString:@" " options:NSBackwardsSearch], dividingDashRange = [fontName rangeOfString:@"-" options:NSBackwardsSearch]; + dividingRange = (0 < dividingSpaceRange.length && 0 < dividingDashRange.length) ? (dividingSpaceRange.location > dividingDashRange.location ? dividingSpaceRange : dividingDashRange) : (0 < dividingSpaceRange.length ? dividingSpaceRange : dividingDashRange); + while (0 < dividingRange.length) { + NSString *familyName = [fontName substringToIndex:dividingRange.location]; + if ([availableFamilyNames containsObject:familyName]) { + NSArray *familyMemberArray; + NSString *faceName = [fontName substringFromIndex:(dividingRange.location + dividingRange.length)]; + NSArray *familyMemberArrays = [fontManager availableMembersOfFontFamily:familyName]; + NSEnumerator *familyMemberArraysEnum = [familyMemberArrays objectEnumerator]; + while ((familyMemberArray = [familyMemberArraysEnum nextObject])) { + NSString *familyMemberFaceName = [familyMemberArray objectAtIndex:1]; + if ([familyMemberFaceName compare:faceName options:NSCaseInsensitiveSearch] == NSOrderedSame) { + NSFontTraitMask traits = [[familyMemberArray objectAtIndex:3] integerValue]; + NSInteger weight = [[familyMemberArray objectAtIndex:2] integerValue]; + font = [fontManager fontWithFamily:familyName traits:traits weight:weight size:size]; + break; + } + } + if (!font) { + if (0 < [familyMemberArrays count]) { + NSArray *familyMemberArray = [familyMemberArrays objectAtIndex:0]; + NSFontTraitMask traits = [[familyMemberArray objectAtIndex:3] integerValue]; + NSInteger weight = [[familyMemberArray objectAtIndex:2] integerValue]; + font = [fontManager fontWithFamily:familyName traits:traits weight:weight size:size]; + } + } + break; + } else { + dividingSpaceRange = [familyName rangeOfString:@" " options:NSBackwardsSearch]; + dividingDashRange = [familyName rangeOfString:@"-" options:NSBackwardsSearch]; + dividingRange = (0 < dividingSpaceRange.length && 0 < dividingDashRange.length) ? (dividingSpaceRange.location > dividingDashRange.location ? dividingSpaceRange : dividingDashRange) : (0 < dividingSpaceRange.length ? dividingSpaceRange : dividingDashRange); + } + } + } + if (!font) font = [NSFont fontWithName:@"Times" size:size]; + if (!font) font = [NSFont userFontOfSize:size]; + if (!font) font = [fontManager convertFont:WebDefaultFont() toSize:size]; + if (!font) font = WebDefaultFont(); + [cache setObject:font forKey:fontName]; + return font; +} + ++ (NSParagraphStyle *)defaultParagraphStyle +{ + static NSMutableParagraphStyle *defaultParagraphStyle = nil; + if (!defaultParagraphStyle) { + defaultParagraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; + [defaultParagraphStyle setDefaultTabInterval:36]; + [defaultParagraphStyle setTabStops:[NSArray array]]; + } + return defaultParagraphStyle; +} + +- (NSArray *)_childrenForNode:(DOMNode *)node +{ + NSMutableArray *array = [NSMutableArray array]; + DOMNode *child = [node firstChild]; + while (child) { + [array addObject:child]; + child = [child nextSibling]; + } + return array; +} + +- (DOMCSSStyleDeclaration *)_computedStyleForElement:(DOMElement *)element +{ + DOMDocument *document = [element ownerDocument]; + DOMCSSStyleDeclaration *result = nil; + result = [_computedStylesForElements objectForKey:element]; + if (result) { + if ([[NSNull null] isEqual:result]) result = nil; + } else { + result = [document getComputedStyle:element pseudoElement:@""] ; + [_computedStylesForElements setObject:(result ? (id)result : (id)[NSNull null]) forKey:element]; + } + return result; +} + +- (DOMCSSStyleDeclaration *)_specifiedStyleForElement:(DOMElement *)element +{ + DOMCSSStyleDeclaration *result = [_specifiedStylesForElements objectForKey:element]; + if (result) { + if ([[NSNull null] isEqual:result]) result = nil; + } else { + result = [element style]; + [_specifiedStylesForElements setObject:(result ? (id)result : (id)[NSNull null]) forKey:element]; + } + return result; +} + +- (NSString *)_computedStringForNode:(DOMNode *)node property:(NSString *)key +{ + NSString *result = nil; + BOOL inherit = YES; + DOMElement *element = (DOMElement *)node; + if (element && [element nodeType] == DOM_ELEMENT_NODE) { + DOMCSSStyleDeclaration *computedStyle, *specifiedStyle; + inherit = NO; + if (!result && (computedStyle = [self _computedStyleForElement:element])) { + DOMCSSPrimitiveValue *computedValue = (DOMCSSPrimitiveValue *)[computedStyle getPropertyCSSValue:key]; + if (computedValue) { + unsigned short valueType = [computedValue cssValueType]; + if (valueType == DOM_CSS_PRIMITIVE_VALUE) { + unsigned short primitiveType = [computedValue primitiveType]; + if (primitiveType == DOM_CSS_STRING || primitiveType == DOM_CSS_URI || primitiveType == DOM_CSS_IDENT || primitiveType == DOM_CSS_ATTR) { + result = [computedValue getStringValue]; + if (result && [result length] == 0) result = nil; + } + } else if (valueType == DOM_CSS_VALUE_LIST) { + result = [computedStyle getPropertyValue:key]; + } + } + } + if (!result && (specifiedStyle = [self _specifiedStyleForElement:element])) { + DOMCSSPrimitiveValue *specifiedValue = (DOMCSSPrimitiveValue *)[specifiedStyle getPropertyCSSValue:key]; + if (specifiedValue) { + unsigned short valueType = [specifiedValue cssValueType]; + if (valueType == DOM_CSS_PRIMITIVE_VALUE) { + unsigned short primitiveType = [specifiedValue primitiveType]; + if (primitiveType == DOM_CSS_STRING || primitiveType == DOM_CSS_URI || primitiveType == DOM_CSS_IDENT || primitiveType == DOM_CSS_ATTR) { + result = [specifiedValue getStringValue]; + if (result && [result length] == 0) result = nil; + // ??? hack alert + if (!result) { + result = [specifiedStyle getPropertyValue:key]; + } + } + } else if (valueType == DOM_CSS_INHERIT) { + inherit = YES; + } else if (valueType == DOM_CSS_VALUE_LIST) { + result = [specifiedStyle getPropertyValue:key]; + } + } + } + if (!result) { + Element* coreElement = core(element); + if ([@"display" isEqualToString:key]) { + if (coreElement->hasTagName(headTag) || coreElement->hasTagName(scriptTag) || coreElement->hasTagName(appletTag) || coreElement->hasTagName(noframesTag)) + result = @"none"; + else if (coreElement->hasTagName(addressTag) || coreElement->hasTagName(blockquoteTag) || coreElement->hasTagName(bodyTag) || coreElement->hasTagName(centerTag) + || coreElement->hasTagName(ddTag) || coreElement->hasTagName(dirTag) || coreElement->hasTagName(divTag) || coreElement->hasTagName(dlTag) + || coreElement->hasTagName(dtTag) || coreElement->hasTagName(fieldsetTag) || coreElement->hasTagName(formTag) || coreElement->hasTagName(frameTag) + || coreElement->hasTagName(framesetTag) || coreElement->hasTagName(hrTag) || coreElement->hasTagName(htmlTag) || coreElement->hasTagName(h1Tag) + || coreElement->hasTagName(h2Tag) || coreElement->hasTagName(h3Tag) || coreElement->hasTagName(h4Tag) || coreElement->hasTagName(h5Tag) + || coreElement->hasTagName(h6Tag) || coreElement->hasTagName(iframeTag) || coreElement->hasTagName(menuTag) || coreElement->hasTagName(noscriptTag) + || coreElement->hasTagName(olTag) || coreElement->hasTagName(pTag) || coreElement->hasTagName(preTag) || coreElement->hasTagName(ulTag)) + result = @"block"; + else if (coreElement->hasTagName(liTag)) + result = @"list-item"; + else if (coreElement->hasTagName(tableTag)) + result = @"table"; + else if (coreElement->hasTagName(trTag)) + result = @"table-row"; + else if (coreElement->hasTagName(thTag) || coreElement->hasTagName(tdTag)) + result = @"table-cell"; + else if (coreElement->hasTagName(theadTag)) + result = @"table-header-group"; + else if (coreElement->hasTagName(tbodyTag)) + result = @"table-row-group"; + else if (coreElement->hasTagName(tfootTag)) + result = @"table-footer-group"; + else if (coreElement->hasTagName(colTag)) + result = @"table-column"; + else if (coreElement->hasTagName(colgroupTag)) + result = @"table-column-group"; + else if (coreElement->hasTagName(captionTag)) + result = @"table-caption"; + } else if ([@"white-space" isEqualToString:key]) { + if (coreElement->hasTagName(preTag)) + result = @"pre"; + else + inherit = YES; + } else if ([@"font-style" isEqualToString:key]) { + if (coreElement->hasTagName(iTag) || coreElement->hasTagName(citeTag) || coreElement->hasTagName(emTag) || coreElement->hasTagName(varTag) || coreElement->hasTagName(addressTag)) + result = @"italic"; + else + inherit = YES; + } else if ([@"font-weight" isEqualToString:key]) { + if (coreElement->hasTagName(bTag) || coreElement->hasTagName(strongTag) || coreElement->hasTagName(thTag)) + result = @"bolder"; + else + inherit = YES; + } else if ([@"text-decoration" isEqualToString:key]) { + if (coreElement->hasTagName(uTag) || coreElement->hasTagName(insTag)) + result = @"underline"; + else if (coreElement->hasTagName(sTag) || coreElement->hasTagName(strikeTag) || coreElement->hasTagName(delTag)) + result = @"line-through"; + else + inherit = YES; // ??? this is not strictly correct + } else if ([@"text-align" isEqualToString:key]) { + if (coreElement->hasTagName(centerTag) || coreElement->hasTagName(captionTag) || coreElement->hasTagName(thTag)) + result = @"center"; + else + inherit = YES; + } else if ([@"vertical-align" isEqualToString:key]) { + if (coreElement->hasTagName(supTag)) + result = @"super"; + else if (coreElement->hasTagName(subTag)) + result = @"sub"; + else if (coreElement->hasTagName(theadTag) || coreElement->hasTagName(tbodyTag) || coreElement->hasTagName(tfootTag)) + result = @"middle"; + else if (coreElement->hasTagName(trTag) || coreElement->hasTagName(thTag) || coreElement->hasTagName(tdTag)) + inherit = YES; + } else if ([@"font-family" isEqualToString:key] || [@"font-variant" isEqualToString:key] || [@"font-effect" isEqualToString:key] + || [@"text-transform" isEqualToString:key] || [@"text-shadow" isEqualToString:key] || [@"visibility" isEqualToString:key] + || [@"border-collapse" isEqualToString:key] || [@"empty-cells" isEqualToString:key] || [@"word-spacing" isEqualToString:key] + || [@"list-style-type" isEqualToString:key] || [@"direction" isEqualToString:key]) { + inherit = YES; + } + } + } + if (!result && inherit) { + DOMNode *parentNode = [node parentNode]; + if (parentNode) result = [self _stringForNode:parentNode property:key]; + } + return result ? [result lowercaseString] : nil; +} + +- (NSString *)_stringForNode:(DOMNode *)node property:(NSString *)key +{ + NSString *result = nil; + NSMutableDictionary *attributeDictionary = [_stringsForNodes objectForKey:node]; + if (!attributeDictionary) { + attributeDictionary = [[NSMutableDictionary alloc] init]; + [_stringsForNodes setObject:attributeDictionary forKey:node]; + [attributeDictionary release]; + } + result = [attributeDictionary objectForKey:key]; + if (result) { + if ([@"" isEqualToString:result]) result = nil; + } else { + result = [self _computedStringForNode:node property:key]; + [attributeDictionary setObject:(result ? result : @"") forKey:key]; + } + return result; +} + +static inline BOOL _getFloat(DOMCSSPrimitiveValue *primitiveValue, CGFloat *val) +{ + if (!val) + return NO; + switch ([primitiveValue primitiveType]) { + case DOM_CSS_PX: + *val = [primitiveValue getFloatValue:DOM_CSS_PX]; + return YES; + case DOM_CSS_PT: + *val = 4 * [primitiveValue getFloatValue:DOM_CSS_PT] / 3; + return YES; + case DOM_CSS_PC: + *val = 16 * [primitiveValue getFloatValue:DOM_CSS_PC]; + return YES; + case DOM_CSS_CM: + *val = 96 * [primitiveValue getFloatValue:DOM_CSS_CM] / (CGFloat)2.54; + return YES; + case DOM_CSS_MM: + *val = 96 * [primitiveValue getFloatValue:DOM_CSS_MM] / (CGFloat)25.4; + return YES; + case DOM_CSS_IN: + *val = 96 * [primitiveValue getFloatValue:DOM_CSS_IN]; + return YES; + default: + return NO; + } +} + +- (BOOL)_getComputedFloat:(CGFloat *)val forNode:(DOMNode *)node property:(NSString *)key +{ + BOOL result = NO, inherit = YES; + CGFloat floatVal = 0; + DOMElement *element = (DOMElement *)node; + if (element && [element nodeType] == DOM_ELEMENT_NODE) { + DOMCSSStyleDeclaration *computedStyle, *specifiedStyle; + inherit = NO; + if (!result && (computedStyle = [self _computedStyleForElement:element])) { + DOMCSSPrimitiveValue *computedValue = (DOMCSSPrimitiveValue *)[computedStyle getPropertyCSSValue:key]; + if (computedValue && [computedValue cssValueType] == DOM_CSS_PRIMITIVE_VALUE) { + result = _getFloat(computedValue, &floatVal); + } + } + if (!result && (specifiedStyle = [self _specifiedStyleForElement:element])) { + DOMCSSPrimitiveValue *specifiedValue = (DOMCSSPrimitiveValue *)[specifiedStyle getPropertyCSSValue:key]; + if (specifiedValue) { + unsigned short valueType = [specifiedValue cssValueType]; + if (valueType == DOM_CSS_PRIMITIVE_VALUE) { + result = _getFloat(specifiedValue, &floatVal); + } else if (valueType == DOM_CSS_INHERIT) { + inherit = YES; + } + } + } + if (!result) { + if ([@"text-indent" isEqualToString:key] || [@"letter-spacing" isEqualToString:key] || [@"word-spacing" isEqualToString:key] + || [@"line-height" isEqualToString:key] || [@"widows" isEqualToString:key] || [@"orphans" isEqualToString:key]) + inherit = YES; + } + } + if (!result && inherit) { + DOMNode *parentNode = [node parentNode]; + if (parentNode) result = [self _getFloat:&floatVal forNode:parentNode property:key]; + } + if (result && val) + *val = floatVal; + return result; +} + +- (BOOL)_getFloat:(CGFloat *)val forNode:(DOMNode *)node property:(NSString *)key +{ + BOOL result = NO; + CGFloat floatVal = 0; + NSNumber *floatNumber; + NSMutableDictionary *attributeDictionary = [_floatsForNodes objectForKey:node]; + if (!attributeDictionary) { + attributeDictionary = [[NSMutableDictionary alloc] init]; + [_floatsForNodes setObject:attributeDictionary forKey:node]; + [attributeDictionary release]; + } + floatNumber = [attributeDictionary objectForKey:key]; + if (floatNumber) { + if (![[NSNull null] isEqual:floatNumber]) { + result = YES; + floatVal = [floatNumber floatValue]; + } + } else { + result = [self _getComputedFloat:&floatVal forNode:node property:key]; + [attributeDictionary setObject:(result ? (id)[NSNumber numberWithDouble:floatVal] : (id)[NSNull null]) forKey:key]; + } + if (result && val) *val = floatVal; + return result; +} + +static inline NSColor *_colorForRGBColor(DOMRGBColor *domRGBColor, BOOL ignoreBlack) +{ + NSColor *color = [domRGBColor _color]; + NSColorSpace *colorSpace = [color colorSpace]; + const CGFloat ColorEpsilon = 1 / (2 * (CGFloat)255.0); + + if (color) { + if ([colorSpace isEqual:[NSColorSpace genericGrayColorSpace]] || [colorSpace isEqual:[NSColorSpace deviceGrayColorSpace]]) { + CGFloat white, alpha; + [color getWhite:&white alpha:&alpha]; + if (white < ColorEpsilon && (ignoreBlack || alpha < ColorEpsilon)) color = nil; + } else { + NSColor *rgbColor = nil; + if ([colorSpace isEqual:[NSColorSpace genericRGBColorSpace]] || [colorSpace isEqual:[NSColorSpace deviceRGBColorSpace]]) rgbColor = color; + if (!rgbColor) rgbColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace]; + if (rgbColor) { + CGFloat red, green, blue, alpha; + [rgbColor getRed:&red green:&green blue:&blue alpha:&alpha]; + if (red < ColorEpsilon && green < ColorEpsilon && blue < ColorEpsilon && (ignoreBlack || alpha < ColorEpsilon)) color = nil; + } + } + } + return color; +} + +static inline NSShadow *_shadowForShadowStyle(NSString *shadowStyle) +{ + NSShadow *shadow = nil; + NSUInteger shadowStyleLength = [shadowStyle length]; + NSRange openParenRange = [shadowStyle rangeOfString:@"("], closeParenRange = [shadowStyle rangeOfString:@")"], firstRange = NSMakeRange(NSNotFound, 0), secondRange = NSMakeRange(NSNotFound, 0), thirdRange = NSMakeRange(NSNotFound, 0), spaceRange; + if (openParenRange.length > 0 && closeParenRange.length > 0 && NSMaxRange(openParenRange) < closeParenRange.location) { + NSArray *components = [[shadowStyle substringWithRange:NSMakeRange(NSMaxRange(openParenRange), closeParenRange.location - NSMaxRange(openParenRange))] componentsSeparatedByString:@","]; + if ([components count] >= 3) { + CGFloat red = [[components objectAtIndex:0] floatValue] / 255, green = [[components objectAtIndex:1] floatValue] / 255, blue = [[components objectAtIndex:2] floatValue] / 255, alpha = ([components count] >= 4) ? [[components objectAtIndex:3] floatValue] / 255 : 1; + NSColor *shadowColor = [NSColor colorWithCalibratedRed:red green:green blue:blue alpha:alpha]; + NSSize shadowOffset; + CGFloat shadowBlurRadius; + firstRange = [shadowStyle rangeOfString:@"px"]; + if (firstRange.length > 0 && NSMaxRange(firstRange) < shadowStyleLength) secondRange = [shadowStyle rangeOfString:@"px" options:0 range:NSMakeRange(NSMaxRange(firstRange), shadowStyleLength - NSMaxRange(firstRange))]; + if (secondRange.length > 0 && NSMaxRange(secondRange) < shadowStyleLength) thirdRange = [shadowStyle rangeOfString:@"px" options:0 range:NSMakeRange(NSMaxRange(secondRange), shadowStyleLength - NSMaxRange(secondRange))]; + if (firstRange.location > 0 && firstRange.length > 0 && secondRange.length > 0 && thirdRange.length > 0) { + spaceRange = [shadowStyle rangeOfString:@" " options:NSBackwardsSearch range:NSMakeRange(0, firstRange.location)]; + if (spaceRange.length == 0) spaceRange = NSMakeRange(0, 0); + shadowOffset.width = [[shadowStyle substringWithRange:NSMakeRange(NSMaxRange(spaceRange), firstRange.location - NSMaxRange(spaceRange))] floatValue]; + spaceRange = [shadowStyle rangeOfString:@" " options:NSBackwardsSearch range:NSMakeRange(0, secondRange.location)]; + if (spaceRange.length == 0) spaceRange = NSMakeRange(0, 0); + shadowOffset.height = -[[shadowStyle substringWithRange:NSMakeRange(NSMaxRange(spaceRange), secondRange.location - NSMaxRange(spaceRange))] floatValue]; + spaceRange = [shadowStyle rangeOfString:@" " options:NSBackwardsSearch range:NSMakeRange(0, thirdRange.location)]; + if (spaceRange.length == 0) spaceRange = NSMakeRange(0, 0); + shadowBlurRadius = [[shadowStyle substringWithRange:NSMakeRange(NSMaxRange(spaceRange), thirdRange.location - NSMaxRange(spaceRange))] floatValue]; + shadow = [[[NSShadow alloc] init] autorelease]; + [shadow setShadowColor:shadowColor]; + [shadow setShadowOffset:shadowOffset]; + [shadow setShadowBlurRadius:shadowBlurRadius]; + } + } + } + return shadow; +} + +- (BOOL)_elementIsBlockLevel:(DOMElement *)element +{ + BOOL isBlockLevel = NO; + NSNumber *val = nil; + val = [_elementIsBlockLevel objectForKey:element]; + if (val) { + isBlockLevel = [val boolValue]; + } else { + NSString *displayVal = [self _stringForNode:element property:@"display"], *floatVal = [self _stringForNode:element property:@"float"]; + if (floatVal && ([@"left" isEqualToString:floatVal] || [@"right" isEqualToString:floatVal])) { + isBlockLevel = YES; + } else if (displayVal) { + isBlockLevel = ([@"block" isEqualToString:displayVal] || [@"list-item" isEqualToString:displayVal] || [displayVal hasPrefix:@"table"]); + } + [_elementIsBlockLevel setObject:[NSNumber numberWithBool:isBlockLevel] forKey:element]; + } + return isBlockLevel; +} + +- (BOOL)_elementHasOwnBackgroundColor:(DOMElement *)element +{ + // In the text system, text blocks (table elements) and documents (body elements) have their own background colors, which should not be inherited + if ([self _elementIsBlockLevel:element]) { + Element* coreElement = core(element); + NSString *displayVal = [self _stringForNode:element property:@"display"]; + if (coreElement->hasTagName(htmlTag) || coreElement->hasTagName(bodyTag) || [displayVal hasPrefix:@"table"]) + return YES; + } + return NO; +} + +- (DOMElement *)_blockLevelElementForNode:(DOMNode *)node +{ + DOMElement *element = (DOMElement *)node; + while (element && [element nodeType] != DOM_ELEMENT_NODE) + element = (DOMElement *)[element parentNode]; + if (element && ![self _elementIsBlockLevel:element]) + element = [self _blockLevelElementForNode:[element parentNode]]; + return element; +} + +- (NSColor *)_computedColorForNode:(DOMNode *)node property:(NSString *)key +{ + NSColor *result = nil; + BOOL inherit = YES, haveResult = NO, isColor = [@"color" isEqualToString:key], isBackgroundColor = [@"background-color" isEqualToString:key]; + DOMElement *element = (DOMElement *)node; + if (element && [element nodeType] == DOM_ELEMENT_NODE) { + DOMCSSStyleDeclaration *computedStyle, *specifiedStyle; + inherit = NO; + if (!haveResult && (computedStyle = [self _computedStyleForElement:element])) { + DOMCSSPrimitiveValue *computedValue = (DOMCSSPrimitiveValue *)[computedStyle getPropertyCSSValue:key]; + if (computedValue && [computedValue cssValueType] == DOM_CSS_PRIMITIVE_VALUE && [computedValue primitiveType] == DOM_CSS_RGBCOLOR) { + result = _colorForRGBColor([computedValue getRGBColorValue], isColor); + haveResult = YES; + } + } + if (!haveResult && (specifiedStyle = [self _specifiedStyleForElement:element])) { + DOMCSSPrimitiveValue *specifiedValue = (DOMCSSPrimitiveValue *)[specifiedStyle getPropertyCSSValue:key]; + if (specifiedValue) { + unsigned short valueType = [specifiedValue cssValueType]; + if (valueType == DOM_CSS_PRIMITIVE_VALUE && [specifiedValue primitiveType] == DOM_CSS_RGBCOLOR) { + result = _colorForRGBColor([specifiedValue getRGBColorValue], isColor); + haveResult = YES; + } else if (valueType == DOM_CSS_INHERIT) { + inherit = YES; + } + } + } + if (!result) { + if ((isColor && !haveResult) || (isBackgroundColor && ![self _elementHasOwnBackgroundColor:element])) inherit = YES; + } + } + if (!result && inherit) { + DOMNode *parentNode = [node parentNode]; + if (parentNode && !(isBackgroundColor && [parentNode nodeType] == DOM_ELEMENT_NODE && [self _elementHasOwnBackgroundColor:(DOMElement *)parentNode])) { + result = [self _colorForNode:parentNode property:key]; + } + } + return result; +} + +- (NSColor *)_colorForNode:(DOMNode *)node property:(NSString *)key +{ + NSColor *result = nil; + NSMutableDictionary *attributeDictionary = [_colorsForNodes objectForKey:node]; + if (!attributeDictionary) { + attributeDictionary = [[NSMutableDictionary alloc] init]; + [_colorsForNodes setObject:attributeDictionary forKey:node]; + [attributeDictionary release]; + } + result = [attributeDictionary objectForKey:key]; + if (result) { + if ([[NSColor clearColor] isEqual:result]) result = nil; + } else { + result = [self _computedColorForNode:node property:key]; + [attributeDictionary setObject:(result ? result : [NSColor clearColor]) forKey:key]; + } + return result; +} + +- (NSDictionary *)_computedAttributesForElement:(DOMElement *)element +{ + DOMElement *blockElement = [self _blockLevelElementForNode:element]; + NSMutableDictionary *attrs = [NSMutableDictionary dictionary]; + NSFontManager *fontManager = [NSFontManager sharedFontManager]; + NSString *fontEffect = [self _stringForNode:element property:@"font-effect"], *textDecoration = [self _stringForNode:element property:@"text-decoration"], *verticalAlign = [self _stringForNode:element property:@"vertical-align"], *textShadow = [self _stringForNode:element property:@"text-shadow"]; + CGFloat fontSize = 0, baselineOffset = 0, kerning = 0; + NSFont *font = nil, *actualFont = [element _font]; + NSColor *foregroundColor = [self _colorForNode:element property:@"color"], *backgroundColor = [self _colorForNode:element property:@"background-color"]; + + if (![self _getFloat:&fontSize forNode:element property:@"font-size"] || fontSize <= 0.0) fontSize = _defaultFontSize; + fontSize *= _textSizeMultiplier; + if (fontSize < _minimumFontSize) fontSize = _minimumFontSize; + if (fabs(floor(2.0 * fontSize + 0.5) / 2.0 - fontSize) < 0.05) { + fontSize = (CGFloat)floor(2.0 * fontSize + 0.5) / 2; + } else if (fabs(floor(10.0 * fontSize + 0.5) / 10.0 - fontSize) < 0.005) { + fontSize = (CGFloat)floor(10.0 * fontSize + 0.5) / 10; + } + if (fontSize <= 0.0) fontSize = 12; + + if (actualFont) font = [fontManager convertFont:actualFont toSize:fontSize]; + if (!font) { + NSString *fontName = [[self _stringForNode:element property:@"font-family"] capitalizedString], *fontStyle = [self _stringForNode:element property:@"font-style"], *fontWeight = [self _stringForNode:element property:@"font-weight"], *fontVariant = [self _stringForNode:element property:@"font-variant"]; + + if (!fontName) fontName = _standardFontFamily; + if (fontName) font = _fontForNameAndSize(fontName, fontSize, _fontCache); + if (!font) font = [NSFont fontWithName:@"Times" size:fontSize]; + if ([@"italic" isEqualToString:fontStyle] || [@"oblique" isEqualToString:fontStyle]) { + NSFont *originalFont = font; + font = [fontManager convertFont:font toHaveTrait:NSItalicFontMask]; + if (!font) font = originalFont; + } + if ([fontWeight hasPrefix:@"bold"] || [fontWeight integerValue] >= 700) { + // ??? handle weight properly using NSFontManager + NSFont *originalFont = font; + font = [fontManager convertFont:font toHaveTrait:NSBoldFontMask]; + if (!font) font = originalFont; + } + if ([@"small-caps" isEqualToString:fontVariant]) { + // ??? synthesize small-caps if [font isEqual:originalFont] + NSFont *originalFont = font; + font = [fontManager convertFont:font toHaveTrait:NSSmallCapsFontMask]; + if (!font) font = originalFont; + } + } + if (font) [attrs setObject:font forKey:NSFontAttributeName]; + if (foregroundColor) [attrs setObject:foregroundColor forKey:NSForegroundColorAttributeName]; + if (backgroundColor && ![self _elementHasOwnBackgroundColor:element]) [attrs setObject:backgroundColor forKey:NSBackgroundColorAttributeName]; + if (fontEffect) { + if ([fontEffect rangeOfString:@"outline"].location != NSNotFound) [attrs setObject:[NSNumber numberWithDouble:3.0] forKey:NSStrokeWidthAttributeName]; + if ([fontEffect rangeOfString:@"emboss"].location != NSNotFound) [attrs setObject:[[[NSShadow alloc] init] autorelease] forKey:NSShadowAttributeName]; + } + if (textDecoration && [textDecoration length] > 4) { + if ([textDecoration rangeOfString:@"underline"].location != NSNotFound) [attrs setObject:[NSNumber numberWithInteger:NSUnderlineStyleSingle] forKey:NSUnderlineStyleAttributeName]; + if ([textDecoration rangeOfString:@"line-through"].location != NSNotFound) [attrs setObject:[NSNumber numberWithInteger:NSUnderlineStyleSingle] forKey:NSStrikethroughStyleAttributeName]; + } + if (verticalAlign) { + if ([verticalAlign rangeOfString:@"super"].location != NSNotFound) [attrs setObject:[NSNumber numberWithInteger:1] forKey:NSSuperscriptAttributeName]; + if ([verticalAlign rangeOfString:@"sub"].location != NSNotFound) [attrs setObject:[NSNumber numberWithInteger:-1] forKey:NSSuperscriptAttributeName]; + } + if ([self _getFloat:&baselineOffset forNode:element property:@"vertical-align"]) [attrs setObject:[NSNumber numberWithDouble:baselineOffset] forKey:NSBaselineOffsetAttributeName]; + if ([self _getFloat:&kerning forNode:element property:@"letter-spacing"]) [attrs setObject:[NSNumber numberWithDouble:kerning] forKey:NSKernAttributeName]; + if (textShadow && [textShadow length] > 4) { + NSShadow *shadow = _shadowForShadowStyle(textShadow); + if (shadow) [attrs setObject:shadow forKey:NSShadowAttributeName]; + } + if (element != blockElement && [_writingDirectionArray count] > 0) [attrs setObject:[NSArray arrayWithArray:_writingDirectionArray] forKey:NSWritingDirectionAttributeName]; + + if (blockElement) { + NSMutableParagraphStyle *paragraphStyle = [[[self class] defaultParagraphStyle] mutableCopy]; + NSString *blockTag = [blockElement tagName]; + BOOL isParagraph = ([@"P" isEqualToString:blockTag] || [@"LI" isEqualToString:blockTag] || ([blockTag hasPrefix:@"H"] && 2 == [blockTag length])); + NSString *textAlign = [self _stringForNode:blockElement property:@"text-align"], *direction = [self _stringForNode:blockElement property:@"direction"]; + CGFloat leftMargin = 0, rightMargin = 0, bottomMargin = 0, textIndent = 0, lineHeight = 0; + if (textAlign) { + // WebKit can return -khtml-left, -khtml-right, -khtml-center + if ([textAlign hasSuffix:@"left"]) [paragraphStyle setAlignment:NSLeftTextAlignment]; + else if ([textAlign hasSuffix:@"right"]) [paragraphStyle setAlignment:NSRightTextAlignment]; + else if ([textAlign hasSuffix:@"center"]) [paragraphStyle setAlignment:NSCenterTextAlignment]; + else if ([textAlign hasSuffix:@"justify"]) [paragraphStyle setAlignment:NSJustifiedTextAlignment]; + } + if (direction) { + if ([direction isEqualToString:@"ltr"]) [paragraphStyle setBaseWritingDirection:NSWritingDirectionLeftToRight]; + else if ([direction isEqualToString:@"rtl"]) [paragraphStyle setBaseWritingDirection:NSWritingDirectionRightToLeft]; + } + if ([blockTag hasPrefix:@"H"] && 2 == [blockTag length]) { + NSInteger headerLevel = [blockTag characterAtIndex:1] - '0'; + if (1 <= headerLevel && headerLevel <= 6) [paragraphStyle setHeaderLevel:headerLevel]; + } + if (isParagraph) { + //if ([self _getFloat:&topMargin forNode:blockElement property:@"margin-top"] && topMargin > 0.0) [paragraphStyle setParagraphSpacingBefore:topMargin]; + if ([self _getFloat:&leftMargin forNode:blockElement property:@"margin-left"] && leftMargin > 0.0) [paragraphStyle setHeadIndent:leftMargin]; + if ([self _getFloat:&textIndent forNode:blockElement property:@"text-indent"]) [paragraphStyle setFirstLineHeadIndent:[paragraphStyle headIndent] + textIndent]; + if ([self _getFloat:&rightMargin forNode:blockElement property:@"margin-right"] && rightMargin > 0.0) [paragraphStyle setTailIndent:-rightMargin]; + if ([self _getFloat:&bottomMargin forNode:blockElement property:@"margin-bottom"] && bottomMargin > 0.0) [paragraphStyle setParagraphSpacing:bottomMargin]; + } + if (_webViewTextSizeMultiplier > 0.0 && [self _getFloat:&lineHeight forNode:element property:@"line-height"] && lineHeight > 0.0) { + [paragraphStyle setMinimumLineHeight:lineHeight / _webViewTextSizeMultiplier]; + } + if ([_textLists count] > 0) [paragraphStyle setTextLists:_textLists]; + if ([_textBlocks count] > 0) [paragraphStyle setTextBlocks:_textBlocks]; + [attrs setObject:paragraphStyle forKey:NSParagraphStyleAttributeName]; + [paragraphStyle release]; + } + return attrs; +} + +- (NSDictionary *)_attributesForElement:(DOMElement *)element +{ + NSDictionary *result; + if (element) { + result = [_attributesForElements objectForKey:element]; + if (!result) { + result = [self _computedAttributesForElement:element]; + [_attributesForElements setObject:result forKey:element]; + } + } else { + result = [NSDictionary dictionary]; + } + return result; + +} + +- (void)_newParagraphForElement:(DOMElement *)element tag:(NSString *)tag allowEmpty:(BOOL)flag suppressTrailingSpace:(BOOL)suppress +{ + NSUInteger textLength = [_attrStr length]; + unichar lastChar = (textLength > 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : '\n'; + NSRange rangeToReplace = (suppress && _flags.isSoft && (lastChar == ' ' || lastChar == NSLineSeparatorCharacter)) ? NSMakeRange(textLength - 1, 1) : NSMakeRange(textLength, 0); + BOOL needBreak = (flag || lastChar != '\n'); + if (needBreak) { + NSString *string = (([@"BODY" isEqualToString:tag] || [@"HTML" isEqualToString:tag]) ? @"" : @"\n"); + [_writingDirectionArray removeAllObjects]; + [_attrStr replaceCharactersInRange:rangeToReplace withString:string]; + if (rangeToReplace.location < _domRangeStartIndex) _domRangeStartIndex += [string length] - rangeToReplace.length; + rangeToReplace.length = [string length]; + if (!_flags.isIndexing) { + NSDictionary *attrs = [self _attributesForElement:element]; + if (!_flags.isTesting && rangeToReplace.length > 0) [_attrStr setAttributes:attrs range:rangeToReplace]; + } + _flags.isSoft = YES; + } +} + +- (void)_newLineForElement:(DOMElement *)element +{ + unichar c = NSLineSeparatorCharacter; + NSString *string = [[NSString alloc] initWithCharacters:&c length:1]; + NSUInteger textLength = [_attrStr length]; + NSRange rangeToReplace = NSMakeRange(textLength, 0); + [_attrStr replaceCharactersInRange:rangeToReplace withString:string]; + rangeToReplace.length = [string length]; + if (rangeToReplace.location < _domRangeStartIndex) _domRangeStartIndex += rangeToReplace.length; + if (!_flags.isIndexing) { + NSDictionary *attrs = [self _attributesForElement:element]; + if (!_flags.isTesting && rangeToReplace.length > 0) [_attrStr setAttributes:attrs range:rangeToReplace]; + } + [string release]; + _flags.isSoft = YES; +} + +- (void)_newTabForElement:(DOMElement *)element +{ + NSString *string = @"\t"; + NSUInteger textLength = [_attrStr length]; + unichar lastChar = (textLength > 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : '\n'; + NSRange rangeToReplace = (_flags.isSoft && lastChar == ' ') ? NSMakeRange(textLength - 1, 1) : NSMakeRange(textLength, 0); + [_attrStr replaceCharactersInRange:rangeToReplace withString:string]; + rangeToReplace.length = [string length]; + if (rangeToReplace.location < _domRangeStartIndex) _domRangeStartIndex += rangeToReplace.length; + if (!_flags.isIndexing) { + NSDictionary *attrs = [self _attributesForElement:element]; + if (!_flags.isTesting && rangeToReplace.length > 0) [_attrStr setAttributes:attrs range:rangeToReplace]; + } + [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 +{ + BOOL retval = NO, notFound = NO; + NSFileWrapper *fileWrapper = nil; + static NSImage *missingImage = nil; + Frame* frame = core([element ownerDocument])->frame(); + DocumentLoader *dataSource = frame->loader()->frameHasLoaded() ? frame->loader()->documentLoader() : 0; + BOOL ignoreOrientation = YES; + + if (_flags.isIndexing) return NO; + if ([url isFileURL]) { + NSString *path = [[url path] stringByStandardizingPath]; + if (path) fileWrapper = [[[NSFileWrapper alloc] initWithPath:path] autorelease]; + } + if (!fileWrapper) { + RefPtr<ArchiveResource> resource = dataSource->subresource(url); + if (!resource) resource = dataSource->subresource(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()]]; + } + } + if (!fileWrapper && !notFound) { + fileWrapper = fileWrapperForURL(dataSource, url); + if (flag && fileWrapper && [[[[fileWrapper preferredFilename] pathExtension] lowercaseString] hasPrefix:@"htm"]) notFound = YES; + if (notFound) fileWrapper = nil; + } + if (!fileWrapper && !notFound) { + fileWrapper = fileWrapperForURL(_dataSource, url); + if (flag && fileWrapper && [[[[fileWrapper preferredFilename] pathExtension] lowercaseString] hasPrefix:@"htm"]) notFound = YES; + if (notFound) fileWrapper = nil; + } + if (fileWrapper || flag) { + NSUInteger textLength = [_attrStr length]; + NSTextAttachment *attachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper]; + NSTextAttachmentCell *cell; + NSString *string = [[NSString alloc] initWithFormat:(needsParagraph ? @"%C\n" : @"%C"), NSAttachmentCharacter]; + NSRange rangeToReplace = NSMakeRange(textLength, 0); + NSDictionary *attrs; + if (fileWrapper) { + if (ignoreOrientation) [attachment setIgnoresOrientation:YES]; + } else { + cell = [[NSTextAttachmentCell alloc] initImageCell:missingImage]; + [attachment setAttachmentCell:cell]; + [cell release]; + } + [_attrStr replaceCharactersInRange:rangeToReplace withString:string]; + rangeToReplace.length = [string length]; + if (rangeToReplace.location < _domRangeStartIndex) _domRangeStartIndex += rangeToReplace.length; + attrs = [self _attributesForElement:element]; + if (!_flags.isTesting && rangeToReplace.length > 0) { + [_attrStr setAttributes:attrs range:rangeToReplace]; + rangeToReplace.length = 1; + [_attrStr addAttribute:NSAttachmentAttributeName value:attachment range:rangeToReplace]; + } + [string release]; + [attachment release]; + _flags.isSoft = NO; + retval = YES; + } + return retval; +} + +- (void)_addQuoteForElement:(DOMElement *)element opening:(BOOL)opening level:(NSInteger)level +{ + unichar c = ((level % 2) == 0) ? (opening ? 0x201c : 0x201d) : (opening ? 0x2018 : 0x2019); + NSString *string = [[NSString alloc] initWithCharacters:&c length:1]; + NSUInteger textLength = [_attrStr length]; + NSRange rangeToReplace = NSMakeRange(textLength, 0); + [_attrStr replaceCharactersInRange:rangeToReplace withString:string]; + rangeToReplace.length = [string length]; + if (rangeToReplace.location < _domRangeStartIndex) _domRangeStartIndex += rangeToReplace.length; + if (!_flags.isIndexing) { + NSDictionary *attrs = [self _attributesForElement:element]; + if (!_flags.isTesting && rangeToReplace.length > 0) [_attrStr setAttributes:attrs range:rangeToReplace]; + } + [string release]; + _flags.isSoft = NO; +} + +- (void)_addValue:(NSString *)value forElement:(DOMElement *)element +{ + NSUInteger textLength = [_attrStr length], valueLength = [value length]; + NSRange rangeToReplace = NSMakeRange(textLength, 0); + if (valueLength > 0) { + [_attrStr replaceCharactersInRange:rangeToReplace withString:value]; + rangeToReplace.length = valueLength; + if (rangeToReplace.location < _domRangeStartIndex) _domRangeStartIndex += rangeToReplace.length; + if (!_flags.isIndexing) { + NSDictionary *attrs = [self _attributesForElement:element]; + if (!_flags.isTesting && rangeToReplace.length > 0) [_attrStr setAttributes:attrs range:rangeToReplace]; + } + _flags.isSoft = NO; + } +} + +- (void)_fillInBlock:(NSTextBlock *)block forElement:(DOMElement *)element backgroundColor:(NSColor *)backgroundColor extraMargin:(CGFloat)extraMargin extraPadding:(CGFloat)extraPadding isTable:(BOOL)isTable +{ + CGFloat val = 0; + NSColor *color = nil; + BOOL isTableCellElement = [element isKindOfClass:[DOMHTMLTableCellElement class]]; + NSString *width = isTableCellElement ? [(DOMHTMLTableCellElement *)element width] : [element getAttribute:@"width"]; + + if ((width && [width length] > 0) || !isTable) { + if ([self _getFloat:&val forNode:element property:@"width"]) [block setValue:val type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockWidth]; + } + + if ([self _getFloat:&val forNode:element property:@"min-width"]) [block setValue:val type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMinimumWidth]; + if ([self _getFloat:&val forNode:element property:@"max-width"]) [block setValue:val type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMaximumWidth]; + if ([self _getFloat:&val forNode:element property:@"min-height"]) [block setValue:val type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMinimumHeight]; + if ([self _getFloat:&val forNode:element property:@"max-height"]) [block setValue:val type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMaximumHeight]; + + if ([self _getFloat:&val forNode:element property:@"padding-left"]) [block setWidth:val + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinXEdge]; else [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinXEdge]; + if ([self _getFloat:&val forNode:element property:@"padding-top"]) [block setWidth:val + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinYEdge]; else [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinYEdge]; + if ([self _getFloat:&val forNode:element property:@"padding-right"]) [block setWidth:val + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxXEdge]; else [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxXEdge]; + if ([self _getFloat:&val forNode:element property:@"padding-bottom"]) [block setWidth:val + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxYEdge]; else [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxYEdge]; + + if ([self _getFloat:&val forNode:element property:@"border-left-width"]) [block setWidth:val type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMinXEdge]; + if ([self _getFloat:&val forNode:element property:@"border-top-width"]) [block setWidth:val type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMinYEdge]; + if ([self _getFloat:&val forNode:element property:@"border-right-width"]) [block setWidth:val type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMaxXEdge]; + if ([self _getFloat:&val forNode:element property:@"border-bottom-width"]) [block setWidth:val type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMaxYEdge]; + + if ([self _getFloat:&val forNode:element property:@"margin-left"]) [block setWidth:val + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinXEdge]; else [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinXEdge]; + if ([self _getFloat:&val forNode:element property:@"margin-top"]) [block setWidth:val + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinYEdge]; else [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinYEdge]; + if ([self _getFloat:&val forNode:element property:@"margin-right"]) [block setWidth:val + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxXEdge]; else [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxXEdge]; + if ([self _getFloat:&val forNode:element property:@"margin-bottom"]) [block setWidth:val + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxYEdge]; else [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxYEdge]; + + if ((color = [self _colorForNode:element property:@"background-color"])) [block setBackgroundColor:color]; + if (!color && backgroundColor) [block setBackgroundColor:backgroundColor]; + if ((color = [self _colorForNode:element property:@"border-left-color"])) [block setBorderColor:color forEdge:NSMinXEdge]; + if ((color = [self _colorForNode:element property:@"border-top-color"])) [block setBorderColor:color forEdge:NSMinYEdge]; + if ((color = [self _colorForNode:element property:@"border-right-color"])) [block setBorderColor:color forEdge:NSMaxXEdge]; + if ((color = [self _colorForNode:element property:@"border-bottom-color"])) [block setBorderColor:color forEdge:NSMaxYEdge]; +} + +static inline BOOL read2DigitNumber(const char **pp, int8_t *outval) +{ + BOOL result = NO; + char c1 = *(*pp)++, c2; + if (isASCIIDigit(c1)) { + c2 = *(*pp)++; + if (isASCIIDigit(c2)) { + *outval = 10 * (c1 - '0') + (c2 - '0'); + result = YES; + } + } + return result; +} + +static inline NSDate *_dateForString(NSString *string) +{ + CFGregorianDate date; + const char *p = [string UTF8String]; + int8_t secval = 0; + BOOL wellFormed = YES; + + date.year = 0; + while (*p && isASCIIDigit(*p)) date.year = 10 * date.year + *p++ - '0'; + if (*p++ != '-') wellFormed = NO; + if (!wellFormed || !read2DigitNumber(&p, &date.month) || *p++ != '-') wellFormed = NO; + if (!wellFormed || !read2DigitNumber(&p, &date.day) || *p++ != 'T') wellFormed = NO; + if (!wellFormed || !read2DigitNumber(&p, &date.hour) || *p++ != ':') wellFormed = NO; + if (!wellFormed || !read2DigitNumber(&p, &date.minute) || *p++ != ':') wellFormed = NO; + if (!wellFormed || !read2DigitNumber(&p, &secval) || *p++ != 'Z') wellFormed = NO; + if (wellFormed) date.second = secval; + return wellFormed ? [(NSDate *)CFDateCreate(NULL, CFGregorianDateGetAbsoluteTime(date, NULL)) autorelease] : nil; +} + +static NSInteger _colCompare(id block1, id block2, void *) +{ + NSInteger col1 = [(NSTextTableBlock *)block1 startingColumn], col2 = [(NSTextTableBlock *)block2 startingColumn]; + return ((col1 < col2) ? NSOrderedAscending : ((col1 == col2) ? NSOrderedSame : NSOrderedDescending)); +} + +- (BOOL)_enterElement:(DOMElement *)element tag:(NSString *)tag display:(NSString *)displayVal +{ + if (!displayVal || !([@"none" isEqualToString:displayVal] || [@"table-column" isEqualToString:displayVal] || [@"table-column-group" isEqualToString:displayVal])) { + if ([self _elementIsBlockLevel:element] && ![@"BR" isEqualToString:tag] && !([@"table-cell" isEqualToString:displayVal] && [_textTables count] == 0) + && !([_textLists count] > 0 && [@"block" isEqualToString:displayVal] && ![@"LI" isEqualToString:tag] && ![@"UL" isEqualToString:tag] && ![@"OL" isEqualToString:tag])) + [self _newParagraphForElement:element tag:tag allowEmpty:NO suppressTrailingSpace:YES]; + return YES; + } + return NO; +} + +- (void)_addTableForElement:(DOMElement *)tableElement +{ + NSTextTable *table = [[NSTextTable alloc] init]; + CGFloat cellSpacingVal = 1, cellPaddingVal = 1; + [table setNumberOfColumns:1]; + [table setLayoutAlgorithm:NSTextTableAutomaticLayoutAlgorithm]; + [table setCollapsesBorders:NO]; + [table setHidesEmptyCells:NO]; + if (tableElement) { + NSString *borderCollapse = [self _stringForNode:tableElement property:@"border-collapse"], *emptyCells = [self _stringForNode:tableElement property:@"empty-cells"], *tableLayout = [self _stringForNode:tableElement property:@"table-layout"]; + if ([tableElement respondsToSelector:@selector(cellSpacing)]) { + NSString *cellSpacing = [(DOMHTMLTableElement *)tableElement cellSpacing]; + if (cellSpacing && [cellSpacing length] > 0 && ![cellSpacing hasSuffix:@"%"]) cellSpacingVal = [cellSpacing floatValue]; + } + if ([tableElement respondsToSelector:@selector(cellPadding)]) { + NSString *cellPadding = [(DOMHTMLTableElement *)tableElement cellPadding]; + if (cellPadding && [cellPadding length] > 0 && ![cellPadding hasSuffix:@"%"]) cellPaddingVal = [cellPadding floatValue]; + } + [self _fillInBlock:table forElement:tableElement backgroundColor:nil extraMargin:0 extraPadding:0 isTable:YES]; + if ([@"collapse" isEqualToString:borderCollapse]) { + [table setCollapsesBorders:YES]; + cellSpacingVal = 0; + } + if ([@"hide" isEqualToString:emptyCells]) [table setHidesEmptyCells:YES]; + if ([@"fixed" isEqualToString:tableLayout]) [table setLayoutAlgorithm:NSTextTableFixedLayoutAlgorithm]; + } + [_textTables addObject:table]; + [_textTableSpacings addObject:[NSNumber numberWithDouble:cellSpacingVal]]; + [_textTablePaddings addObject:[NSNumber numberWithDouble:cellPaddingVal]]; + [_textTableRows addObject:[NSNumber numberWithInteger:0]]; + [_textTableRowArrays addObject:[NSMutableArray array]]; + [table release]; +} + +- (void)_addTableCellForElement:(DOMElement *)tableCellElement +{ + NSTextTable *table = [_textTables lastObject]; + NSInteger rowNumber = [[_textTableRows lastObject] integerValue], columnNumber = 0, rowSpan = 1, colSpan = 1; + NSMutableArray *rowArray = [_textTableRowArrays lastObject]; + NSUInteger i, count = [rowArray count]; + NSColor *color = ([_textTableRowBackgroundColors count] > 0) ? [_textTableRowBackgroundColors lastObject] : nil; + NSTextTableBlock *block, *previousBlock; + CGFloat cellSpacingVal = [[_textTableSpacings lastObject] floatValue]; + if ([color isEqual:[NSColor clearColor]]) color = nil; + for (i = 0; i < count; i++) { + previousBlock = [rowArray objectAtIndex:i]; + if (columnNumber >= [previousBlock startingColumn] && columnNumber < [previousBlock startingColumn] + [previousBlock columnSpan]) columnNumber = [previousBlock startingColumn] + [previousBlock columnSpan]; + } + if (tableCellElement) { + if ([tableCellElement respondsToSelector:@selector(rowSpan)]) { + rowSpan = [(DOMHTMLTableCellElement *)tableCellElement rowSpan]; + if (rowSpan < 1) rowSpan = 1; + } + if ([tableCellElement respondsToSelector:@selector(colSpan)]) { + colSpan = [(DOMHTMLTableCellElement *)tableCellElement colSpan]; + if (colSpan < 1) colSpan = 1; + } + } + block = [[NSTextTableBlock alloc] initWithTable:table startingRow:rowNumber rowSpan:rowSpan startingColumn:columnNumber columnSpan:colSpan]; + if (tableCellElement) { + NSString *verticalAlign = [self _stringForNode:tableCellElement property:@"vertical-align"]; + [self _fillInBlock:block forElement:tableCellElement backgroundColor:color extraMargin:cellSpacingVal / 2 extraPadding:0 isTable:NO]; + if ([@"middle" isEqualToString:verticalAlign]) [block setVerticalAlignment:NSTextBlockMiddleAlignment]; + else if ([@"bottom" isEqualToString:verticalAlign]) [block setVerticalAlignment:NSTextBlockBottomAlignment]; + else if ([@"baseline" isEqualToString:verticalAlign]) [block setVerticalAlignment:NSTextBlockBaselineAlignment]; + else if ([@"top" isEqualToString:verticalAlign]) [block setVerticalAlignment:NSTextBlockTopAlignment]; + } + [_textBlocks addObject:block]; + [rowArray addObject:block]; + [rowArray sortUsingFunction:_colCompare context:NULL]; + [block release]; +} + +- (BOOL)_processElement:(DOMElement *)element tag:(NSString *)tag display:(NSString *)displayVal depth:(NSInteger)depth +{ + BOOL retval = YES, isBlockLevel = [self _elementIsBlockLevel:element]; + if (isBlockLevel) { + [_writingDirectionArray removeAllObjects]; + } else { + NSString *bidi = [self _stringForNode:element property:@"unicode-bidi"]; + if (bidi && [bidi isEqualToString:@"embed"]) { + NSUInteger val = NSTextWritingDirectionEmbedding; + NSString *direction = [self _stringForNode:element property:@"direction"]; + if ([direction isEqualToString:@"rtl"]) val |= NSWritingDirectionRightToLeft; + [_writingDirectionArray addObject:[NSNumber numberWithUnsignedInteger:val]]; + } else if (bidi && [bidi isEqualToString:@"bidi-override"]) { + NSUInteger val = NSTextWritingDirectionOverride; + NSString *direction = [self _stringForNode:element property:@"direction"]; + if ([direction isEqualToString:@"rtl"]) val |= NSWritingDirectionRightToLeft; + [_writingDirectionArray addObject:[NSNumber numberWithUnsignedInteger:val]]; + } + } + if ([@"table" isEqualToString:displayVal] || ([_textTables count] == 0 && [@"table-row-group" isEqualToString:displayVal])) { + DOMElement *tableElement = element; + if ([@"table-row-group" isEqualToString:displayVal]) { + // If we are starting in medias res, the first thing we see may be the tbody, so go up to the table + tableElement = [self _blockLevelElementForNode:[element parentNode]]; + if (![@"table" isEqualToString:[self _stringForNode:tableElement property:@"display"]]) tableElement = element; + } + while ([_textTables count] > [_textBlocks count]) { + [self _addTableCellForElement:nil]; + } + [self _addTableForElement:tableElement]; + } else if ([@"table-footer-group" isEqualToString:displayVal] && [_textTables count] > 0) { + [_textTableFooters setObject:element forKey:[NSValue valueWithNonretainedObject:[_textTables lastObject]]]; + retval = NO; + } else if ([@"table-row" isEqualToString:displayVal] && [_textTables count] > 0) { + NSColor *color = [self _colorForNode:element property:@"background-color"]; + if (!color) color = [NSColor clearColor]; + [_textTableRowBackgroundColors addObject:color]; + } else if ([@"table-cell" isEqualToString:displayVal]) { + while ([_textTables count] < [_textBlocks count] + 1) { + [self _addTableForElement:nil]; + } + [self _addTableCellForElement:element]; + } else if ([@"IMG" isEqualToString:tag]) { + NSString *urlString = [element getAttribute:@"src"]; + if (urlString && [urlString length] > 0) { + NSURL *url = core([element ownerDocument])->completeURL(stripLeadingAndTrailingHTMLSpaces(urlString)); + if (!url) url = [NSURL _web_URLWithString:[urlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] relativeToURL:_baseURL]; + if (url) [self _addAttachmentForElement:element URL:url needsParagraph:isBlockLevel usePlaceholder:YES]; + } + retval = NO; + } else if ([@"OBJECT" isEqualToString:tag]) { + NSString *baseString = [element getAttribute:@"codebase"], *urlString = [element getAttribute:@"data"], *declareString = [element getAttribute:@"declare"]; + if (urlString && [urlString length] > 0 && ![@"true" isEqualToString:declareString]) { + NSURL *baseURL = nil, *url = nil; + if (baseString && [baseString length] > 0) { + baseURL = core([element ownerDocument])->completeURL(stripLeadingAndTrailingHTMLSpaces(baseString)); + if (!baseURL) baseURL = [NSURL _web_URLWithString:[baseString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] relativeToURL:_baseURL]; + } + if (baseURL) url = [NSURL _web_URLWithString:[urlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] relativeToURL:baseURL]; + if (!url) url =core([element ownerDocument])->completeURL(stripLeadingAndTrailingHTMLSpaces(urlString)); + if (!url) url = [NSURL _web_URLWithString:[urlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] relativeToURL:_baseURL]; + if (url) retval = ![self _addAttachmentForElement:element URL:url needsParagraph:isBlockLevel usePlaceholder:NO]; + } + } else if ([@"FRAME" isEqualToString:tag]) { + if ([element respondsToSelector:@selector(contentDocument)]) { + DOMDocument *contentDocument = [(DOMHTMLFrameElement *)element contentDocument]; + if (contentDocument) [self _traverseNode:contentDocument depth:depth + 1 embedded:YES]; + } + retval = NO; + } else if ([@"IFRAME" isEqualToString:tag]) { + if ([element respondsToSelector:@selector(contentDocument)]) { + DOMDocument *contentDocument = [(DOMHTMLIFrameElement *)element contentDocument]; + if (contentDocument) { + [self _traverseNode:contentDocument depth:depth + 1 embedded:YES]; + retval = NO; + } + } + } else if ([@"BR" isEqualToString:tag]) { + DOMElement *blockElement = [self _blockLevelElementForNode:[element parentNode]]; + NSString *breakClass = [element getAttribute:@"class"], *blockTag = [blockElement tagName]; + BOOL isExtraBreak = [@"Apple-interchange-newline" isEqualToString:breakClass], blockElementIsParagraph = ([@"P" isEqualToString:blockTag] || [@"LI" isEqualToString:blockTag] || ([blockTag hasPrefix:@"H"] && 2 == [blockTag length])); + if (isExtraBreak) { + _flags.hasTrailingNewline = YES; + } else { + if (blockElement && blockElementIsParagraph) { + [self _newLineForElement:element]; + } else { + [self _newParagraphForElement:element tag:tag allowEmpty:YES suppressTrailingSpace:NO]; + } + } + } else if ([@"UL" isEqualToString:tag]) { + NSTextList *list; + NSString *listStyleType = [self _stringForNode:element property:@"list-style-type"]; + if (!listStyleType || [listStyleType length] == 0) listStyleType = @"disc"; + list = [[NSTextList alloc] initWithMarkerFormat:[NSString stringWithFormat:@"{%@}", listStyleType] options:0]; + [_textLists addObject:list]; + [list release]; + } else if ([@"OL" isEqualToString:tag]) { + NSTextList *list; + NSString *listStyleType = [self _stringForNode:element property:@"list-style-type"]; + if (!listStyleType || [listStyleType length] == 0) listStyleType = @"decimal"; + list = [[NSTextList alloc] initWithMarkerFormat:[NSString stringWithFormat:@"{%@}.", listStyleType] options:0]; + if ([element respondsToSelector:@selector(start)]) { + NSInteger startingItemNumber = [(DOMHTMLOListElement *)element start]; + [list setStartingItemNumber:startingItemNumber]; + } + [_textLists addObject:list]; + [list release]; + } else if ([@"Q" isEqualToString:tag]) { + [self _addQuoteForElement:element opening:YES level:_quoteLevel++]; + } else if ([@"INPUT" isEqualToString:tag]) { + if ([element respondsToSelector:@selector(type)] && [element respondsToSelector:@selector(value)] && [@"text" compare:[(DOMHTMLInputElement *)element type] options:NSCaseInsensitiveSearch] == NSOrderedSame) { + NSString *value = [(DOMHTMLInputElement *)element value]; + if (value && [value length] > 0) [self _addValue:value forElement:element]; + } + } else if ([@"TEXTAREA" isEqualToString:tag]) { + if ([element respondsToSelector:@selector(value)]) { + NSString *value = [(DOMHTMLTextAreaElement *)element value]; + if (value && [value length] > 0) [self _addValue:value forElement:element]; + } + retval = NO; + } + return retval; +} + +- (void)_addMarkersToList:(NSTextList *)list range:(NSRange)range +{ + NSInteger itemNum = [list startingItemNumber]; + NSString *string = [_attrStr string], *stringToInsert; + NSDictionary *attrsToInsert = nil; + NSFont *font; + NSParagraphStyle *paragraphStyle; + NSMutableParagraphStyle *newStyle; + NSTextTab *tab = nil, *tabToRemove; + NSRange paragraphRange, styleRange; + NSUInteger textLength = [_attrStr length], listIndex, idx, insertLength, i, count; + NSArray *textLists; + CGFloat markerLocation, listLocation, pointSize; + + if (range.length == 0 || range.location >= textLength) return; + if (NSMaxRange(range) > textLength) range.length = textLength - range.location; + paragraphStyle = [_attrStr attribute:NSParagraphStyleAttributeName atIndex:range.location effectiveRange:NULL]; + if (paragraphStyle) { + textLists = [paragraphStyle textLists]; + listIndex = [textLists indexOfObject:list]; + if (textLists && listIndex != NSNotFound) { + for (idx = range.location; idx < NSMaxRange(range);) { + paragraphRange = [string paragraphRangeForRange:NSMakeRange(idx, 0)]; + paragraphStyle = [_attrStr attribute:NSParagraphStyleAttributeName atIndex:idx effectiveRange:&styleRange]; + font = [_attrStr attribute:NSFontAttributeName atIndex:idx effectiveRange:NULL]; + pointSize = font ? [font pointSize] : 12; + if ([[paragraphStyle textLists] count] == listIndex + 1) { + stringToInsert = [NSString stringWithFormat:@"\t%@\t", [list markerForItemNumber:itemNum++]]; + insertLength = [stringToInsert length]; + if (!_flags.isIndexing && !_flags.isTesting) attrsToInsert = [NSTextList _standardMarkerAttributesForAttributes:[_attrStr attributesAtIndex:paragraphRange.location effectiveRange:NULL]]; + [_attrStr replaceCharactersInRange:NSMakeRange(paragraphRange.location, 0) withString:stringToInsert]; + if (!_flags.isIndexing && !_flags.isTesting) [_attrStr setAttributes:attrsToInsert range:NSMakeRange(paragraphRange.location, insertLength)]; + range.length += insertLength; + paragraphRange.length += insertLength; + if (paragraphRange.location < _domRangeStartIndex) _domRangeStartIndex += insertLength; + + newStyle = [paragraphStyle mutableCopy]; + listLocation = (listIndex + 1) * 36; + markerLocation = listLocation - 25; + [newStyle setFirstLineHeadIndent:0]; + [newStyle setHeadIndent:listLocation]; + while ((count = [[newStyle tabStops] count]) > 0) { + for (i = 0, tabToRemove = nil; !tabToRemove && i < count; i++) { + tab = [[newStyle tabStops] objectAtIndex:i]; + if ([tab location] <= listLocation) tabToRemove = tab; + } + if (tabToRemove) [newStyle removeTabStop:tab]; else break; + } + tab = [[NSTextTab alloc] initWithType:NSLeftTabStopType location:markerLocation]; + [newStyle addTabStop:tab]; + [tab release]; + tab = [[NSTextTab alloc] initWithTextAlignment:NSNaturalTextAlignment location:listLocation options:nil]; + [newStyle addTabStop:tab]; + [tab release]; + if (!_flags.isIndexing && !_flags.isTesting) [_attrStr addAttribute:NSParagraphStyleAttributeName value:newStyle range:paragraphRange]; + [newStyle release]; + + idx = NSMaxRange(paragraphRange); + } else { + // skip any deeper-nested lists + idx = NSMaxRange(styleRange); + } + } + } + } +} + +- (void)_exitElement:(DOMElement *)element tag:(NSString *)tag display:(NSString *)displayVal depth:(NSInteger)depth startIndex:(NSUInteger)startIndex +{ + NSRange range = NSMakeRange(startIndex, [_attrStr length] - startIndex); + if (range.length > 0 && [@"A" isEqualToString:tag]) { + NSString *urlString = [element getAttribute:@"href"], *strippedString = [urlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + if (urlString && [urlString length] > 0 && strippedString && [strippedString length] > 0 && ![strippedString hasPrefix:@"#"]) { + NSURL *url = core([element ownerDocument])->completeURL(stripLeadingAndTrailingHTMLSpaces(urlString)); + if (!url) url = core([element ownerDocument])->completeURL(stripLeadingAndTrailingHTMLSpaces(strippedString)); + if (!url) url = [NSURL _web_URLWithString:strippedString relativeToURL:_baseURL]; + if (!_flags.isIndexing && !_flags.isTesting) [_attrStr addAttribute:NSLinkAttributeName value:url ? (id)url : (id)urlString range:range]; + } + } + if (!_flags.reachedEnd && [self _elementIsBlockLevel:element]) { + [_writingDirectionArray removeAllObjects]; + if ([@"table-cell" isEqualToString:displayVal] && [_textBlocks count] == 0) { + [self _newTabForElement:element]; + } else if ([_textLists count] > 0 && [@"block" isEqualToString:displayVal] && ![@"LI" isEqualToString:tag] && ![@"UL" isEqualToString:tag] && ![@"OL" isEqualToString:tag]) { + [self _newLineForElement:element]; + } else { + [self _newParagraphForElement:element tag:tag allowEmpty:(range.length == 0) suppressTrailingSpace:YES]; + } + } else if ([_writingDirectionArray count] > 0) { + NSString *bidi = [self _stringForNode:element property:@"unicode-bidi"]; + if (bidi && ([bidi isEqualToString:@"embed"] || [bidi isEqualToString:@"bidi-override"])) { + [_writingDirectionArray removeLastObject]; + } + } + range = NSMakeRange(startIndex, [_attrStr length] - startIndex); + if ([@"table" isEqualToString:displayVal] && [_textTables count] > 0) { + NSValue *key = [NSValue valueWithNonretainedObject:[_textTables lastObject]]; + DOMNode *footer = [_textTableFooters objectForKey:key]; + while ([_textTables count] < [_textBlocks count] + 1) { + [_textBlocks removeLastObject]; + } + if (footer) { + [self _traverseFooterNode:footer depth:depth + 1]; + [_textTableFooters removeObjectForKey:key]; + } + [_textTables removeLastObject]; + [_textTableSpacings removeLastObject]; + [_textTablePaddings removeLastObject]; + [_textTableRows removeLastObject]; + [_textTableRowArrays removeLastObject]; + } else if ([@"table-row" isEqualToString:displayVal] && [_textTables count] > 0) { + NSTextTable *table = [_textTables lastObject]; + NSTextTableBlock *block; + NSMutableArray *rowArray = [_textTableRowArrays lastObject], *previousRowArray; + NSUInteger i, count; + NSInteger numberOfColumns = [table numberOfColumns]; + NSInteger openColumn; + NSInteger rowNumber = [[_textTableRows lastObject] integerValue]; + do { + rowNumber++; + previousRowArray = rowArray; + rowArray = [NSMutableArray array]; + count = [previousRowArray count]; + for (i = 0; i < count; i++) { + block = [previousRowArray objectAtIndex:i]; + if ([block startingColumn] + [block columnSpan] > numberOfColumns) numberOfColumns = [block startingColumn] + [block columnSpan]; + if ([block startingRow] + [block rowSpan] > rowNumber) [rowArray addObject:block]; + } + count = [rowArray count]; + openColumn = 0; + for (i = 0; i < count; i++) { + block = [rowArray objectAtIndex:i]; + if (openColumn >= [block startingColumn] && openColumn < [block startingColumn] + [block columnSpan]) openColumn = [block startingColumn] + [block columnSpan]; + } + } while (openColumn >= numberOfColumns); + if ((NSUInteger)numberOfColumns > [table numberOfColumns]) [table setNumberOfColumns:numberOfColumns]; + [_textTableRows removeLastObject]; + [_textTableRows addObject:[NSNumber numberWithInteger:rowNumber]]; + [_textTableRowArrays removeLastObject]; + [_textTableRowArrays addObject:rowArray]; + if ([_textTableRowBackgroundColors count] > 0) [_textTableRowBackgroundColors removeLastObject]; + } else if ([@"table-cell" isEqualToString:displayVal] && [_textBlocks count] > 0) { + while ([_textTables count] > [_textBlocks count]) { + [_textTables removeLastObject]; + [_textTableSpacings removeLastObject]; + [_textTablePaddings removeLastObject]; + [_textTableRows removeLastObject]; + [_textTableRowArrays removeLastObject]; + } + [_textBlocks removeLastObject]; + } else if (([@"UL" isEqualToString:tag] || [@"OL" isEqualToString:tag]) && [_textLists count] > 0) { + NSTextList *list = [_textLists lastObject]; + [self _addMarkersToList:list range:range]; + [_textLists removeLastObject]; + } else if ([@"Q" isEqualToString:tag]) { + [self _addQuoteForElement:element opening:NO level:--_quoteLevel]; + } else if ([@"SPAN" isEqualToString:tag]) { + NSString *className = [element getAttribute:@"class"]; + NSMutableString *mutableString; + NSUInteger i, count = 0; + unichar c; + if ([@"Apple-converted-space" isEqualToString:className]) { + mutableString = [_attrStr mutableString]; + for (i = range.location; i < NSMaxRange(range); i++) { + c = [mutableString characterAtIndex:i]; + if (0xa0 == c) [mutableString replaceCharactersInRange:NSMakeRange(i, 1) withString:@" "]; + } + } else if ([@"Apple-converted-tab" isEqualToString:className]) { + mutableString = [_attrStr mutableString]; + for (i = range.location; i < NSMaxRange(range); i++) { + NSRange rangeToReplace = NSMakeRange(NSNotFound, 0); + c = [mutableString characterAtIndex:i]; + if (' ' == c || 0xa0 == c) { + count++; + if (count >= 4 || i + 1 >= NSMaxRange(range)) rangeToReplace = NSMakeRange(i + 1 - count, count); + } else { + if (count > 0) rangeToReplace = NSMakeRange(i - count, count); + } + if (rangeToReplace.length > 0) { + [mutableString replaceCharactersInRange:rangeToReplace withString:@"\t"]; + range.length -= (rangeToReplace.length - 1); + i -= (rangeToReplace.length - 1); + if (NSMaxRange(rangeToReplace) <= _domRangeStartIndex) { + _domRangeStartIndex -= (rangeToReplace.length - 1); + } else if (rangeToReplace.location < _domRangeStartIndex) { + _domRangeStartIndex = rangeToReplace.location; + } + count = 0; + } + } + } + } +} + +- (void)_processText:(DOMCharacterData *)text +{ + NSString *instr = [text data], *outstr = instr, *whitespaceVal, *transformVal; + NSUInteger textLength = [_attrStr length], startOffset = 0, endOffset = [instr length]; + unichar lastChar = (textLength > 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : '\n'; + BOOL wasSpace = NO, wasLeading = YES, suppressLeadingSpace = ((_flags.isSoft && lastChar == ' ') || lastChar == '\n' || lastChar == '\r' || lastChar == '\t' || lastChar == NSParagraphSeparatorCharacter || lastChar == NSLineSeparatorCharacter || lastChar == NSFormFeedCharacter || lastChar == WebNextLineCharacter); + NSRange rangeToReplace = NSMakeRange(textLength, 0); + CFMutableStringRef mutstr = NULL; + whitespaceVal = [self _stringForNode:text property:@"white-space"]; + transformVal = [self _stringForNode:text property:@"text-transform"]; + + if (_domRange) { + if (text == [_domRange startContainer]) { + startOffset = (NSUInteger)[_domRange startOffset]; + _domRangeStartIndex = [_attrStr length]; + _flags.reachedStart = YES; + } + if (text == [_domRange endContainer]) { + endOffset = (NSUInteger)[_domRange endOffset]; + _flags.reachedEnd = YES; + } + if ((startOffset > 0 || endOffset < [instr length]) && endOffset >= startOffset) { + instr = [instr substringWithRange:NSMakeRange(startOffset, endOffset - startOffset)]; + outstr = instr; + } + } + if ([whitespaceVal hasPrefix:@"pre"]) { + if (textLength > 0 && [instr length] > 0 && _flags.isSoft) { + unichar c = [instr characterAtIndex:0]; + if (c == '\n' || c == '\r' || c == NSParagraphSeparatorCharacter || c == NSLineSeparatorCharacter || c == NSFormFeedCharacter || c == WebNextLineCharacter) rangeToReplace = NSMakeRange(textLength - 1, 1); + } + } else { + CFStringInlineBuffer inlineBuffer; + const unsigned int TextBufferSize = 255; + + unichar buffer[TextBufferSize + 1]; + NSUInteger i, count = [instr length], idx = 0; + + mutstr = CFStringCreateMutable(NULL, 0); + CFStringInitInlineBuffer((CFStringRef)instr, &inlineBuffer, CFRangeMake(0, count)); + for (i = 0; i < count; i++) { + unichar c = CFStringGetCharacterFromInlineBuffer(&inlineBuffer, i); + if (c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == 0xc || c == 0x200b) { + wasSpace = (!wasLeading || !suppressLeadingSpace); + } else { + if (wasSpace) buffer[idx++] = ' '; + buffer[idx++] = c; + if (idx >= TextBufferSize) { + CFStringAppendCharacters(mutstr, buffer, idx); + idx = 0; + } + wasSpace = wasLeading = NO; + } + } + if (wasSpace) buffer[idx++] = ' '; + if (idx > 0) CFStringAppendCharacters(mutstr, buffer, idx); + outstr = (NSString *)mutstr; + } + if ([outstr length] > 0) { + if ([@"capitalize" isEqualToString:transformVal]) { + outstr = [outstr capitalizedString]; + } else if ([@"uppercase" isEqualToString:transformVal]) { + outstr = [outstr uppercaseString]; + } else if ([@"lowercase" isEqualToString:transformVal]) { + outstr = [outstr lowercaseString]; + } + [_attrStr replaceCharactersInRange:rangeToReplace withString:outstr]; + rangeToReplace.length = [outstr length]; + if (!_flags.isIndexing) { + NSDictionary *attrs; + DOMElement *element = (DOMElement *)text; + while (element && [element nodeType] != DOM_ELEMENT_NODE) element = (DOMElement *)[element parentNode]; + attrs = [self _attributesForElement:element]; + if (!_flags.isTesting && rangeToReplace.length > 0) [_attrStr setAttributes:attrs range:rangeToReplace]; + } + _flags.isSoft = wasSpace; + } + if (mutstr) CFRelease(mutstr); +} + +- (void)_traverseNode:(DOMNode *)node depth:(NSInteger)depth embedded:(BOOL)embedded +{ + unsigned short nodeType; + NSArray *childNodes; + NSUInteger i, count, startOffset, endOffset; + BOOL isStart = NO, isEnd = NO; + + if (_flags.reachedEnd) return; + if (_domRange && !_flags.reachedStart && _domStartAncestors && ![_domStartAncestors containsObject:node]) return; + + nodeType = [node nodeType]; + childNodes = [self _childrenForNode:node]; + count = [childNodes count]; + startOffset = 0; + endOffset = count; + + if (_domRange) { + if (node == [_domRange startContainer]) { + startOffset = (NSUInteger)[_domRange startOffset]; + isStart = YES; + _flags.reachedStart = YES; + } + if (node == [_domRange endContainer]) { + endOffset = (NSUInteger)[_domRange endOffset]; + isEnd = YES; + } + } + + if (nodeType == DOM_DOCUMENT_NODE || nodeType == DOM_DOCUMENT_FRAGMENT_NODE) { + for (i = 0; i < count; i++) { + if (isStart && i == startOffset) _domRangeStartIndex = [_attrStr length]; + if ((!isStart || startOffset <= i) && (!isEnd || endOffset > i)) [self _traverseNode:[childNodes objectAtIndex:i] depth:depth + 1 embedded:embedded]; + if (isEnd && i + 1 >= endOffset) _flags.reachedEnd = YES; + if (_thumbnailLimit > 0 && [_attrStr length] >= _thumbnailLimit) _flags.reachedEnd = YES; + if (_flags.reachedEnd) break; + } + } else if (nodeType == DOM_ELEMENT_NODE) { + DOMElement *element = (DOMElement *)node; + NSString *tag = [element tagName], *displayVal = [self _stringForNode:element property:@"display"], *floatVal = [self _stringForNode:element property:@"float"]; + BOOL isBlockLevel = NO; + if (floatVal && ([@"left" isEqualToString:floatVal] || [@"right" isEqualToString:floatVal])) { + isBlockLevel = YES; + } else if (displayVal) { + isBlockLevel = ([@"block" isEqualToString:displayVal] || [@"list-item" isEqualToString:displayVal] || [displayVal hasPrefix:@"table"]); + } + [_elementIsBlockLevel setObject:[NSNumber numberWithBool:isBlockLevel] forKey:element]; + if ([self _enterElement:element tag:tag display:displayVal]) { + NSUInteger startIndex = [_attrStr length]; + if ([self _processElement:element tag:tag display:displayVal depth:depth]) { + for (i = 0; i < count; i++) { + if (isStart && i == startOffset) _domRangeStartIndex = [_attrStr length]; + if ((!isStart || startOffset <= i) && (!isEnd || endOffset > i)) [self _traverseNode:[childNodes objectAtIndex:i] depth:depth + 1 embedded:embedded]; + if (isEnd && i + 1 >= endOffset) _flags.reachedEnd = YES; + if (_flags.reachedEnd) break; + } + [self _exitElement:element tag:tag display:displayVal depth:depth startIndex:startIndex]; + } + } + } else if (nodeType == DOM_TEXT_NODE || nodeType == DOM_CDATA_SECTION_NODE) { + [self _processText:(DOMCharacterData *)node]; + } + + if (isEnd) _flags.reachedEnd = YES; +} + +- (void)_traverseFooterNode:(DOMNode *)node depth:(NSInteger)depth +{ + DOMElement *element = (DOMElement *)node; + NSArray *childNodes = [self _childrenForNode:node]; + NSString *tag = @"TBODY", *displayVal = @"table-row-group"; + NSUInteger i, count = [childNodes count], startOffset = 0, endOffset = count; + BOOL isStart = NO, isEnd = NO; + + if (_flags.reachedEnd) return; + if (_domRange && !_flags.reachedStart && _domStartAncestors && ![_domStartAncestors containsObject:node]) return; + if (_domRange) { + if (node == [_domRange startContainer]) { + startOffset = (NSUInteger)[_domRange startOffset]; + isStart = YES; + _flags.reachedStart = YES; + } + if (node == [_domRange endContainer]) { + endOffset = (NSUInteger)[_domRange endOffset]; + isEnd = YES; + } + } + if ([self _enterElement:element tag:tag display:displayVal]) { + NSUInteger startIndex = [_attrStr length]; + if ([self _processElement:element tag:tag display:displayVal depth:depth]) { + for (i = 0; i < count; i++) { + if (isStart && i == startOffset) _domRangeStartIndex = [_attrStr length]; + if ((!isStart || startOffset <= i) && (!isEnd || endOffset > i)) [self _traverseNode:[childNodes objectAtIndex:i] depth:depth + 1 embedded:YES]; + if (isEnd && i + 1 >= endOffset) _flags.reachedEnd = YES; + if (_flags.reachedEnd) break; + } + [self _exitElement:element tag:tag display:displayVal depth:depth startIndex:startIndex]; + } + } + if (isEnd) _flags.reachedEnd = YES; +} + +- (void)_adjustTrailingNewline +{ + NSUInteger textLength = [_attrStr length]; + unichar lastChar = (textLength > 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : 0; + BOOL alreadyHasTrailingNewline = (lastChar == '\n' || lastChar == '\r' || lastChar == NSParagraphSeparatorCharacter || lastChar == NSLineSeparatorCharacter || lastChar == WebNextLineCharacter); + if (_flags.hasTrailingNewline && !alreadyHasTrailingNewline) + [_attrStr replaceCharactersInRange:NSMakeRange(textLength, 0) withString:@"\n"]; +} + +- (void)_loadFromDOMRange +{ + if (-1 == _errorCode) { + DOMNode *commonAncestorContainer = [_domRange commonAncestorContainer], *ancestorContainer = [_domRange startContainer]; + + _domStartAncestors = [[NSMutableArray alloc] init]; + while (ancestorContainer) { + [_domStartAncestors addObject:ancestorContainer]; + if (ancestorContainer == commonAncestorContainer) break; + ancestorContainer = [ancestorContainer parentNode]; + } + _document = [commonAncestorContainer ownerDocument]; + _dataSource = (DocumentLoader *)core(_document)->frame()->loader()->documentLoader(); + if (_textSizeMultiplier <= 0.0) _textSizeMultiplier = 1; + if (_defaultFontSize <= 0.0) _defaultFontSize = 12; + if (_minimumFontSize < 1.0) _minimumFontSize = 1; + if (_document && _dataSource) { + _domRangeStartIndex = 0; + _errorCode = 0; + [self _traverseNode:commonAncestorContainer depth:0 embedded:NO]; + if (_domRangeStartIndex > 0 && _domRangeStartIndex <= [_attrStr length]) [_attrStr deleteCharactersInRange:NSMakeRange(0, _domRangeStartIndex)]; + } + } +} + +- (void)dealloc +{ + [_attrStr release]; + [_domRange release]; + [_domStartAncestors release]; + [_standardFontFamily release]; + [_textLists release]; + [_textBlocks release]; + [_textTables release]; + [_textTableFooters release]; + [_textTableSpacings release]; + [_textTablePaddings release]; + [_textTableRows release]; + [_textTableRowArrays release]; + [_textTableRowBackgroundColors release]; + [_computedStylesForElements release]; + [_specifiedStylesForElements release]; + [_stringsForNodes release]; + [_floatsForNodes release]; + [_colorsForNodes release]; + [_attributesForElements release]; + [_elementIsBlockLevel release]; + [_fontCache release]; + [_writingDirectionArray release]; + [super dealloc]; +} + +- (id)init +{ + self = [super init]; + if (!self) return nil; + + _attrStr = [[NSMutableAttributedString alloc] init]; + + _textLists = [[NSMutableArray alloc] init]; + _textBlocks = [[NSMutableArray alloc] init]; + _textTables = [[NSMutableArray alloc] init]; + _textTableFooters = [[NSMutableDictionary alloc] init]; + _textTableSpacings = [[NSMutableArray alloc] init]; + _textTablePaddings = [[NSMutableArray alloc] init]; + _textTableRows = [[NSMutableArray alloc] init]; + _textTableRowArrays = [[NSMutableArray alloc] init]; + _textTableRowBackgroundColors = [[NSMutableArray alloc] init]; + _computedStylesForElements = [[NSMutableDictionary alloc] init]; + _specifiedStylesForElements = [[NSMutableDictionary alloc] init]; + _stringsForNodes = [[NSMutableDictionary alloc] init]; + _floatsForNodes = [[NSMutableDictionary alloc] init]; + _colorsForNodes = [[NSMutableDictionary alloc] init]; + _attributesForElements = [[NSMutableDictionary alloc] init]; + _elementIsBlockLevel = [[NSMutableDictionary alloc] init]; + _fontCache = [[NSMutableDictionary alloc] init]; + _writingDirectionArray = [[NSMutableArray alloc] init]; + + _textSizeMultiplier = 1; + _webViewTextSizeMultiplier = 0; + _defaultTabInterval = 36; + _defaultFontSize = 12; + _minimumFontSize = 1; + _errorCode = -1; + _indexingLimit = 0; + _thumbnailLimit = 0; + + _flags.isIndexing = (_indexingLimit > 0); + _flags.isTesting = 0; + + return self; +} + +- (id)initWithDOMRange:(DOMRange *)domRange +{ + self = [self init]; + if (!self) return nil; + _domRange = [domRange retain]; + return self; +} + +- (NSAttributedString *)attributedString +{ + [self _loadFromDOMRange]; + return (0 == _errorCode) ? [[_attrStr retain] autorelease] : nil; +} + +@end +#endif diff --git a/Source/WebCore/platform/mac/LoggingMac.mm b/Source/WebCore/platform/mac/LoggingMac.mm index ee2f39e..168d0cc 100644 --- a/Source/WebCore/platform/mac/LoggingMac.mm +++ b/Source/WebCore/platform/mac/LoggingMac.mm @@ -23,6 +23,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" + #include "Logging.h" namespace WebCore { diff --git a/Source/WebCore/platform/mac/PasteboardMac.mm b/Source/WebCore/platform/mac/PasteboardMac.mm index 8c6610a..da06606 100644 --- a/Source/WebCore/platform/mac/PasteboardMac.mm +++ b/Source/WebCore/platform/mac/PasteboardMac.mm @@ -38,6 +38,10 @@ #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" #import "KURL.h" @@ -144,9 +148,30 @@ void Pasteboard::writeSelection(NSPasteboard* pasteboard, NSArray* pasteboardTyp Pasteboard::generalPasteboard(); // Initializes pasteboard types. ASSERT(selectedRange); + // If the selection is at the beginning of content inside an anchor tag + // we move the selection start to include the anchor. + // This way the attributed string will contain the url attribute as well. + // See <rdar://problem/9084267>. + ExceptionCode ec; + Node* commonAncestor = selectedRange->commonAncestorContainer(ec); + ASSERT(commonAncestor); + Node* enclosingAnchor = enclosingNodeWithTag(firstPositionInNode(commonAncestor), HTMLNames::aTag); + if (enclosingAnchor && comparePositions(firstPositionInOrBeforeNode(selectedRange->startPosition().anchorNode()), selectedRange->startPosition()) >= 0) + selectedRange->setStart(enclosingAnchor, 0, ec); + // Using different API for WebKit and WebKit2. - // FIXME - We need to have a way to create the NSAttributedString for WebKit2 that doesn't require accessing the WebFrame. - NSAttributedString *attributedString = (frame->view()->platformWidget()) ? [[[NSAttributedString alloc] _initWithDOMRange:kit(selectedRange)] autorelease] : [[[NSAttributedString alloc] initWithString:selectedRange->text()] autorelease]; + NSAttributedString *attributedString = nil; + if (frame->view()->platformWidget()) + attributedString = [[[NSAttributedString alloc] _initWithDOMRange:kit(selectedRange)] autorelease]; +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + else { + // In WebKit2 we are using a different way to create the NSAttributedString from the DOMrange that doesn't require access to the WebView. + RetainPtr<WebHTMLConverter> converter = [[WebHTMLConverter alloc] initWithDOMRange:kit(selectedRange)]; + if (converter) + attributedString = [converter.get() attributedString]; + } +#endif + #ifdef BUILDING_ON_TIGER // 4930197: Mail overrides [WebHTMLView pasteboardTypesForSelection] in order to add another type to the pasteboard // after WebKit does. On Tiger we must call this function so that Mail code will be executed, meaning that diff --git a/Source/WebCore/platform/mac/PlatformScreenMac.mm b/Source/WebCore/platform/mac/PlatformScreenMac.mm index 5dbfcf4..916fc9f 100644 --- a/Source/WebCore/platform/mac/PlatformScreenMac.mm +++ b/Source/WebCore/platform/mac/PlatformScreenMac.mm @@ -76,12 +76,21 @@ NSScreen *screenForWindow(NSWindow *window) return nil; } +static CGFloat windowScaleFactor(NSWindow *window) +{ +#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) + return [window backingScaleFactor]; +#else + return [window userSpaceScaleFactor]; +#endif +} + FloatRect toUserSpace(const NSRect& rect, NSWindow *destination) { FloatRect userRect = rect; userRect.setY(NSMaxY([screenForWindow(destination) frame]) - (userRect.y() + userRect.height())); // flip if (destination) - userRect.scale(1 / [destination userSpaceScaleFactor]); // scale down + userRect.scale(1 / windowScaleFactor(destination)); // scale down return userRect; } @@ -89,7 +98,7 @@ NSRect toDeviceSpace(const FloatRect& rect, NSWindow *source) { FloatRect deviceRect = rect; if (source) - deviceRect.scale([source userSpaceScaleFactor]); // scale up + deviceRect.scale(windowScaleFactor(source)); // scale up deviceRect.setY(NSMaxY([screenForWindow(source) frame]) - (deviceRect.y() + deviceRect.height())); // flip return deviceRect; } diff --git a/Source/WebCore/platform/mac/SSLKeyGeneratorMac.cpp b/Source/WebCore/platform/mac/SSLKeyGeneratorMac.cpp new file mode 100644 index 0000000..0a1a4d8 --- /dev/null +++ b/Source/WebCore/platform/mac/SSLKeyGeneratorMac.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2003, 2005, 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. + */ + +#include "config.h" +#include "SSLKeyGenerator.h" + +#include "KURL.h" +#include "LocalizedStrings.h" +#include "WebCoreSystemInterface.h" +#include <wtf/RetainPtr.h> + +namespace WebCore { + +void getSupportedKeySizes(Vector<String>& supportedKeySizes) +{ + ASSERT(supportedKeySizes.isEmpty()); + supportedKeySizes.append(keygenMenuItem2048()); + supportedKeySizes.append(keygenMenuItem1024()); + supportedKeySizes.append(keygenMenuItem512()); +} + +String signedPublicKeyAndChallengeString(unsigned keySizeIndex, const String& challengeString, const KURL& url) +{ + // This switch statement must always be synced with the UI strings returned by getSupportedKeySizes. + UInt32 keySize; + switch (keySizeIndex) { + case 0: + keySize = 2048; + break; + case 1: + keySize = 1024; + break; + case 2: + keySize = 512; + break; + default: + ASSERT_NOT_REACHED(); + return String(); + } + + RetainPtr<CFStringRef> challengeStringCF(AdoptCF, challengeString.createCFString()); + RetainPtr<CFStringRef> keyDescription(AdoptCF, keygenKeychainItemName(url.host()).createCFString()); + RetainPtr<CFStringRef> result(AdoptCF, wkSignedPublicKeyAndChallengeString(keySize, challengeStringCF.get(), keyDescription.get())); + + return result.get(); +} + +} diff --git a/Source/WebCore/platform/mac/ScrollAnimatorMac.h b/Source/WebCore/platform/mac/ScrollAnimatorMac.h index 2bafbf5..f7b6332 100644 --- a/Source/WebCore/platform/mac/ScrollAnimatorMac.h +++ b/Source/WebCore/platform/mac/ScrollAnimatorMac.h @@ -30,7 +30,6 @@ #include "FloatPoint.h" #include "FloatSize.h" -#include "HeaderDetection.h" #include "ScrollAnimator.h" #include "Timer.h" #include "WebCoreSystemInterface.h" @@ -67,6 +66,8 @@ public: #endif #endif + virtual void cancelAnimations(); + void immediateScrollToPoint(const FloatPoint& newPosition); void immediateScrollByDeltaX(float deltaX); void immediateScrollByDeltaY(float deltaY); @@ -74,14 +75,25 @@ public: void setIsDrawingIntoLayer(bool b) { m_drawingIntoLayer = b; } bool isDrawingIntoLayer() const { return m_drawingIntoLayer; } + bool haveScrolledSincePageLoad() const { return m_haveScrolledSincePageLoad; } + +#if USE(WK_SCROLLBAR_PAINTER) + bool scrollbarPaintTimerIsActive() const; + void startScrollbarPaintTimer(); + void stopScrollbarPaintTimer(); +#endif + private: RetainPtr<id> m_scrollAnimationHelper; RetainPtr<ScrollAnimationHelperDelegate> m_scrollAnimationHelperDelegate; -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) RetainPtr<WKScrollbarPainterControllerRef> m_scrollbarPainterController; RetainPtr<ScrollbarPainterControllerDelegate> m_scrollbarPainterControllerDelegate; RetainPtr<id> m_scrollbarPainterDelegate; + + void initialScrollbarPaintTimerFired(Timer<ScrollAnimatorMac>*); + Timer<ScrollAnimatorMac> m_initialScrollbarPaintTimer; #endif virtual void notityPositionChanged(); @@ -131,6 +143,7 @@ private: Timer<ScrollAnimatorMac> m_snapRubberBandTimer; #endif bool m_drawingIntoLayer; + bool m_haveScrolledSincePageLoad; }; } // namespace WebCore diff --git a/Source/WebCore/platform/mac/ScrollAnimatorMac.mm b/Source/WebCore/platform/mac/ScrollAnimatorMac.mm index 67c0904..5725880 100644 --- a/Source/WebCore/platform/mac/ScrollAnimatorMac.mm +++ b/Source/WebCore/platform/mac/ScrollAnimatorMac.mm @@ -141,7 +141,7 @@ static NSSize abs(NSSize size) @end -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) @interface ScrollbarPainterControllerDelegate : NSObject { @@ -240,6 +240,13 @@ static NSSize abs(NSSize size) verticalScrollbar->controlSize(), false); macTheme->setNewPainterForScrollbar(verticalScrollbar, newVerticalPainter); + wkSetPainterForPainterController(painterController, newVerticalPainter, false); + + // The different scrollbar styles have different thicknesses, so we must re-set the + // frameRect to the new thickness, and the re-layout below will ensure the position + // and length are properly updated. + int thickness = macTheme->scrollbarThickness(verticalScrollbar->controlSize()); + verticalScrollbar->setFrameRect(WebCore::IntRect(0, 0, thickness, thickness)); } WKScrollbarPainterRef oldHorizontalPainter = wkHorizontalScrollbarPainterForController(painterController); @@ -250,9 +257,19 @@ static NSSize abs(NSSize size) horizontalScrollbar->controlSize(), true); macTheme->setNewPainterForScrollbar(horizontalScrollbar, newHorizontalPainter); + wkSetPainterForPainterController(painterController, newHorizontalPainter, true); + + // The different scrollbar styles have different thicknesses, so we must re-set the + // frameRect to the new thickness, and the re-layout below will ensure the position + // and length are properly updated. + int thickness = macTheme->scrollbarThickness(horizontalScrollbar->controlSize()); + horizontalScrollbar->setFrameRect(WebCore::IntRect(0, 0, thickness, thickness)); } wkSetScrollbarPainterControllerStyle(painterController, newRecommendedScrollerStyle); + + // The different scrollbar styles affect layout, so we must re-layout everything. + _animator->scrollableArea()->scrollbarStyleChanged(); } @end @@ -329,6 +346,7 @@ static NSSize abs(NSSize size) RetainPtr<ScrollbarPartAnimation> _horizontalTrackAnimation; } - (id)initWithScrollAnimator:(WebCore::ScrollAnimatorMac*)scrollAnimator; +- (void)cancelAnimations; @end @implementation ScrollbarPainterDelegate @@ -343,6 +361,14 @@ static NSSize abs(NSSize size) return self; } +- (void)cancelAnimations +{ + [_verticalKnobAnimation.get() stopAnimation]; + [_horizontalKnobAnimation.get() stopAnimation]; + [_verticalTrackAnimation.get() stopAnimation]; + [_horizontalTrackAnimation.get() stopAnimation]; +} + - (NSRect)convertRectToBacking:(NSRect)aRect { return aRect; @@ -367,12 +393,29 @@ static NSSize abs(NSSize size) - (void)setUpAnimation:(RetainPtr<ScrollbarPartAnimation>&)scrollbarPartAnimation scrollerPainter:(WKScrollbarPainterRef)scrollerPainter part:(WebCore::ScrollbarPart)part animateAlphaTo:(CGFloat)newAlpha duration:(NSTimeInterval)duration { + // If the user has scrolled the page, then the scrollbars must be animated here. + // This overrides the early returns. + bool mustAnimate = _animator->haveScrolledSincePageLoad(); + + if (_animator->scrollbarPaintTimerIsActive() && !mustAnimate) + return; + + if (_animator->scrollableArea()->shouldSuspendScrollAnimations() && !mustAnimate) { + _animator->startScrollbarPaintTimer(); + return; + } + + // At this point, we are definitely going to animate now, so stop the timer. + _animator->stopScrollbarPaintTimer(); + // If we are currently animating, stop if (scrollbarPartAnimation) { [scrollbarPartAnimation.get() stopAnimation]; scrollbarPartAnimation = nil; } - + + [NSAnimationContext beginGrouping]; + [[NSAnimationContext currentContext] setDuration:duration]; scrollbarPartAnimation.adoptNS([[ScrollbarPartAnimation alloc] initWithScrollbarPainter:scrollerPainter part:part scrollAnimator:_animator @@ -380,6 +423,7 @@ static NSSize abs(NSSize size) duration:duration]); [scrollbarPartAnimation.get() setAnimationBlockingMode:NSAnimationNonblocking]; [scrollbarPartAnimation.get() startAnimation]; + [NSAnimationContext endGrouping]; } - (void)scrollerImp:(id)scrollerImp animateKnobAlphaTo:(CGFloat)newKnobAlpha duration:(NSTimeInterval)duration @@ -388,9 +432,6 @@ static NSSize abs(NSSize size) return; WKScrollbarPainterRef scrollerPainter = (WKScrollbarPainterRef)scrollerImp; - if (newKnobAlpha == wkScrollbarPainterKnobAlpha(scrollerPainter)) - return; - if (wkScrollbarPainterIsHorizontal(scrollerPainter)) [self setUpAnimation:_horizontalKnobAnimation scrollerPainter:scrollerPainter part:WebCore::ThumbPart animateAlphaTo:newKnobAlpha duration:duration]; else @@ -403,9 +444,6 @@ static NSSize abs(NSSize size) return; WKScrollbarPainterRef scrollerPainter = (WKScrollbarPainterRef)scrollerImp; - if (newTrackAlpha == wkScrollbarPainterTrackAlpha(scrollerPainter)) - return; - if (wkScrollbarPainterIsHorizontal(scrollerPainter)) [self setUpAnimation:_horizontalTrackAnimation scrollerPainter:scrollerPainter part:WebCore::BackTrackPart animateAlphaTo:newTrackAlpha duration:duration]; else @@ -414,20 +452,8 @@ static NSSize abs(NSSize size) - (void)scrollerImp:(id)scrollerImp overlayScrollerStateChangedTo:(NSUInteger)newOverlayScrollerState { - if (!_animator) - return; - - WKScrollbarPainterRef scrollbarPainter = (WKScrollbarPainterRef)scrollerImp; - wkScrollbarPainterSetOverlayState(scrollbarPainter, newOverlayScrollerState); - - if (wkScrollbarPainterIsHorizontal(scrollbarPainter)) { - WebCore::Scrollbar* horizontalScrollbar = _animator->scrollableArea()->horizontalScrollbar(); - _animator->scrollableArea()->invalidateScrollbarRect(horizontalScrollbar, WebCore::IntRect(0, 0, horizontalScrollbar->width(), horizontalScrollbar->height())); - } else { - WebCore::Scrollbar* verticalScrollbar = _animator->scrollableArea()->verticalScrollbar(); - _animator->scrollableArea()->invalidateScrollbarRect(verticalScrollbar, WebCore::IntRect(0, 0, verticalScrollbar->width(), verticalScrollbar->height())); - - } + UNUSED_PARAM(scrollerImp); + UNUSED_PARAM(newOverlayScrollerState); } - (void)scrollAnimatorDestroyed @@ -440,7 +466,8 @@ static NSSize abs(NSSize size) } @end -#endif // #if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) + +#endif // USE(WK_SCROLLBAR_PAINTER) namespace WebCore { @@ -451,6 +478,9 @@ PassOwnPtr<ScrollAnimator> ScrollAnimator::create(ScrollableArea* scrollableArea ScrollAnimatorMac::ScrollAnimatorMac(ScrollableArea* scrollableArea) : ScrollAnimator(scrollableArea) +#if USE(WK_SCROLLBAR_PAINTER) + , m_initialScrollbarPaintTimer(this, &ScrollAnimatorMac::initialScrollbarPaintTimerFired) +#endif #if ENABLE(RUBBER_BANDING) , m_inScrollGesture(false) , m_momentumScrollInProgress(false) @@ -460,11 +490,12 @@ ScrollAnimatorMac::ScrollAnimatorMac(ScrollableArea* scrollableArea) , m_snapRubberBandTimer(this, &ScrollAnimatorMac::snapRubberBandTimerFired) #endif , m_drawingIntoLayer(false) + , m_haveScrolledSincePageLoad(false) { m_scrollAnimationHelperDelegate.adoptNS([[ScrollAnimationHelperDelegate alloc] initWithScrollAnimator:this]); m_scrollAnimationHelper.adoptNS([[NSClassFromString(@"NSScrollAnimationHelper") alloc] initWithDelegate:m_scrollAnimationHelperDelegate.get()]); -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) m_scrollbarPainterControllerDelegate.adoptNS([[ScrollbarPainterControllerDelegate alloc] initWithScrollAnimator:this]); m_scrollbarPainterController = wkMakeScrollbarPainterController(m_scrollbarPainterControllerDelegate.get()); m_scrollbarPainterDelegate.adoptNS([[ScrollbarPainterDelegate alloc] initWithScrollAnimator:this]); @@ -473,7 +504,7 @@ ScrollAnimatorMac::ScrollAnimatorMac(ScrollableArea* scrollableArea) ScrollAnimatorMac::~ScrollAnimatorMac() { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) [m_scrollbarPainterControllerDelegate.get() scrollAnimatorDestroyed]; [(id)m_scrollbarPainterController.get() setDelegate:nil]; [m_scrollbarPainterDelegate.get() scrollAnimatorDestroyed]; @@ -483,6 +514,8 @@ ScrollAnimatorMac::~ScrollAnimatorMac() bool ScrollAnimatorMac::scroll(ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float multiplier) { + m_haveScrolledSincePageLoad = true; + if (![[NSUserDefaults standardUserDefaults] boolForKey:@"AppleScrollAnimationEnabled"]) return ScrollAnimator::scroll(orientation, granularity, step, multiplier); @@ -561,7 +594,7 @@ void ScrollAnimatorMac::immediateScrollByDeltaY(float deltaY) void ScrollAnimatorMac::notityPositionChanged() { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) wkContentAreaScrolled(m_scrollbarPainterController.get()); #endif ScrollAnimator::notityPositionChanged(); @@ -569,70 +602,70 @@ void ScrollAnimatorMac::notityPositionChanged() void ScrollAnimatorMac::contentAreaWillPaint() const { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) wkContentAreaWillPaint(m_scrollbarPainterController.get()); #endif } void ScrollAnimatorMac::mouseEnteredContentArea() const { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) wkMouseEnteredContentArea(m_scrollbarPainterController.get()); #endif } void ScrollAnimatorMac::mouseExitedContentArea() const { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) wkMouseExitedContentArea(m_scrollbarPainterController.get()); #endif } void ScrollAnimatorMac::mouseMovedInContentArea() const { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) wkMouseMovedInContentArea(m_scrollbarPainterController.get()); #endif } void ScrollAnimatorMac::willStartLiveResize() { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) wkWillStartLiveResize(m_scrollbarPainterController.get()); #endif } void ScrollAnimatorMac::contentsResized() const { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) wkContentAreaResized(m_scrollbarPainterController.get()); #endif } void ScrollAnimatorMac::willEndLiveResize() { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) wkWillEndLiveResize(m_scrollbarPainterController.get()); #endif } void ScrollAnimatorMac::contentAreaDidShow() const { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) wkContentAreaDidShow(m_scrollbarPainterController.get()); #endif } void ScrollAnimatorMac::contentAreaDidHide() const { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) wkContentAreaDidHide(m_scrollbarPainterController.get()); #endif } void ScrollAnimatorMac::didAddVerticalScrollbar(Scrollbar* scrollbar) { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar); wkScrollbarPainterSetDelegate(painter, m_scrollbarPainterDelegate.get()); wkSetPainterForPainterController(m_scrollbarPainterController.get(), painter, false); @@ -645,7 +678,7 @@ void ScrollAnimatorMac::didAddVerticalScrollbar(Scrollbar* scrollbar) void ScrollAnimatorMac::willRemoveVerticalScrollbar(Scrollbar* scrollbar) { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar); wkScrollbarPainterSetDelegate(painter, nil); wkSetPainterForPainterController(m_scrollbarPainterController.get(), nil, false); @@ -656,7 +689,7 @@ void ScrollAnimatorMac::willRemoveVerticalScrollbar(Scrollbar* scrollbar) void ScrollAnimatorMac::didAddHorizontalScrollbar(Scrollbar* scrollbar) { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar); wkScrollbarPainterSetDelegate(painter, m_scrollbarPainterDelegate.get()); wkSetPainterForPainterController(m_scrollbarPainterController.get(), painter, true); @@ -669,7 +702,7 @@ void ScrollAnimatorMac::didAddHorizontalScrollbar(Scrollbar* scrollbar) void ScrollAnimatorMac::willRemoveHorizontalScrollbar(Scrollbar* scrollbar) { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar); wkScrollbarPainterSetDelegate(painter, nil); wkSetPainterForPainterController(m_scrollbarPainterController.get(), nil, true); @@ -678,6 +711,17 @@ void ScrollAnimatorMac::willRemoveHorizontalScrollbar(Scrollbar* scrollbar) #endif } +void ScrollAnimatorMac::cancelAnimations() +{ + m_haveScrolledSincePageLoad = false; + +#if USE(WK_SCROLLBAR_PAINTER) + if (scrollbarPaintTimerIsActive()) + stopScrollbarPaintTimer(); + [m_scrollbarPainterDelegate.get() cancelAnimations]; +#endif +} + #if ENABLE(RUBBER_BANDING) static const float scrollVelocityZeroingTimeout = 0.10f; @@ -720,6 +764,8 @@ static float scrollWheelMultiplier() void ScrollAnimatorMac::handleWheelEvent(PlatformWheelEvent& wheelEvent) { + m_haveScrolledSincePageLoad = true; + if (!wheelEvent.hasPreciseScrollingDeltas()) { ScrollAnimator::handleWheelEvent(wheelEvent); return; @@ -751,18 +797,18 @@ bool ScrollAnimatorMac::pinnedInDirection(float deltaX, float deltaY) if (fabsf(deltaY) >= fabsf(deltaX)) { if (deltaY < 0) { // We are trying to scroll up. Make sure we are not pinned to the top - limitDelta.setHeight(m_scrollableArea->visibleContentRect().y()); + limitDelta.setHeight(m_scrollableArea->visibleContentRect().y() + + m_scrollableArea->scrollOrigin().y()); } else { // We are trying to scroll down. Make sure we are not pinned to the bottom - limitDelta.setHeight(m_scrollableArea->contentsSize().height() - m_scrollableArea->visibleContentRect().maxY()); + limitDelta.setHeight(m_scrollableArea->contentsSize().height() - (m_scrollableArea->visibleContentRect().maxY() + m_scrollableArea->scrollOrigin().y())); } } else if (deltaX != 0) { if (deltaX < 0) { // We are trying to scroll left. Make sure we are not pinned to the left - limitDelta.setWidth(m_scrollableArea->visibleContentRect().x()); + limitDelta.setWidth(m_scrollableArea->visibleContentRect().x() + m_scrollableArea->scrollOrigin().x()); } else { // We are trying to scroll right. Make sure we are not pinned to the right - limitDelta.setWidth(m_scrollableArea->contentsSize().width() - m_scrollableArea->visibleContentRect().maxX()); + limitDelta.setWidth(m_scrollableArea->contentsSize().width() - (m_scrollableArea->visibleContentRect().maxX() + m_scrollableArea->scrollOrigin().x())); } } @@ -793,6 +839,8 @@ bool ScrollAnimatorMac::allowsHorizontalStretching() const void ScrollAnimatorMac::smoothScrollWithEvent(PlatformWheelEvent& wheelEvent) { + m_haveScrolledSincePageLoad = true; + float deltaX = m_overflowScrollDelta.width(); float deltaY = m_overflowScrollDelta.height(); @@ -925,7 +973,7 @@ void ScrollAnimatorMac::smoothScrollWithEvent(PlatformWheelEvent& wheelEvent) m_stretchScrollForce.setHeight(m_stretchScrollForce.height() + deltaY); FloatSize dampedDelta(ceilf(elasticDeltaForReboundDelta(m_stretchScrollForce.width())), ceilf(elasticDeltaForReboundDelta(m_stretchScrollForce.height()))); - FloatPoint origOrigin = m_scrollableArea->visibleContentRect().location() - stretchAmount; + FloatPoint origOrigin = (m_scrollableArea->visibleContentRect().location() + m_scrollableArea->scrollOrigin()) - stretchAmount; FloatPoint newOrigin = origOrigin + dampedDelta; if (origOrigin != newOrigin) { @@ -945,6 +993,7 @@ void ScrollAnimatorMac::smoothScrollWithEvent(PlatformWheelEvent& wheelEvent) void ScrollAnimatorMac::beginScrollGesture() { + m_haveScrolledSincePageLoad = true; m_inScrollGesture = true; m_momentumScrollInProgress = false; m_ignoreMomentumScrolls = false; @@ -1017,7 +1066,7 @@ void ScrollAnimatorMac::snapRubberBandTimerFired(Timer<ScrollAnimatorMac>*) return; } - m_origOrigin = m_scrollableArea->visibleContentRect().location() - m_startStretch; + m_origOrigin = (m_scrollableArea->visibleContentRect().location() + m_scrollableArea->scrollOrigin()) - m_startStretch; m_origVelocity = m_momentumVelocity; // Just like normal scrolling, prefer vertical rubberbanding @@ -1069,6 +1118,28 @@ void ScrollAnimatorMac::snapRubberBandTimerFired(Timer<ScrollAnimatorMac>*) } #endif +#if USE(WK_SCROLLBAR_PAINTER) +void ScrollAnimatorMac::startScrollbarPaintTimer() +{ + m_initialScrollbarPaintTimer.startOneShot(0.1); +} + +bool ScrollAnimatorMac::scrollbarPaintTimerIsActive() const +{ + return m_initialScrollbarPaintTimer.isActive(); +} + +void ScrollAnimatorMac::stopScrollbarPaintTimer() +{ + m_initialScrollbarPaintTimer.stop(); +} + +void ScrollAnimatorMac::initialScrollbarPaintTimerFired(Timer<ScrollAnimatorMac>*) +{ + wkScrollbarPainterForceFlashScrollers(m_scrollbarPainterController.get()); +} +#endif + } // namespace WebCore #endif // ENABLE(SMOOTH_SCROLLING) diff --git a/Source/WebCore/platform/mac/ScrollbarThemeMac.h b/Source/WebCore/platform/mac/ScrollbarThemeMac.h index 844a088..bd56808 100644 --- a/Source/WebCore/platform/mac/ScrollbarThemeMac.h +++ b/Source/WebCore/platform/mac/ScrollbarThemeMac.h @@ -26,7 +26,6 @@ #ifndef ScrollbarThemeMac_h #define ScrollbarThemeMac_h -#include "HeaderDetection.h" #include "ScrollbarThemeComposite.h" #include "WebCoreSystemInterface.h" @@ -52,7 +51,7 @@ public: virtual void registerScrollbar(Scrollbar*); virtual void unregisterScrollbar(Scrollbar*); -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) void setNewPainterForScrollbar(Scrollbar*, WKScrollbarPainterRef); WKScrollbarPainterRef painterForScrollbar(Scrollbar*); #endif diff --git a/Source/WebCore/platform/mac/ScrollbarThemeMac.mm b/Source/WebCore/platform/mac/ScrollbarThemeMac.mm index 5a3796d..5504f5c 100644 --- a/Source/WebCore/platform/mac/ScrollbarThemeMac.mm +++ b/Source/WebCore/platform/mac/ScrollbarThemeMac.mm @@ -169,7 +169,7 @@ void ScrollbarThemeMac::unregisterScrollbar(Scrollbar* scrollbar) scrollbarMap()->remove(scrollbar); } -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) void ScrollbarThemeMac::setNewPainterForScrollbar(Scrollbar* scrollbar, WKScrollbarPainterRef newPainter) { scrollbarMap()->set(scrollbar, newPainter); @@ -440,7 +440,11 @@ bool ScrollbarThemeMac::paint(Scrollbar* scrollbar, GraphicsContext* context, co overhang = scrollbar->currentPos() + scrollbar->visibleSize() - scrollbar->totalSize(); } else { // Within the bounds of the scrollable area. - value = scrollbar->currentPos() / scrollbar->maximum(); + int maximum = scrollbar->maximum(); + if (maximum > 0) + value = scrollbar->currentPos() / maximum; + else + value = 0; } ScrollAnimatorMac* scrollAnimator = static_cast<ScrollAnimatorMac*>(scrollbar->scrollableArea()->scrollAnimator()); diff --git a/Source/WebCore/platform/mac/ThemeMac.mm b/Source/WebCore/platform/mac/ThemeMac.mm index e510ea7..918bc07 100644 --- a/Source/WebCore/platform/mac/ThemeMac.mm +++ b/Source/WebCore/platform/mac/ThemeMac.mm @@ -52,6 +52,11 @@ using namespace std; return nil; } +- (BOOL)_automaticFocusRingDisabled +{ + return YES; +} + - (NSRect)_focusRingVisibleRect { return [self visibleRect]; diff --git a/Source/WebCore/platform/mac/WebCoreObjCExtras.mm b/Source/WebCore/platform/mac/WebCoreObjCExtras.mm index 05d3e01..5a2d564 100644 --- a/Source/WebCore/platform/mac/WebCoreObjCExtras.mm +++ b/Source/WebCore/platform/mac/WebCoreObjCExtras.mm @@ -26,6 +26,11 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +// This file intentionally calls objc_finalizeOnMainThread, which is deprecated. +// According to http://gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/Diagnostic-Pragmas.html#Diagnostic-Pragmas +// we need to place this directive before any data or functions are defined. +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + #include "config.h" #include "WebCoreObjCExtras.h" diff --git a/Source/WebCore/platform/mac/WebCoreSystemInterface.h b/Source/WebCore/platform/mac/WebCoreSystemInterface.h index df65ff2..308a551 100644 --- a/Source/WebCore/platform/mac/WebCoreSystemInterface.h +++ b/Source/WebCore/platform/mac/WebCoreSystemInterface.h @@ -86,6 +86,8 @@ class QTMovie; class QTMovieView; #endif +typedef struct _CFURLResponse *CFURLResponseRef; + extern "C" { // In alphabetical order. @@ -115,6 +117,7 @@ extern BOOL (*wkGetGlyphTransformedAdvances)(CGFontRef, NSFont*, CGAffineTransfo extern void (*wkDrawMediaSliderTrack)(int themeStyle, CGContextRef context, CGRect rect, float timeLoaded, float currentTime, float duration, unsigned state); extern void (*wkDrawMediaUIPart)(int part, int themeStyle, CGContextRef context, CGRect rect, unsigned state); +extern CFStringRef (*wkSignedPublicKeyAndChallengeString)(unsigned keySize, CFStringRef challenge, CFStringRef keyDescription); extern NSString* (*wkGetPreferredExtensionForMIMEType)(NSString*); extern NSArray* (*wkGetExtensionsForMIMEType)(NSString*); extern NSString* (*wkGetMIMETypeForExtension)(NSString*); @@ -194,10 +197,13 @@ extern CGContextRef (*wkIOSurfaceContextCreate)(IOSurfaceRef surface, unsigned w extern CGImageRef (*wkIOSurfaceContextCreateImage)(CGContextRef context); typedef struct __WKScrollbarPainter *WKScrollbarPainterRef; +typedef struct __WKScrollbarPainterController *WKScrollbarPainterControllerRef; + extern WKScrollbarPainterRef (*wkMakeScrollbarPainter)(int controlSize, bool isHorizontal); extern WKScrollbarPainterRef (*wkMakeScrollbarReplacementPainter)(WKScrollbarPainterRef oldPainter, int newStyle, int controlSize, bool isHorizontal); extern void (*wkScrollbarPainterSetDelegate)(WKScrollbarPainterRef, id scrollbarPainterDelegate); extern void (*wkScrollbarPainterPaint)(WKScrollbarPainterRef, bool enabled, double value, CGFloat proportion, CGRect frameRect); +extern void (*wkScrollbarPainterForceFlashScrollers)(WKScrollbarPainterControllerRef); extern int (*wkScrollbarThickness)(int controlSize); extern int (*wkScrollbarMinimumThumbLength)(WKScrollbarPainterRef); extern int (*wkScrollbarMinimumTotalLengthNeededForThumb)(WKScrollbarPainterRef); @@ -208,7 +214,6 @@ extern void (*wkSetScrollbarPainterTrackAlpha)(WKScrollbarPainterRef, CGFloat); extern bool (*wkScrollbarPainterIsHorizontal)(WKScrollbarPainterRef); extern void (*wkScrollbarPainterSetOverlayState)(WKScrollbarPainterRef, int overlayScrollerState); -typedef struct __WKScrollbarPainterController *WKScrollbarPainterControllerRef; extern WKScrollbarPainterControllerRef (*wkMakeScrollbarPainterController)(id painterControllerDelegate); extern void (*wkSetPainterForPainterController)(WKScrollbarPainterControllerRef, WKScrollbarPainterRef, bool isHorizontal); extern WKScrollbarPainterRef (*wkVerticalScrollbarPainterForController)(WKScrollbarPainterControllerRef); @@ -244,12 +249,18 @@ extern CFURLStorageSessionRef (*wkCreatePrivateStorageSession)(CFStringRef); extern NSURLRequest* (*wkCopyRequestWithStorageSession)(CFURLStorageSessionRef, NSURLRequest*); typedef struct OpaqueCFHTTPCookieStorage* CFHTTPCookieStorageRef; -extern CFHTTPCookieStorageRef (*wkCreatePrivateInMemoryHTTPCookieStorage)(CFURLStorageSessionRef); +extern CFHTTPCookieStorageRef (*wkCopyHTTPCookieStorage)(CFURLStorageSessionRef); extern unsigned (*wkGetHTTPCookieAcceptPolicy)(CFHTTPCookieStorageRef); extern NSArray *(*wkHTTPCookiesForURL)(CFHTTPCookieStorageRef, NSURL *); extern void (*wkSetHTTPCookiesForURL)(CFHTTPCookieStorageRef, NSArray *, NSURL *, NSURL *); extern void (*wkDeleteHTTPCookie)(CFHTTPCookieStorageRef, NSHTTPCookie *); +extern CFStringRef (*wkGetCFURLResponseMIMEType)(CFURLResponseRef); +extern CFURLRef (*wkGetCFURLResponseURL)(CFURLResponseRef); +extern CFHTTPMessageRef (*wkGetCFURLResponseHTTPResponse)(CFURLResponseRef); +extern CFStringRef (*wkCopyCFURLResponseSuggestedFilename)(CFURLResponseRef); +extern void (*wkSetCFURLResponseMIMEType)(CFURLResponseRef, CFStringRef mimeType); + } #endif diff --git a/Source/WebCore/platform/mac/WebCoreSystemInterface.mm b/Source/WebCore/platform/mac/WebCoreSystemInterface.mm index 50ac236..ab059bd 100644 --- a/Source/WebCore/platform/mac/WebCoreSystemInterface.mm +++ b/Source/WebCore/platform/mac/WebCoreSystemInterface.mm @@ -48,6 +48,7 @@ void (*wkDrawMediaUIPart)(int part, int themeStyle, CGContextRef context, CGRect void (*wkMeasureMediaUIPart)(int part, int themeStyle, CGRect *bounds, CGSize *naturalSize); BOOL (*wkMediaControllerThemeAvailable)(int themeStyle); NSString* (*wkGetPreferredExtensionForMIMEType)(NSString*); +CFStringRef (*wkSignedPublicKeyAndChallengeString)(unsigned keySize, CFStringRef challenge, CFStringRef keyDescription); NSArray* (*wkGetExtensionsForMIMEType)(NSString*); NSString* (*wkGetMIMETypeForExtension)(NSString*); NSTimeInterval (*wkGetNSURLResponseCalculatedExpiration)(NSURLResponse *response); @@ -132,6 +133,7 @@ WKScrollbarPainterRef (*wkMakeScrollbarPainter)(int controlSize, bool isHorizont WKScrollbarPainterRef (*wkMakeScrollbarReplacementPainter)(WKScrollbarPainterRef oldPainter, int newStyle, int controlSize, bool isHorizontal); void (*wkScrollbarPainterSetDelegate)(WKScrollbarPainterRef, id scrollbarPainterDelegate); void (*wkScrollbarPainterPaint)(WKScrollbarPainterRef, bool enabled, double value, CGFloat proportion, CGRect frameRect); +void (*wkScrollbarPainterForceFlashScrollers)(WKScrollbarPainterControllerRef); int (*wkScrollbarThickness)(int controlSize); int (*wkScrollbarMinimumThumbLength)(WKScrollbarPainterRef); int (*wkScrollbarMinimumTotalLengthNeededForThumb)(WKScrollbarPainterRef); @@ -174,8 +176,14 @@ AXUIElementRef (*wkCreateAXUIElementRef)(id element); CFURLStorageSessionRef (*wkCreatePrivateStorageSession)(CFStringRef); NSURLRequest* (*wkCopyRequestWithStorageSession)(CFURLStorageSessionRef, NSURLRequest*); -CFHTTPCookieStorageRef (*wkCreatePrivateInMemoryHTTPCookieStorage)(CFURLStorageSessionRef); +CFHTTPCookieStorageRef (*wkCopyHTTPCookieStorage)(CFURLStorageSessionRef); unsigned (*wkGetHTTPCookieAcceptPolicy)(CFHTTPCookieStorageRef); NSArray *(*wkHTTPCookiesForURL)(CFHTTPCookieStorageRef, NSURL *); void (*wkSetHTTPCookiesForURL)(CFHTTPCookieStorageRef, NSArray *, NSURL *, NSURL *); void (*wkDeleteHTTPCookie)(CFHTTPCookieStorageRef, NSHTTPCookie *); + +CFStringRef (*wkGetCFURLResponseMIMEType)(CFURLResponseRef); +CFURLRef (*wkGetCFURLResponseURL)(CFURLResponseRef); +CFHTTPMessageRef (*wkGetCFURLResponseHTTPResponse)(CFURLResponseRef); +CFStringRef (*wkCopyCFURLResponseSuggestedFilename)(CFURLResponseRef); +void (*wkSetCFURLResponseMIMEType)(CFURLResponseRef, CFStringRef mimeType); diff --git a/Source/WebCore/platform/mac/WidgetMac.mm b/Source/WebCore/platform/mac/WidgetMac.mm index 96bcde2..f75faaa 100644 --- a/Source/WebCore/platform/mac/WidgetMac.mm +++ b/Source/WebCore/platform/mac/WidgetMac.mm @@ -115,10 +115,15 @@ void Widget::setFocus(bool focused) BEGIN_BLOCK_OBJC_EXCEPTIONS; + // If there's no platformWidget, WK2 is running. The focus() method needs to be used + // to bring focus to the right view on the UIProcess side. NSView *view = [platformWidget() _webcore_effectiveFirstResponder]; - if (Page* page = frame->page()) - page->chrome()->focusNSView(view); - + if (Page* page = frame->page()) { + if (!platformWidget()) + page->chrome()->focus(); + else + page->chrome()->focusNSView(view); + } END_BLOCK_OBJC_EXCEPTIONS; } diff --git a/Source/WebCore/platform/mock/GeolocationClientMock.cpp b/Source/WebCore/platform/mock/GeolocationClientMock.cpp index 5255b34..d067c8a 100644 --- a/Source/WebCore/platform/mock/GeolocationClientMock.cpp +++ b/Source/WebCore/platform/mock/GeolocationClientMock.cpp @@ -79,6 +79,11 @@ void GeolocationClientMock::setPermission(bool allowed) asyncUpdatePermission(); } +int GeolocationClientMock::numberOfPendingPermissionRequests() const +{ + return m_pendingPermission.size(); +} + void GeolocationClientMock::requestPermission(Geolocation* geolocation) { m_pendingPermission.add(geolocation); diff --git a/Source/WebCore/platform/mock/GeolocationClientMock.h b/Source/WebCore/platform/mock/GeolocationClientMock.h index df35316..b400166 100644 --- a/Source/WebCore/platform/mock/GeolocationClientMock.h +++ b/Source/WebCore/platform/mock/GeolocationClientMock.h @@ -59,6 +59,7 @@ public: void setError(PassRefPtr<GeolocationError>); void setPosition(PassRefPtr<GeolocationPosition>); void setPermission(bool allowed); + int numberOfPendingPermissionRequests() const; // GeolocationClient virtual void geolocationDestroyed(); diff --git a/Source/WebCore/platform/network/BlobData.h b/Source/WebCore/platform/network/BlobData.h index c1f5522..f919d64 100644 --- a/Source/WebCore/platform/network/BlobData.h +++ b/Source/WebCore/platform/network/BlobData.h @@ -34,11 +34,11 @@ #include "KURL.h" #include "PlatformString.h" #include <wtf/Forward.h> -#include <wtf/ThreadSafeShared.h> +#include <wtf/ThreadSafeRefCounted.h> namespace WebCore { -class RawData : public ThreadSafeShared<RawData> { +class RawData : public ThreadSafeRefCounted<RawData> { public: static PassRefPtr<RawData> create() { diff --git a/Source/WebCore/platform/network/FormDataBuilder.cpp b/Source/WebCore/platform/network/FormDataBuilder.cpp index e973f99..3174614 100644 --- a/Source/WebCore/platform/network/FormDataBuilder.cpp +++ b/Source/WebCore/platform/network/FormDataBuilder.cpp @@ -32,6 +32,7 @@ #include <limits> #include <wtf/Assertions.h> +#include <wtf/HexNumber.h> #include <wtf/text/CString.h> #include <wtf/RandomNumber.h> @@ -192,8 +193,6 @@ void FormDataBuilder::addKeyValuePairAsFormData(Vector<char>& buffer, const CStr void FormDataBuilder::encodeStringAsFormData(Vector<char>& buffer, const CString& string) { - static const char hexDigits[17] = "0123456789ABCDEF"; - // Same safe characters as Netscape for compatibility. static const char safeCharacters[] = "-._*"; @@ -210,8 +209,7 @@ void FormDataBuilder::encodeStringAsFormData(Vector<char>& buffer, const CString append(buffer, "%0D%0A"); else if (c != '\r') { append(buffer, '%'); - append(buffer, hexDigits[c >> 4]); - append(buffer, hexDigits[c & 0xF]); + appendByteAsHex(c, buffer); } } } diff --git a/Source/WebCore/platform/network/ProtectionSpace.h b/Source/WebCore/platform/network/ProtectionSpace.h index deb59d2..87758e1 100644 --- a/Source/WebCore/platform/network/ProtectionSpace.h +++ b/Source/WebCore/platform/network/ProtectionSpace.h @@ -49,7 +49,7 @@ enum ProtectionSpaceAuthenticationScheme { ProtectionSpaceAuthenticationSchemeNegotiate = 6, ProtectionSpaceAuthenticationSchemeClientCertificateRequested = 7, ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested = 8, - ProtectionSpaceAuthenticationSchemeUnknown = 100, + ProtectionSpaceAuthenticationSchemeUnknown = 100 }; class ProtectionSpace { diff --git a/Source/WebCore/platform/network/ProtectionSpaceHash.h b/Source/WebCore/platform/network/ProtectionSpaceHash.h index 9934321..40eb9b6 100644 --- a/Source/WebCore/platform/network/ProtectionSpaceHash.h +++ b/Source/WebCore/platform/network/ProtectionSpaceHash.h @@ -46,7 +46,7 @@ struct ProtectionSpaceHash { // Ignore realm for proxies. if (protectionSpace.isProxy()) codeCount -= sizeof(hashCodes[0]); - return WTF::StringHasher::createBlobHash(hashCodes, codeCount); + return StringHasher::hashMemory(hashCodes, codeCount); } static bool equal(const ProtectionSpace& a, const ProtectionSpace& b) { return a == b; } diff --git a/Source/WebCore/platform/network/ResourceErrorBase.cpp b/Source/WebCore/platform/network/ResourceErrorBase.cpp index 42bc0de..e1d29e0 100644 --- a/Source/WebCore/platform/network/ResourceErrorBase.cpp +++ b/Source/WebCore/platform/network/ResourceErrorBase.cpp @@ -42,6 +42,7 @@ ResourceError ResourceErrorBase::copy() const errorCopy.m_localizedDescription = m_localizedDescription.crossThreadString(); errorCopy.m_isNull = m_isNull; errorCopy.m_isCancellation = m_isCancellation; + platformCopy(errorCopy); return errorCopy; } diff --git a/Source/WebCore/platform/network/ResourceErrorBase.h b/Source/WebCore/platform/network/ResourceErrorBase.h index a6b7c69..2d7be70 100644 --- a/Source/WebCore/platform/network/ResourceErrorBase.h +++ b/Source/WebCore/platform/network/ResourceErrorBase.h @@ -74,6 +74,9 @@ protected: // The ResourceError subclass may "shadow" this method to lazily initialize platform specific fields void platformLazyInit() {} + // The ResourceError subclass may "shadow" this method to copy platform specific fields + void platformCopy(ResourceError&) const {} + // The ResourceError subclass may "shadow" this method to compare platform specific fields static bool platformCompare(const ResourceError&, const ResourceError&) { return true; } diff --git a/Source/WebCore/platform/network/ResourceHandleClient.h b/Source/WebCore/platform/network/ResourceHandleClient.h index d9350ee..e92b376 100644 --- a/Source/WebCore/platform/network/ResourceHandleClient.h +++ b/Source/WebCore/platform/network/ResourceHandleClient.h @@ -59,7 +59,7 @@ namespace WebCore { enum CacheStoragePolicy { StorageAllowed, StorageAllowedInMemoryOnly, - StorageNotAllowed, + StorageNotAllowed }; class ResourceHandleClient { @@ -78,6 +78,11 @@ namespace WebCore { virtual void wasBlocked(ResourceHandle*) { } virtual void cannotShowURL(ResourceHandle*) { } +#if HAVE(CFNETWORK_DATA_ARRAY_CALLBACK) + virtual bool supportsDataArray() { return false; } + virtual void didReceiveDataArray(ResourceHandle*, CFArrayRef) { } +#endif + virtual void willCacheResponse(ResourceHandle*, CacheStoragePolicy&) { } virtual bool shouldUseCredentialStorage(ResourceHandle*) { return false; } diff --git a/Source/WebCore/platform/network/ResourceRequestBase.h b/Source/WebCore/platform/network/ResourceRequestBase.h index ec7e32a..31a1e69 100644 --- a/Source/WebCore/platform/network/ResourceRequestBase.h +++ b/Source/WebCore/platform/network/ResourceRequestBase.h @@ -41,7 +41,7 @@ namespace WebCore { UseProtocolCachePolicy, // normal load ReloadIgnoringCacheData, // reload ReturnCacheDataElseLoad, // back/forward or encoding change - allow stale data - ReturnCacheDataDontLoad, // results of a post - allow stale data and only use cache + ReturnCacheDataDontLoad // results of a post - allow stale data and only use cache }; class ResourceRequest; diff --git a/Source/WebCore/platform/network/cf/CookieStorageCFNet.cpp b/Source/WebCore/platform/network/cf/CookieStorageCFNet.cpp index c2a5691..2eac3f6 100644 --- a/Source/WebCore/platform/network/cf/CookieStorageCFNet.cpp +++ b/Source/WebCore/platform/network/cf/CookieStorageCFNet.cpp @@ -42,7 +42,7 @@ namespace WebCore { -static RetainPtr<CFHTTPCookieStorageRef>& privateBrowsingCookieStorage() +static RetainPtr<CFHTTPCookieStorageRef>& privateCookieStorage() { DEFINE_STATIC_LOCAL(RetainPtr<CFHTTPCookieStorageRef>, cookieStorage, ()); return cookieStorage; @@ -52,16 +52,21 @@ CFHTTPCookieStorageRef currentCookieStorage() { ASSERT(isMainThread()); - if (CFHTTPCookieStorageRef privateCookieStorage = privateBrowsingCookieStorage().get()) - return privateCookieStorage; + if (CFHTTPCookieStorageRef cookieStorage = privateCookieStorage().get()) + return cookieStorage; return wkGetDefaultHTTPCookieStorage(); } +CFHTTPCookieStorageRef privateBrowsingCookieStorage() +{ + return privateCookieStorage().get(); +} + void setCurrentCookieStorage(CFHTTPCookieStorageRef cookieStorage) { ASSERT(isMainThread()); - privateBrowsingCookieStorage().adoptCF(cookieStorage); + privateCookieStorage().adoptCF(cookieStorage); } void setCookieStoragePrivateBrowsingEnabled(bool enabled) @@ -69,15 +74,21 @@ void setCookieStoragePrivateBrowsingEnabled(bool enabled) ASSERT(isMainThread()); if (!enabled) { - privateBrowsingCookieStorage() = nullptr; + privateCookieStorage() = nullptr; return; } #if USE(CFURLSTORAGESESSIONS) - privateBrowsingCookieStorage().adoptCF(wkCreatePrivateInMemoryHTTPCookieStorage(ResourceHandle::privateBrowsingStorageSession())); -#else - privateBrowsingCookieStorage().adoptCF(wkCreatePrivateInMemoryHTTPCookieStorage(0)); + if (CFURLStorageSessionRef privateStorageSession = ResourceHandle::privateBrowsingStorageSession()) + privateCookieStorage().adoptCF(wkCopyHTTPCookieStorage(privateStorageSession)); + else #endif + privateCookieStorage().adoptCF(wkCreateInMemoryHTTPCookieStorage()); +} + +CFHTTPCookieStorageRef defaultCookieStorage() +{ + return wkGetDefaultHTTPCookieStorage(); } static void notifyCookiesChangedOnMainThread(void* context) diff --git a/Source/WebCore/platform/network/cf/CookieStorageCFNet.h b/Source/WebCore/platform/network/cf/CookieStorageCFNet.h index 0167587..d33c76e 100644 --- a/Source/WebCore/platform/network/cf/CookieStorageCFNet.h +++ b/Source/WebCore/platform/network/cf/CookieStorageCFNet.h @@ -33,6 +33,8 @@ typedef struct OpaqueCFHTTPCookieStorage* CFHTTPCookieStorageRef; namespace WebCore { CFHTTPCookieStorageRef currentCookieStorage(); + CFHTTPCookieStorageRef defaultCookieStorage(); + CFHTTPCookieStorageRef privateBrowsingCookieStorage(); // Needed for WebKit1 API only. void setCurrentCookieStorage(CFHTTPCookieStorageRef cookieStorage); diff --git a/Source/WebCore/platform/network/cf/LoaderRunLoopCF.h b/Source/WebCore/platform/network/cf/LoaderRunLoopCF.h index e0d3ba4..272acf9 100644 --- a/Source/WebCore/platform/network/cf/LoaderRunLoopCF.h +++ b/Source/WebCore/platform/network/cf/LoaderRunLoopCF.h @@ -29,7 +29,7 @@ #if USE(CFNETWORK) #if !PLATFORM(WIN) -#error This code is not needed on platforms other than Windows, because main thread's CFRunLoop can be used. +#error This code is not needed on platforms other than Windows, because the CFRunLoop from the main thread can be used. #endif typedef struct __CFRunLoop* CFRunLoopRef; diff --git a/Source/WebCore/platform/network/cf/ResourceError.h b/Source/WebCore/platform/network/cf/ResourceError.h index aae9a4a..d36903f 100644 --- a/Source/WebCore/platform/network/cf/ResourceError.h +++ b/Source/WebCore/platform/network/cf/ResourceError.h @@ -32,6 +32,7 @@ #if USE(CFNETWORK) #include <CoreFoundation/CFStream.h> #else + #ifdef __OBJC__ @class NSError; #else @@ -54,38 +55,38 @@ public: { } -#if USE(CFNETWORK) - ResourceError(CFStreamError error); - - ResourceError(CFErrorRef error) - : m_dataIsUpToDate(false) - , m_platformError(error) - { - m_isNull = !error; - } + ResourceError(CFErrorRef error); + CFErrorRef cfError() const; operator CFErrorRef() const; + +#if USE(CFNETWORK) +#if PLATFORM(WIN) + ResourceError(const String& domain, int errorCode, const String& failingURL, const String& localizedDescription, CFDataRef certificate); + PCCERT_CONTEXT certificate() const; +#endif + ResourceError(CFStreamError error); + CFStreamError cfStreamError() const; operator CFStreamError() const; #else - ResourceError(NSError* error) - : m_dataIsUpToDate(false) - , m_platformError(error) - { - m_isNull = !error; - } - - operator NSError*() const; + ResourceError(NSError *); + NSError *nsError() const; + operator NSError *() const; #endif private: friend class ResourceErrorBase; void platformLazyInit(); + void platformCopy(ResourceError&) const; static bool platformCompare(const ResourceError& a, const ResourceError& b); bool m_dataIsUpToDate; #if USE(CFNETWORK) mutable RetainPtr<CFErrorRef> m_platformError; +#if PLATFORM(WIN) + RetainPtr<CFDataRef> m_certificate; +#endif #else mutable RetainPtr<NSError> m_platformError; #endif diff --git a/Source/WebCore/platform/network/cf/ResourceErrorCF.cpp b/Source/WebCore/platform/network/cf/ResourceErrorCF.cpp index 1eba97e..556ad6e 100644 --- a/Source/WebCore/platform/network/cf/ResourceErrorCF.cpp +++ b/Source/WebCore/platform/network/cf/ResourceErrorCF.cpp @@ -24,44 +24,46 @@ */ #include "config.h" -#include "KURL.h" #include "ResourceError.h" #if USE(CFNETWORK) -// FIXME: Once <rdar://problem/5050881> is fixed in open source we -// can remove this extern "C" -extern "C" { -#include <CFNetwork/CFNetworkErrors.h> -} - +#include "KURL.h" #include <CoreFoundation/CFError.h> +#include <CFNetwork/CFNetworkErrors.h> +#if PLATFORM(WIN) +#include <WebKitSystemInterface/WebKitSystemInterface.h> +#endif #include <WTF/RetainPtr.h> namespace WebCore { -const CFStringRef failingURLStringKey = CFSTR("NSErrorFailingURLStringKey"); -const CFStringRef failingURLKey = CFSTR("NSErrorFailingURLKey"); +ResourceError::ResourceError(CFErrorRef cfError) + : m_dataIsUpToDate(false) + , m_platformError(cfError) +{ + m_isNull = !cfError; +} -// FIXME: Once <rdar://problem/5050841> is fixed we can remove this constructor. -ResourceError::ResourceError(CFStreamError error) - : m_dataIsUpToDate(true) +#if PLATFORM(WIN) +ResourceError::ResourceError(const String& domain, int errorCode, const String& failingURL, const String& localizedDescription, CFDataRef certificate) + : ResourceErrorBase(domain, errorCode, failingURL, localizedDescription) + , m_dataIsUpToDate(true) + , m_certificate(certificate) { - m_isNull = false; - m_errorCode = error.error; +} - switch(error.domain) { - case kCFStreamErrorDomainCustom: - m_domain ="NSCustomErrorDomain"; - break; - case kCFStreamErrorDomainPOSIX: - m_domain = "NSPOSIXErrorDomain"; - break; - case kCFStreamErrorDomainMacOSStatus: - m_domain = "NSOSStatusErrorDomain"; - break; - } +PCCERT_CONTEXT ResourceError::certificate() const +{ + if (!m_certificate) + return 0; + + return reinterpret_cast<PCCERT_CONTEXT>(CFDataGetBytePtr(m_certificate.get())); } +#endif // PLATFORM(WIN) + +const CFStringRef failingURLStringKey = CFSTR("NSErrorFailingURLStringKey"); +const CFStringRef failingURLKey = CFSTR("NSErrorFailingURLKey"); void ResourceError::platformLazyInit() { @@ -101,23 +103,34 @@ void ResourceError::platformLazyInit() } } m_localizedDescription = (CFStringRef) CFDictionaryGetValue(userInfo.get(), kCFErrorLocalizedDescriptionKey); + +#if PLATFORM(WIN) + m_certificate = wkGetSSLPeerCertificateData(userInfo.get()); +#endif } m_dataIsUpToDate = true; } +void ResourceError::platformCopy(ResourceError& errorCopy) const +{ +#if PLATFORM(WIN) + errorCopy.m_certificate = m_certificate; +#endif +} + bool ResourceError::platformCompare(const ResourceError& a, const ResourceError& b) { - return (CFErrorRef)a == (CFErrorRef)b; + return a.cfError() == b.cfError(); } -ResourceError::operator CFErrorRef() const +CFErrorRef ResourceError::cfError() const { if (m_isNull) { ASSERT(!m_platformError); return 0; } - + if (!m_platformError) { RetainPtr<CFMutableDictionaryRef> userInfo(AdoptCF, CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); @@ -133,6 +146,11 @@ ResourceError::operator CFErrorRef() const CFDictionarySetValue(userInfo.get(), failingURLKey, url.get()); } +#if PLATFORM(WIN) + if (m_certificate) + wkSetSSLPeerCertificateData(userInfo.get(), m_certificate.get()); +#endif + RetainPtr<CFStringRef> domainString(AdoptCF, m_domain.createCFString()); m_platformError.adoptCF(CFErrorCreate(0, domainString.get(), m_errorCode, userInfo.get())); } @@ -140,7 +158,32 @@ ResourceError::operator CFErrorRef() const return m_platformError.get(); } -ResourceError::operator CFStreamError() const +ResourceError::operator CFErrorRef() const +{ + return cfError(); +} + +// FIXME: Once <rdar://problem/5050841> is fixed we can remove this constructor. +ResourceError::ResourceError(CFStreamError error) + : m_dataIsUpToDate(true) +{ + m_isNull = false; + m_errorCode = error.error; + + switch(error.domain) { + case kCFStreamErrorDomainCustom: + m_domain ="NSCustomErrorDomain"; + break; + case kCFStreamErrorDomainPOSIX: + m_domain = "NSPOSIXErrorDomain"; + break; + case kCFStreamErrorDomainMacOSStatus: + m_domain = "NSOSStatusErrorDomain"; + break; + } +} + +CFStreamError ResourceError::cfStreamError() const { lazyInit(); @@ -159,6 +202,11 @@ ResourceError::operator CFStreamError() const return result; } +ResourceError::operator CFStreamError() const +{ + return cfStreamError(); +} + } // namespace WebCore #endif // USE(CFNETWORK) diff --git a/Source/WebCore/platform/network/cf/ResourceRequestCFNet.h b/Source/WebCore/platform/network/cf/ResourceRequestCFNet.h index 09f4cea..271dcd2 100644 --- a/Source/WebCore/platform/network/cf/ResourceRequestCFNet.h +++ b/Source/WebCore/platform/network/cf/ResourceRequestCFNet.h @@ -50,6 +50,8 @@ inline ResourceLoadPriority mapHTTPPipeliningPriorityToResourceLoadPriority(int return ResourceLoadPriorityMedium; case 2: return ResourceLoadPriorityHigh; + case 3: + return ResourceLoadPriorityUnresolved; default: ASSERT_NOT_REACHED(); return ResourceLoadPriorityLowest; @@ -67,8 +69,7 @@ inline int mapResourceLoadPriorityToHTTPPipeliningPriority(ResourceLoadPriority case ResourceLoadPriorityHigh: return 2; case ResourceLoadPriorityUnresolved: - ASSERT_NOT_REACHED(); - return 0; + return 3; } ASSERT_NOT_REACHED(); diff --git a/Source/WebCore/platform/network/cf/ResourceResponse.h b/Source/WebCore/platform/network/cf/ResourceResponse.h index 33b6ddc..0551ede 100644 --- a/Source/WebCore/platform/network/cf/ResourceResponse.h +++ b/Source/WebCore/platform/network/cf/ResourceResponse.h @@ -98,9 +98,9 @@ private: static bool platformCompare(const ResourceResponse& a, const ResourceResponse& b); #if USE(CFNETWORK) - RetainPtr<CFURLResponseRef> m_cfResponse; + mutable RetainPtr<CFURLResponseRef> m_cfResponse; #else - RetainPtr<NSURLResponse> m_nsResponse; + mutable RetainPtr<NSURLResponse> m_nsResponse; #endif bool m_isUpToDate; }; diff --git a/Source/WebCore/platform/network/cf/ResourceResponseCFNet.cpp b/Source/WebCore/platform/network/cf/ResourceResponseCFNet.cpp index 167b079..d4a0b31 100644 --- a/Source/WebCore/platform/network/cf/ResourceResponseCFNet.cpp +++ b/Source/WebCore/platform/network/cf/ResourceResponseCFNet.cpp @@ -43,7 +43,14 @@ using namespace std; namespace WebCore { CFURLResponseRef ResourceResponse::cfURLResponse() const -{ +{ + if (!m_cfResponse && !m_isNull) { + RetainPtr<CFURLRef> url(AdoptCF, m_url.createCFURL()); + RetainPtr<CFStringRef> mimeType(AdoptCF, m_mimeType.createCFString()); + RetainPtr<CFStringRef> textEncodingName(AdoptCF, m_textEncodingName.createCFString()); + m_cfResponse.adoptCF(CFURLResponseCreate(0, url.get(), mimeType.get(), m_expectedContentLength, textEncodingName.get(), kCFURLCacheStorageAllowed)); + } + return m_cfResponse.get(); } diff --git a/Source/WebCore/platform/network/cf/SocketStreamHandle.h b/Source/WebCore/platform/network/cf/SocketStreamHandle.h index 5c1c6ff..4adee70 100644 --- a/Source/WebCore/platform/network/cf/SocketStreamHandle.h +++ b/Source/WebCore/platform/network/cf/SocketStreamHandle.h @@ -44,14 +44,14 @@ class AuthenticationChallenge; class Credential; class SocketStreamHandleClient; -class SocketStreamHandle : public RefCounted<SocketStreamHandle>, public SocketStreamHandleBase, public AuthenticationClient { +class SocketStreamHandle : public ThreadSafeRefCounted<SocketStreamHandle>, public SocketStreamHandleBase, public AuthenticationClient { public: static PassRefPtr<SocketStreamHandle> create(const KURL& url, SocketStreamHandleClient* client) { return adoptRef(new SocketStreamHandle(url, client)); } virtual ~SocketStreamHandle(); - using RefCounted<SocketStreamHandle>::ref; - using RefCounted<SocketStreamHandle>::deref; + using ThreadSafeRefCounted<SocketStreamHandle>::ref; + using ThreadSafeRefCounted<SocketStreamHandle>::deref; private: virtual int platformSend(const char* data, int length); diff --git a/Source/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp b/Source/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp index d5b1743..ee06c68 100644 --- a/Source/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp +++ b/Source/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp @@ -117,7 +117,7 @@ CFStringRef SocketStreamHandle::copyPACExecutionDescription(void*) struct MainThreadPACCallbackInfo { MainThreadPACCallbackInfo(SocketStreamHandle* handle, CFArrayRef proxyList) : handle(handle), proxyList(proxyList) { } - SocketStreamHandle* handle; + RefPtr<SocketStreamHandle> handle; CFArrayRef proxyList; }; @@ -436,7 +436,7 @@ CFStringRef SocketStreamHandle::copyCFStreamDescription(void* info) struct MainThreadEventCallbackInfo { MainThreadEventCallbackInfo(CFStreamEventType type, SocketStreamHandle* handle) : type(type), handle(handle) { } CFStreamEventType type; - SocketStreamHandle* handle; + RefPtr<SocketStreamHandle> handle; }; void SocketStreamHandle::readStreamCallback(CFReadStreamRef stream, CFStreamEventType type, void* clientCallBackInfo) diff --git a/Source/WebCore/platform/network/mac/CookieStorageMac.mm b/Source/WebCore/platform/network/mac/CookieStorageMac.mm index db64aae..2696188 100644 --- a/Source/WebCore/platform/network/mac/CookieStorageMac.mm +++ b/Source/WebCore/platform/network/mac/CookieStorageMac.mm @@ -92,7 +92,7 @@ void setCookieStoragePrivateBrowsingEnabled(bool enabled) return; if (enabled && ResourceHandle::privateBrowsingStorageSession()) { - privateBrowsingCookieStorage().adoptCF(wkCreatePrivateInMemoryHTTPCookieStorage(ResourceHandle::privateBrowsingStorageSession())); + privateBrowsingCookieStorage().adoptCF(wkCopyHTTPCookieStorage(ResourceHandle::privateBrowsingStorageSession())); // FIXME: When Private Browsing is enabled, the Private Browsing Cookie Storage should be // observed for changes, not the default Cookie Storage. @@ -116,7 +116,10 @@ void startObservingCookieChanges() void stopObservingCookieChanges() { - ASSERT(cookieStorageAdapter); + // cookieStorageAdapter can be nil here, if the WebProcess crashed and was restarted between + // when startObservingCookieChanges was called, and stopObservingCookieChanges is currently being called. + if (!cookieStorageAdapter) + return; [cookieStorageAdapter stopListeningForCookieChangeNotifications]; } diff --git a/Source/WebCore/platform/network/mac/FormDataStreamMac.mm b/Source/WebCore/platform/network/mac/FormDataStreamMac.mm index eb6f601..f094842 100644 --- a/Source/WebCore/platform/network/mac/FormDataStreamMac.mm +++ b/Source/WebCore/platform/network/mac/FormDataStreamMac.mm @@ -192,8 +192,8 @@ static bool advanceCurrentStream(FormStreamFields* form) } #if ENABLE(BLOB) if (nextInput.m_fileStart > 0) { - CFNumberRef position = CFNumberCreate(0, kCFNumberLongLongType, &nextInput.m_fileStart); - CFReadStreamSetProperty(form->currentStream, kCFStreamPropertyFileCurrentOffset, position); + RetainPtr<CFNumberRef> position(AdoptCF, CFNumberCreate(0, kCFNumberLongLongType, &nextInput.m_fileStart)); + CFReadStreamSetProperty(form->currentStream, kCFStreamPropertyFileCurrentOffset, position.get()); } form->currentStreamRangeLength = nextInput.m_fileLength; #endif diff --git a/Source/WebCore/platform/network/mac/ResourceErrorMac.mm b/Source/WebCore/platform/network/mac/ResourceErrorMac.mm index 275ca41..0bada1f 100644 --- a/Source/WebCore/platform/network/mac/ResourceErrorMac.mm +++ b/Source/WebCore/platform/network/mac/ResourceErrorMac.mm @@ -28,6 +28,7 @@ #import "BlockExceptions.h" #import "KURL.h" +#import <CoreFoundation/CFError.h> #import <Foundation/Foundation.h> @interface NSError (WebExtras) @@ -36,6 +37,20 @@ namespace WebCore { +ResourceError::ResourceError(NSError *nsError) + : m_dataIsUpToDate(false) + , m_platformError(nsError) +{ + m_isNull = !nsError; +} + +ResourceError::ResourceError(CFErrorRef cfError) + : m_dataIsUpToDate(false) + , m_platformError((NSError *)cfError) +{ + m_isNull = !cfError; +} + void ResourceError::platformLazyInit() { if (m_dataIsUpToDate) @@ -59,10 +74,10 @@ void ResourceError::platformLazyInit() bool ResourceError::platformCompare(const ResourceError& a, const ResourceError& b) { - return (NSError*)a == (NSError*)b; + return a.nsError() == b.nsError(); } -ResourceError::operator NSError*() const +NSError *ResourceError::nsError() const { if (m_isNull) { ASSERT(!m_platformError); @@ -87,4 +102,19 @@ ResourceError::operator NSError*() const return m_platformError.get(); } +ResourceError::operator NSError *() const +{ + return nsError(); +} + +CFErrorRef ResourceError::cfError() const +{ + return (CFErrorRef)nsError(); +} + +ResourceError::operator CFErrorRef() const +{ + return cfError(); +} + } // namespace WebCore diff --git a/Source/WebCore/platform/network/mac/ResourceHandleMac.mm b/Source/WebCore/platform/network/mac/ResourceHandleMac.mm index 96d561d..b2a89f0 100644 --- a/Source/WebCore/platform/network/mac/ResourceHandleMac.mm +++ b/Source/WebCore/platform/network/mac/ResourceHandleMac.mm @@ -886,7 +886,7 @@ String ResourceHandle::privateBrowsingStorageSessionIdentifierDefaultBase() // Avoid MIME type sniffing if the response comes back as 304 Not Modified. int statusCode = [r respondsToSelector:@selector(statusCode)] ? [(id)r statusCode] : 0; if (statusCode != 304) - [r adjustMIMETypeIfNecessary]; + adjustMIMETypeIfNecessary([r _CFURLResponse]); if ([m_handle->firstRequest().nsURLRequest() _propertyForKey:@"ForceHTMLMIMEType"]) [r _setMIMEType:@"text/html"]; @@ -910,9 +910,32 @@ String ResourceHandle::privateBrowsingStorageSessionIdentifierDefaultBase() m_handle->client()->didReceiveResponse(m_handle, r); } +#if HAVE(CFNETWORK_DATA_ARRAY_CALLBACK) +- (void)connection:(NSURLConnection *)connection didReceiveDataArray:(NSArray *)dataArray +{ + UNUSED_PARAM(connection); + LOG(Network, "Handle %p delegate connection:%p didReceiveDataArray:%p arraySize:%d", m_handle, connection, dataArray, [dataArray count]); + + if (!dataArray) + return; + + if (!m_handle || !m_handle->client()) + return; + + if (m_handle->client()->supportsDataArray()) + m_handle->client()->didReceiveDataArray(m_handle, reinterpret_cast<CFArrayRef>(dataArray)); + else { + for (NSData *data in dataArray) + m_handle->client()->didReceiveData(m_handle, static_cast<const char*>([data bytes]), [data length], static_cast<int>([data length])); + } + return; +} +#endif + - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived { UNUSED_PARAM(connection); + UNUSED_PARAM(lengthReceived); LOG(Network, "Handle %p delegate connection:%p didReceiveData:%p lengthReceived:%lld", m_handle, connection, data, lengthReceived); @@ -922,7 +945,10 @@ String ResourceHandle::privateBrowsingStorageSessionIdentifierDefaultBase() // However, with today's computers and networking speeds, this won't happen in practice. // Could be an issue with a giant local file. CallbackGuard guard; - m_handle->client()->didReceiveData(m_handle, (const char*)[data bytes], [data length], static_cast<int>(lengthReceived)); + // FIXME: https://bugs.webkit.org/show_bug.cgi?id=19793 + // -1 means we do not provide any data about transfer size to inspector so it would use + // Content-Length headers or content size to show transfer size. + m_handle->client()->didReceiveData(m_handle, (const char*)[data bytes], [data length], -1); } - (void)connection:(NSURLConnection *)connection willStopBufferingData:(NSData *)data diff --git a/Source/WebCore/platform/network/mac/WebCoreURLResponse.h b/Source/WebCore/platform/network/mac/WebCoreURLResponse.h index 8d43a21..d766b96 100644 --- a/Source/WebCore/platform/network/mac/WebCoreURLResponse.h +++ b/Source/WebCore/platform/network/mac/WebCoreURLResponse.h @@ -26,10 +26,15 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -@interface NSURLResponse (WebCoreURLResponse) --(void)adjustMIMETypeIfNecessary; -@end +typedef struct _CFURLResponse* CFURLResponseRef; +#ifdef __OBJC__ @interface NSURLResponse (Details) +- (CFURLResponseRef)_CFURLResponse; - (void)_setMIMEType:(NSString *)type; @end +#endif + +namespace WebCore { +void adjustMIMETypeIfNecessary(CFURLResponseRef); +} diff --git a/Source/WebCore/platform/network/mac/WebCoreURLResponse.mm b/Source/WebCore/platform/network/mac/WebCoreURLResponse.mm index e287e5f..0960492 100644 --- a/Source/WebCore/platform/network/mac/WebCoreURLResponse.mm +++ b/Source/WebCore/platform/network/mac/WebCoreURLResponse.mm @@ -30,308 +30,429 @@ #import "WebCoreURLResponse.h" #import "MIMETypeRegistry.h" -#import <objc/objc-class.h> +#import "WebCoreSystemInterface.h" #import <wtf/Assertions.h> #import <wtf/RetainPtr.h> -#ifndef BUILDING_ON_TIGER +namespace WebCore { + // <rdar://problem/5321972> Plain text document from HTTP server detected as application/octet-stream // When we sniff a resource as application/octet-stream but the http response headers had "text/plain", // we have a hard decision to make about which of the two generic MIME types to go with. // When the URL's extension is a known binary type, we'll go with application/octet-stream. // Otherwise, we'll trust the server. -static NSSet *createBinaryExtensionsSet() +static CFSetRef createBinaryExtensionsSet() { - return [[NSSet alloc] initWithObjects: - @"3g2", - @"3gp", - @"ai", - @"aif", - @"aifc", - @"aiff", - @"au", - @"avi", - @"bcpio", - @"bin", - @"bmp", - @"boz", - @"bpk", - @"bz", - @"bz2", - @"chm", - @"class", - @"com", - @"cpio", - @"dcr", - @"dir", - @"dist", - @"distz", - @"dll", - @"dmg", - @"dms", - @"doc", - @"dot", - @"dump", - @"dv", - @"dvi", - @"dxr", - @"elc", - @"eot", - @"eps", - @"exe", - @"fgd", - @"gif", - @"gtar", - @"h261", - @"h263", - @"h264", - @"ico", - @"ims", - @"indd", - @"iso", - @"jp2", - @"jpe", - @"jpeg", - @"jpg", - @"jpgm", - @"jpgv", - @"jpm", - @"kar", - @"kmz", - @"lha", - @"lrm", - @"lzh", - @"m1v", - @"m2a", - @"m2v", - @"m3a", - @"m3u", - @"m4a", - @"m4p", - @"m4v", - @"mdb", - @"mid", - @"midi", - @"mj2", - @"mjp2", - @"mov", - @"movie", - @"mp2", - @"mp2a", - @"mp3", - @"mp4", - @"mp4a", - @"mp4s", - @"mp4v", - @"mpe", - @"mpeg", - @"mpg", - @"mpg4", - @"mpga", - @"mpp", - @"mpt", - @"msi", - @"ogg", - @"otf", - @"pct", - @"pdf", - @"pfa", - @"pfb", - @"pic", - @"pict", - @"pkg", - @"png", - @"pot", - @"pps", - @"ppt", - @"ps", - @"psd", - @"qt", - @"qti", - @"qtif", - @"qwd", - @"qwt", - @"qxb", - @"qxd", - @"qxl", - @"qxp", - @"qxt", - @"ra", - @"ram", - @"rm", - @"rmi", - @"rmp", - @"scpt", - @"sit", - @"sitx", - @"snd", - @"so", - @"swf", - @"tar", - @"tif", - @"tiff", - @"ttf", - @"wav", - @"wcm", - @"wdb", - @"wks", - @"wm", - @"wma", - @"wmd", - @"wmf", - @"wmv", - @"wmx", - @"wmz", - @"wpd", - @"wpl", - @"wps", - @"wvx", - @"xla", - @"xlc", - @"xlm", - @"xls", - @"xlt", - @"xlw", - @"xps", - @"zip", - nil - ]; + CFStringRef extensions[] = { + CFSTR("3g2"), + CFSTR("3gp"), + CFSTR("ai"), + CFSTR("aif"), + CFSTR("aifc"), + CFSTR("aiff"), + CFSTR("au"), + CFSTR("avi"), + CFSTR("bcpio"), + CFSTR("bin"), + CFSTR("bmp"), + CFSTR("boz"), + CFSTR("bpk"), + CFSTR("bz"), + CFSTR("bz2"), + CFSTR("chm"), + CFSTR("class"), + CFSTR("com"), + CFSTR("cpio"), + CFSTR("dcr"), + CFSTR("dir"), + CFSTR("dist"), + CFSTR("distz"), + CFSTR("dll"), + CFSTR("dmg"), + CFSTR("dms"), + CFSTR("doc"), + CFSTR("dot"), + CFSTR("dump"), + CFSTR("dv"), + CFSTR("dvi"), + CFSTR("dxr"), + CFSTR("elc"), + CFSTR("eot"), + CFSTR("eps"), + CFSTR("exe"), + CFSTR("fgd"), + CFSTR("gif"), + CFSTR("gtar"), + CFSTR("h261"), + CFSTR("h263"), + CFSTR("h264"), + CFSTR("ico"), + CFSTR("ims"), + CFSTR("indd"), + CFSTR("iso"), + CFSTR("jp2"), + CFSTR("jpe"), + CFSTR("jpeg"), + CFSTR("jpg"), + CFSTR("jpgm"), + CFSTR("jpgv"), + CFSTR("jpm"), + CFSTR("kar"), + CFSTR("kmz"), + CFSTR("lha"), + CFSTR("lrm"), + CFSTR("lzh"), + CFSTR("m1v"), + CFSTR("m2a"), + CFSTR("m2v"), + CFSTR("m3a"), + CFSTR("m3u"), + CFSTR("m4a"), + CFSTR("m4p"), + CFSTR("m4v"), + CFSTR("mdb"), + CFSTR("mid"), + CFSTR("midi"), + CFSTR("mj2"), + CFSTR("mjp2"), + CFSTR("mov"), + CFSTR("movie"), + CFSTR("mp2"), + CFSTR("mp2a"), + CFSTR("mp3"), + CFSTR("mp4"), + CFSTR("mp4a"), + CFSTR("mp4s"), + CFSTR("mp4v"), + CFSTR("mpe"), + CFSTR("mpeg"), + CFSTR("mpg"), + CFSTR("mpg4"), + CFSTR("mpga"), + CFSTR("mpp"), + CFSTR("mpt"), + CFSTR("msi"), + CFSTR("ogg"), + CFSTR("otf"), + CFSTR("pct"), + CFSTR("pdf"), + CFSTR("pfa"), + CFSTR("pfb"), + CFSTR("pic"), + CFSTR("pict"), + CFSTR("pkg"), + CFSTR("png"), + CFSTR("pot"), + CFSTR("pps"), + CFSTR("ppt"), + CFSTR("ps"), + CFSTR("psd"), + CFSTR("qt"), + CFSTR("qti"), + CFSTR("qtif"), + CFSTR("qwd"), + CFSTR("qwt"), + CFSTR("qxb"), + CFSTR("qxd"), + CFSTR("qxl"), + CFSTR("qxp"), + CFSTR("qxt"), + CFSTR("ra"), + CFSTR("ram"), + CFSTR("rm"), + CFSTR("rmi"), + CFSTR("rmp"), + CFSTR("scpt"), + CFSTR("sit"), + CFSTR("sitx"), + CFSTR("snd"), + CFSTR("so"), + CFSTR("swf"), + CFSTR("tar"), + CFSTR("tif"), + CFSTR("tiff"), + CFSTR("ttf"), + CFSTR("wav"), + CFSTR("wcm"), + CFSTR("wdb"), + CFSTR("wks"), + CFSTR("wm"), + CFSTR("wma"), + CFSTR("wmd"), + CFSTR("wmf"), + CFSTR("wmv"), + CFSTR("wmx"), + CFSTR("wmz"), + CFSTR("wpd"), + CFSTR("wpl"), + CFSTR("wps"), + CFSTR("wvx"), + CFSTR("xla"), + CFSTR("xlc"), + CFSTR("xlm"), + CFSTR("xls"), + CFSTR("xlt"), + CFSTR("xlw"), + CFSTR("xps"), + CFSTR("zip") + }; + return CFSetCreate(kCFAllocatorDefault, (const void **)&extensions, sizeof(extensions)/sizeof(CFStringRef), &kCFTypeSetCallBacks); } -#endif // <rdar://problem/7007389> CoreTypes UTI map is missing 100+ file extensions that GateKeeper knew about // When we disabled content sniffing for file URLs we caused problems with these 100+ extensions that CoreTypes // doesn't know about. // If CoreTypes is ever brought up to speed we can remove this table and associated code. -static NSDictionary *createExtensionToMIMETypeMap() +static CFDictionaryRef createExtensionToMIMETypeMap() { - return [[NSDictionary alloc] initWithObjectsAndKeys: - @"application/postscript", @"ai", - @"text/plain", @"asc", - @"application/x-bcpio", @"bcpio", - @"image/bmp", @"bmp", - @"application/x-netcdf", @"cdf", - @"application/octet-stream", @"class", - @"application/x-gzip", @"cpgz", - @"application/x-cpio", @"cpio", - @"application/mac-compactpro", @"cpt", - @"application/x-csh", @"csh", - @"text/css", @"css", - @"application/x-director", @"dcr", - @"application/x-director", @"dir", - @"application/x-diskcopy", @"dmg", - @"application/octet-stream", @"dms", - @"application/x-dvi", @"dvi", - @"application/x-director", @"dxr", - @"application/postscript", @"eps", - @"text/x-setext", @"etx", - @"application/andrew-inset", @"ez", - @"application/vnd.fdf", @"fdf", - @"application/octet-stream", @"fla", - @"application/x-filemaker", @"fp", - @"application/x-filemaker", @"fp2", - @"application/x-filemaker", @"fp3", - @"application/x-filemaker", @"fp4", - @"application/x-filemaker", @"fp5", - @"application/x-filemaker", @"fp6", - @"application/x-hdf", @"hdf", - @"x-conference/x-cooltalk", @"ice", - @"image/x-icon", @"ico", - @"text/calendar", @"ics", - @"image/ief", @"ief", - @"model/iges", @"iges", - @"model/iges", @"igs", - @"application/octet-stream", @"iso", - @"text/html", @"jhtml", - @"application/x-latex", @"latex", - @"application/octet-stream", @"lha", - @"application/octet-stream", @"lzh", - @"audio/x-mpegurl", @"m3u", - @"audio/x-m4p", @"m4p", - @"image/x-macpaint", @"mac", - @"application/x-troff-man", @"man", - @"application/x-troff-me", @"me", - @"model/mesh", @"mesh", - @"application/vnd.mif", @"mif", - @"video/x-sgi-movie", @"movie", - @"audio/mpeg", @"mp2", - @"audio/mpeg", @"mpga", - @"application/x-troff-ms", @"ms", - @"model/mesh", @"msh", - @"video/vnd.mpegurl", @"mxu", - @"application/x-netcdf", @"nc", - @"application/oda", @"oda", - @"image/x-portable-bitmap", @"pbm", - @"image/x-pcx", @"pcx", - @"chemical/x-pdb", @"pdb", - @"image/x-portable-graymap", @"pgm", - @"application/x-chess-pgn", @"pgn", - @"audio/scpls", @"pls", - @"image/x-portable-anymap", @"pnm", - @"image/x-macpaint", @"pnt", - @"image/x-macpaint", @"pntg", - @"image/x-portable-pixmap", @"ppm", - @"image/x-cmu-raster", @"ras", - @"image/x-rgb", @"rgb", - @"application/x-troff", @"roff", - @"audio/x-pn-realaudio-plugin", @"rpm", - @"text/richtext", @"rtx", - @"text/sgml", @"sgm", - @"text/sgml", @"sgml", - @"application/x-sh", @"sh", - @"application/x-shar", @"shar", - @"model/mesh", @"silo", - @"application/x-koan", @"skd", - @"application/x-koan", @"skm", - @"application/x-koan", @"skp", - @"application/x-koan", @"skt", - @"application/x-diskcopy", @"smi", - @"application/octet-stream", @"so", - @"application/x-futuresplash", @"spl", - @"application/x-wais-source", @"src", - @"application/x-sv4cpio", @"sv4cpio", - @"application/x-sv4crc", @"sv4crc", - @"application/x-shockwave-flash", @"swf", - @"application/x-troff", @"t", - @"image/x-targa", @"targa", - @"application/x-tcl", @"tcl", - @"application/x-tex", @"tex", - @"application/x-texinfo", @"texi", - @"application/x-texinfo", @"texinfo", - @"application/x-gzip", @"tgz", - @"application/x-bittorrent", @"torrent", - @"application/x-troff", @"tr", - @"text/tab-separated-values", @"tsv", - @"application/x-ustar", @"ustar", - @"application/x-cdlink", @"vcd", - @"model/vrml", @"vrml", - @"image/vnd.wap.wbmp", @"wbmp", - @"application/vnd.wap.wbxml", @"wbxml", - @"application/x-webarchive", @"webarchive", - @"application/x-ms-wmd", @"wmd", - @"text/vnd.wap.wml", @"wml", - @"application/vnd.wap.wmlc", @"wmlc", - @"text/vnd.wap.wmlscript", @"wmls", - @"application/vnd.wap.wmlscriptc", @"wmlsc", - @"model/vrml", @"wrl", - @"application/vnd.adobe.xdp+xml", @"xdp", - @"application/vnd.adobe.xfd+xml", @"xfd", - @"application/vnd.adobe.xfdf", @"xfdf", - @"image/x-xpixmap", @"xpm", - @"text/xml", @"xsl", - @"image/x-xwindowdump", @"xwd", - @"chemical/x-xyz", @"xyz", - @"application/x-compress", @"z", - nil - ]; + CFStringRef keys[] = { + CFSTR("ai"), + CFSTR("asc"), + CFSTR("bcpio"), + CFSTR("bmp"), + CFSTR("cdf"), + CFSTR("class"), + CFSTR("cpgz"), + CFSTR("cpio"), + CFSTR("cpt"), + CFSTR("csh"), + CFSTR("css"), + CFSTR("dcr"), + CFSTR("dir"), + CFSTR("dmg"), + CFSTR("dms"), + CFSTR("dvi"), + CFSTR("dxr"), + CFSTR("eps"), + CFSTR("etx"), + CFSTR("ez"), + CFSTR("fdf"), + CFSTR("fla"), + CFSTR("fp"), + CFSTR("fp2"), + CFSTR("fp3"), + CFSTR("fp4"), + CFSTR("fp5"), + CFSTR("fp6"), + CFSTR("hdf"), + CFSTR("ice"), + CFSTR("ico"), + CFSTR("ics"), + CFSTR("ief"), + CFSTR("iges"), + CFSTR("igs"), + CFSTR("iso"), + CFSTR("jhtml"), + CFSTR("latex"), + CFSTR("lha"), + CFSTR("lzh"), + CFSTR("m3u"), + CFSTR("m4p"), + CFSTR("mac"), + CFSTR("man"), + CFSTR("me"), + CFSTR("mesh"), + CFSTR("mif"), + CFSTR("movie"), + CFSTR("mp2"), + CFSTR("mpga"), + CFSTR("ms"), + CFSTR("msh"), + CFSTR("mxu"), + CFSTR("nc"), + CFSTR("oda"), + CFSTR("pbm"), + CFSTR("pcx"), + CFSTR("pdb"), + CFSTR("pgm"), + CFSTR("pgn"), + CFSTR("pls"), + CFSTR("pnm"), + CFSTR("pnt"), + CFSTR("pntg"), + CFSTR("ppm"), + CFSTR("ras"), + CFSTR("rgb"), + CFSTR("roff"), + CFSTR("rpm"), + CFSTR("rtx"), + CFSTR("sgm"), + CFSTR("sgml"), + CFSTR("sh"), + CFSTR("shar"), + CFSTR("silo"), + CFSTR("skd"), + CFSTR("skm"), + CFSTR("skp"), + CFSTR("skt"), + CFSTR("smi"), + CFSTR("so"), + CFSTR("spl"), + CFSTR("src"), + CFSTR("sv4cpio"), + CFSTR("sv4crc"), + CFSTR("swf"), + CFSTR("t"), + CFSTR("targa"), + CFSTR("tcl"), + CFSTR("tex"), + CFSTR("texi"), + CFSTR("texinfo"), + CFSTR("tgz"), + CFSTR("torrent"), + CFSTR("tr"), + CFSTR("tsv"), + CFSTR("ustar"), + CFSTR("vcd"), + CFSTR("vrml"), + CFSTR("wbmp"), + CFSTR("wbxml"), + CFSTR("webarchive"), + CFSTR("wmd"), + CFSTR("wml"), + CFSTR("wmlc"), + CFSTR("wmls"), + CFSTR("wmlsc"), + CFSTR("wrl"), + CFSTR("xdp"), + CFSTR("xfd"), + CFSTR("xfdf"), + CFSTR("xpm"), + CFSTR("xsl"), + CFSTR("xwd"), + CFSTR("xyz"), + CFSTR("z") + }; + + CFStringRef values[] = { + CFSTR("application/postscript"), + CFSTR("text/plain"), + CFSTR("application/x-bcpio"), + CFSTR("image/bmp"), + CFSTR("application/x-netcdf"), + CFSTR("application/octet-stream"), + CFSTR("application/x-gzip"), + CFSTR("application/x-cpio"), + CFSTR("application/mac-compactpro"), + CFSTR("application/x-csh"), + CFSTR("text/css"), + CFSTR("application/x-director"), + CFSTR("application/x-director"), + CFSTR("application/x-diskcopy"), + CFSTR("application/octet-stream"), + CFSTR("application/x-dvi"), + CFSTR("application/x-director"), + CFSTR("application/postscript"), + CFSTR("text/x-setext"), + CFSTR("application/andrew-inset"), + CFSTR("application/vnd.fdf"), + CFSTR("application/octet-stream"), + CFSTR("application/x-filemaker"), + CFSTR("application/x-filemaker"), + CFSTR("application/x-filemaker"), + CFSTR("application/x-filemaker"), + CFSTR("application/x-filemaker"), + CFSTR("application/x-filemaker"), + CFSTR("application/x-hdf"), + CFSTR("x-conference/x-cooltalk"), + CFSTR("image/x-icon"), + CFSTR("text/calendar"), + CFSTR("image/ief"), + CFSTR("model/iges"), + CFSTR("model/iges"), + CFSTR("application/octet-stream"), + CFSTR("text/html"), + CFSTR("application/x-latex"), + CFSTR("application/octet-stream"), + CFSTR("application/octet-stream"), + CFSTR("audio/x-mpegurl"), + CFSTR("audio/x-m4p"), + CFSTR("image/x-macpaint"), + CFSTR("application/x-troff-man"), + CFSTR("application/x-troff-me"), + CFSTR("model/mesh"), + CFSTR("application/vnd.mif"), + CFSTR("video/x-sgi-movie"), + CFSTR("audio/mpeg"), + CFSTR("audio/mpeg"), + CFSTR("application/x-troff-ms"), + CFSTR("model/mesh"), + CFSTR("video/vnd.mpegurl"), + CFSTR("application/x-netcdf"), + CFSTR("application/oda"), + CFSTR("image/x-portable-bitmap"), + CFSTR("image/x-pcx"), + CFSTR("chemical/x-pdb"), + CFSTR("image/x-portable-graymap"), + CFSTR("application/x-chess-pgn"), + CFSTR("audio/scpls"), + CFSTR("image/x-portable-anymap"), + CFSTR("image/x-macpaint"), + CFSTR("image/x-macpaint"), + CFSTR("image/x-portable-pixmap"), + CFSTR("image/x-cmu-raster"), + CFSTR("image/x-rgb"), + CFSTR("application/x-troff"), + CFSTR("audio/x-pn-realaudio-plugin"), + CFSTR("text/richtext"), + CFSTR("text/sgml"), + CFSTR("text/sgml"), + CFSTR("application/x-sh"), + CFSTR("application/x-shar"), + CFSTR("model/mesh"), + CFSTR("application/x-koan"), + CFSTR("application/x-koan"), + CFSTR("application/x-koan"), + CFSTR("application/x-koan"), + CFSTR("application/x-diskcopy"), + CFSTR("application/octet-stream"), + CFSTR("application/x-futuresplash"), + CFSTR("application/x-wais-source"), + CFSTR("application/x-sv4cpio"), + CFSTR("application/x-sv4crc"), + CFSTR("application/x-shockwave-flash"), + CFSTR("application/x-troff"), + CFSTR("image/x-targa"), + CFSTR("application/x-tcl"), + CFSTR("application/x-tex"), + CFSTR("application/x-texinfo"), + CFSTR("application/x-texinfo"), + CFSTR("application/x-gzip"), + CFSTR("application/x-bittorrent"), + CFSTR("application/x-troff"), + CFSTR("text/tab-separated-values"), + CFSTR("application/x-ustar"), + CFSTR("application/x-cdlink"), + CFSTR("model/vrml"), + CFSTR("image/vnd.wap.wbmp"), + CFSTR("application/vnd.wap.wbxml"), + CFSTR("application/x-webarchive"), + CFSTR("application/x-ms-wmd"), + CFSTR("text/vnd.wap.wml"), + CFSTR("application/vnd.wap.wmlc"), + CFSTR("text/vnd.wap.wmlscript"), + CFSTR("application/vnd.wap.wmlscriptc"), + CFSTR("model/vrml"), + CFSTR("application/vnd.adobe.xdp+xml"), + CFSTR("application/vnd.adobe.xfd+xml"), + CFSTR("application/vnd.adobe.xfdf"), + CFSTR("image/x-xpixmap"), + CFSTR("text/xml"), + CFSTR("image/x-xwindowdump"), + CFSTR("chemical/x-xyz"), + CFSTR("application/x-compress") + }; + + ASSERT(sizeof(keys) == sizeof(values)); + return CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys, (const void**)&values, sizeof(keys)/sizeof(CFStringRef), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } -static RetainPtr<NSString> mimeTypeFromUTITree(CFStringRef uti) +static RetainPtr<CFStringRef> mimeTypeFromUTITree(CFStringRef uti) { // Check if this UTI has a MIME type. RetainPtr<CFStringRef> mimeType(AdoptCF, UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)); if (mimeType) - return (NSString *)mimeType.get(); + return mimeType.get(); // If not, walk the ancestory of this UTI via its "ConformsTo" tags and return the first MIME type we find. RetainPtr<CFDictionaryRef> decl(AdoptCF, UTTypeCopyDeclaration(uti)); @@ -353,7 +474,7 @@ static RetainPtr<NSString> mimeTypeFromUTITree(CFStringRef uti) if (CFGetTypeID(object) != CFStringGetTypeID()) continue; - if (RetainPtr<NSString> mimeType = mimeTypeFromUTITree((CFStringRef)object)) + if (RetainPtr<CFStringRef> mimeType = mimeTypeFromUTITree((CFStringRef)object)) return mimeType; } } @@ -361,33 +482,29 @@ static RetainPtr<NSString> mimeTypeFromUTITree(CFStringRef uti) return nil; } -@implementation NSURLResponse (WebCoreURLResponse) - --(void)adjustMIMETypeIfNecessary +void adjustMIMETypeIfNecessary(CFURLResponseRef cfResponse) { - RetainPtr<NSString> result = [self MIMEType]; - RetainPtr<NSString> originalResult = result; - -#ifdef BUILDING_ON_TIGER - // When content sniffing is disabled, Tiger's CFNetwork automatically returns application/octet-stream for certain - // extensions even when scouring the UTI maps would end up with a better result, so we'll give a chance for that to happen. - if ([[self URL] isFileURL] && [result.get() caseInsensitiveCompare:@"application/octet-stream"] == NSOrderedSame) - result = nil; -#endif + RetainPtr<CFStringRef> result = wkGetCFURLResponseMIMEType(cfResponse); + RetainPtr<CFStringRef> originalResult = result; if (!result) { - NSURL *url = [self URL]; - if ([url isFileURL]) { - if (NSString *extension = [[url path] pathExtension]) { + CFURLRef url = wkGetCFURLResponseURL(cfResponse); + NSURL *nsURL = (NSURL *)url; + if ([nsURL isFileURL]) { + RetainPtr<CFStringRef> extension(AdoptCF, CFURLCopyPathExtension(url)); + if (extension) { // <rdar://problem/7007389> CoreTypes UTI map is missing 100+ file extensions that GateKeeper knew about // When this radar is resolved, we can remove this file:// url specific code. - static NSDictionary *extensionMap = createExtensionToMIMETypeMap(); - result = [extensionMap objectForKey:[extension lowercaseString]]; + static CFDictionaryRef extensionMap = createExtensionToMIMETypeMap(); + CFMutableStringRef mutableExtension = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, extension.get()); + CFStringLowercase(mutableExtension, NULL); + extension.adoptCF(mutableExtension); + result = (CFStringRef) CFDictionaryGetValue(extensionMap, extension.get()); if (!result) { // If the Gatekeeper-based map doesn't have a MIME type, we'll try to figure out what it should be by // looking up the file extension in the UTI maps. - RetainPtr<CFStringRef> uti(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (CFStringRef)extension, 0)); + RetainPtr<CFStringRef> uti(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, extension.get(), 0)); result = mimeTypeFromUTITree(uti.get()); } } @@ -395,29 +512,33 @@ static RetainPtr<NSString> mimeTypeFromUTITree(CFStringRef uti) } if (!result) { - static NSString *defaultMIMETypeString = [(NSString *)WebCore::defaultMIMEType() retain]; + static CFStringRef defaultMIMETypeString = WebCore::defaultMIMEType().createCFString(); result = defaultMIMETypeString; } -#ifndef BUILDING_ON_TIGER // <rdar://problem/5321972> Plain text document from HTTP server detected as application/octet-stream // Make the best guess when deciding between "generic binary" and "generic text" using a table of known binary MIME types. - if ([result.get() isEqualToString:@"application/octet-stream"] && [self respondsToSelector:@selector(allHeaderFields)] && [[[self performSelector:@selector(allHeaderFields)] objectForKey:@"Content-Type"] hasPrefix:@"text/plain"]) { - static NSSet *binaryExtensions = createBinaryExtensionsSet(); - if (![binaryExtensions containsObject:[[[self suggestedFilename] pathExtension] lowercaseString]]) - result = @"text/plain"; + if (CFStringCompare(result.get(), CFSTR("application/octet-stream"), 0) == kCFCompareEqualTo) { + CFHTTPMessageRef message = wkGetCFURLResponseHTTPResponse(cfResponse); + if (message) { + RetainPtr<CFStringRef> contentType(AdoptCF, CFHTTPMessageCopyHeaderFieldValue(message, CFSTR("Content-Type"))); + if (contentType && CFStringHasPrefix(contentType.get(), CFSTR("text/plain"))) { + static CFSetRef binaryExtensions = createBinaryExtensionsSet(); + RetainPtr<NSString> suggestedFilename(AdoptNS, (NSString *)wkCopyCFURLResponseSuggestedFilename(cfResponse)); + if (!CFSetContainsValue(binaryExtensions, (CFStringRef) [[suggestedFilename.get() pathExtension] lowercaseString])) + result = CFSTR("text/plain"); + } + } } -#endif - #ifdef BUILDING_ON_LEOPARD // Workaround for <rdar://problem/5539824> - if ([result.get() isEqualToString:@"text/xml"]) - result = @"application/xml"; + if (CFStringCompare(result.get(), CFSTR("text/xml"), 0) == kCFCompareEqualTo) + result = CFSTR("application/xml"); #endif if (result != originalResult) - [self _setMIMEType:result.get()]; + wkSetCFURLResponseMIMEType(cfResponse, result.get()); } -@end +} diff --git a/Source/WebCore/platform/network/qt/DnsPrefetchHelper.h b/Source/WebCore/platform/network/qt/DnsPrefetchHelper.h index 892a3fb..4fcd19c 100644 --- a/Source/WebCore/platform/network/qt/DnsPrefetchHelper.h +++ b/Source/WebCore/platform/network/qt/DnsPrefetchHelper.h @@ -32,7 +32,7 @@ namespace WebCore { class DnsPrefetchHelper : public QObject { Q_OBJECT public: - DnsPrefetchHelper() : QObject(), currentLookups(0) {}; + DnsPrefetchHelper() : QObject(), currentLookups(0) { } public slots: void lookup(QString hostname) @@ -42,26 +42,8 @@ namespace WebCore { if (currentLookups >= 10) return; // do not launch more than 10 lookups at the same time -#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 3) currentLookups++; QHostInfo::lookupHost(hostname, this, SLOT(lookedUp(QHostInfo))); -#else - // This code is only needed for Qt versions that do not have - // the small Qt DNS cache yet. - - QTime* entryTime = lookupCache.object(hostname); - if (entryTime && entryTime->elapsed() > 300*1000) { - // delete knowledge about lookup if it is already 300 seconds old - lookupCache.remove(hostname); - } else if (!entryTime) { - // not in cache yet, can look it up - QTime *tmpTime = new QTime(); - *tmpTime = QTime::currentTime(); - lookupCache.insert(hostname, tmpTime); - currentLookups++; - QHostInfo::lookupHost(hostname, this, SLOT(lookedUp(QHostInfo))); - } -#endif } void lookedUp(const QHostInfo&) @@ -74,9 +56,6 @@ namespace WebCore { } protected: -#if QT_VERSION < QT_VERSION_CHECK(4, 6, 3) - QCache<QString, QTime> lookupCache; // 100 entries -#endif int currentLookups; }; diff --git a/Source/WebCore/platform/network/qt/NetworkStateNotifierPrivate.h b/Source/WebCore/platform/network/qt/NetworkStateNotifierPrivate.h index 766dc90..4b8252c 100644 --- a/Source/WebCore/platform/network/qt/NetworkStateNotifierPrivate.h +++ b/Source/WebCore/platform/network/qt/NetworkStateNotifierPrivate.h @@ -22,15 +22,9 @@ #include <QObject> -#if QT_VERSION < QT_VERSION_CHECK(4, 7, 0) -namespace QtMobility { -class QNetworkConfigurationManager; -} -#else QT_BEGIN_NAMESPACE class QNetworkConfigurationManager; QT_END_NAMESPACE -#endif namespace WebCore { @@ -46,11 +40,7 @@ public slots: void networkAccessPermissionChanged(bool); public: -#if QT_VERSION < QT_VERSION_CHECK(4, 7, 0) - QtMobility::QNetworkConfigurationManager* m_configurationManager; -#else QNetworkConfigurationManager* m_configurationManager; -#endif bool m_online; bool m_networkAccessAllowed; NetworkStateNotifier* m_notifier; diff --git a/Source/WebCore/platform/network/qt/NetworkStateNotifierQt.cpp b/Source/WebCore/platform/network/qt/NetworkStateNotifierQt.cpp index f3e7023..ced52eb 100644 --- a/Source/WebCore/platform/network/qt/NetworkStateNotifierQt.cpp +++ b/Source/WebCore/platform/network/qt/NetworkStateNotifierQt.cpp @@ -25,10 +25,6 @@ #include "NetworkStateNotifierPrivate.h" #include "qnetworkconfigmanager.h" -#if QT_VERSION < QT_VERSION_CHECK(4, 7, 0) -using namespace QtMobility; -#endif - namespace WebCore { NetworkStateNotifierPrivate::NetworkStateNotifierPrivate(NetworkStateNotifier* notifier) diff --git a/Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp b/Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp index 61fe96c..6e63145 100644 --- a/Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp +++ b/Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp @@ -41,21 +41,11 @@ #include <QDebug> #include <QCoreApplication> -// What type of connection should be used for the signals of the -// QNetworkReply? This depends on if Qt has a bugfix for this or not. -// It is fixed in Qt 4.6.3. See https://bugs.webkit.org/show_bug.cgi?id=32113 -// and https://bugs.webkit.org/show_bug.cgi?id=36755 -#if QT_VERSION > QT_VERSION_CHECK(4, 6, 2) -#define SIGNAL_CONN Qt::DirectConnection -#else -#define SIGNAL_CONN Qt::QueuedConnection -#endif - // In Qt 4.8, the attribute for sending a request synchronously will be made public, // for now, use this hackish solution for setting the internal attribute. const QNetworkRequest::Attribute gSynchronousNetworkRequestAttribute = static_cast<QNetworkRequest::Attribute>(QNetworkRequest::HttpPipeliningWasUsedAttribute + 7); -static const int gMaxRecursionLimit = 10; +static const int gMaxRedirections = 10; namespace WebCore { @@ -159,6 +149,86 @@ bool FormDataIODevice::isSequential() const return true; } +QNetworkReplyWrapper::QNetworkReplyWrapper(QNetworkReply* reply, QObject* parent) + : QObject(parent) + , m_reply(reply) +{ + 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())); +} + +QNetworkReplyWrapper::~QNetworkReplyWrapper() +{ + if (m_reply) + m_reply->deleteLater(); +} + +QNetworkReply* QNetworkReplyWrapper::release() +{ + if (!m_reply) + return 0; + + resetConnections(); + QNetworkReply* reply = m_reply; + m_reply = 0; + reply->setParent(0); + return reply; +} + +void QNetworkReplyWrapper::resetConnections() +{ + if (m_reply) + m_reply->disconnect(this); + QCoreApplication::removePostedEvents(this, QEvent::MetaCall); +} + +void QNetworkReplyWrapper::receiveMetaData() +{ + // This slot is only used to receive the first signal from the QNetworkReply object. + resetConnections(); + + m_redirectionTargetUrl = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); + if (m_redirectionTargetUrl.isValid()) { + emit metaDataChanged(); + emit finished(); + return; + } + + WTF::String contentType = m_reply->header(QNetworkRequest::ContentTypeHeader).toString(); + m_encoding = extractCharsetFromMediaType(contentType); + m_advertisedMimeType = extractMIMETypeFromMediaType(contentType); + + bool hasData = m_reply->bytesAvailable(); + bool isFinished = m_reply->isFinished(); + + 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())); + } + + emit metaDataChanged(); + + if (hasData) + emit readyRead(); + + if (isFinished) { + emit finished(); + return; + } + +} + +void QNetworkReplyWrapper::didReceiveFinished() +{ + // Disconnecting will make sure that nothing will happen after emitting the finished signal. + resetConnections(); + emit finished(); +} + String QNetworkReplyHandler::httpMethod() const { switch (m_method) { @@ -172,30 +242,24 @@ String QNetworkReplyHandler::httpMethod() const return "PUT"; case QNetworkAccessManager::DeleteOperation: return "DELETE"; -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) case QNetworkAccessManager::CustomOperation: return m_resourceHandle->firstRequest().httpMethod(); -#endif default: ASSERT_NOT_REACHED(); return "GET"; } } -QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode loadMode) +QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadType loadType, bool deferred) : QObject(0) - , m_reply(0) + , m_replyWrapper(0) , m_resourceHandle(handle) - , m_redirected(false) - , m_responseSent(false) - , m_responseContainsData(false) - , m_loadMode(loadMode) - , m_shouldStart(true) - , m_shouldFinish(false) - , m_shouldSendResponse(false) - , m_shouldForwardData(false) - , m_redirectionTries(gMaxRecursionLimit) + , m_loadType(loadType) + , m_deferred(deferred) + , m_redirectionTries(gMaxRedirections) { + resetState(); + const ResourceRequest &r = m_resourceHandle->firstRequest(); if (r.httpMethod() == "GET") @@ -208,13 +272,8 @@ QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode load m_method = QNetworkAccessManager::PutOperation; else if (r.httpMethod() == "DELETE") m_method = QNetworkAccessManager::DeleteOperation; -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) else m_method = QNetworkAccessManager::CustomOperation; -#else - else - m_method = QNetworkAccessManager::UnknownOperation; -#endif QObject* originatingObject = 0; if (m_resourceHandle->getInternal()->m_context) @@ -222,40 +281,58 @@ QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode load m_request = r.toNetworkRequest(originatingObject); - if (m_loadMode == LoadSynchronously) - m_request.setAttribute(gSynchronousNetworkRequestAttribute, true); - - if (m_loadMode == LoadNormal || m_loadMode == LoadSynchronously) + 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; + } +} - if (m_loadMode == LoadSynchronously) - m_loadMode = LoadNormal; +void QNetworkReplyHandler::setLoadingDeferred(bool deferred) +{ + m_deferred = deferred; + + if (!deferred) + resumeDeferredLoad(); } -void QNetworkReplyHandler::setLoadMode(LoadMode mode) +void QNetworkReplyHandler::resumeDeferredLoad() { - // https://bugs.webkit.org/show_bug.cgi?id=26556 - // We cannot call sendQueuedItems() from here, because the signal that - // caused us to get into deferred mode, might not be processed yet. - switch (mode) { - case LoadNormal: - m_loadMode = LoadResuming; - emit processQueuedItems(); - break; - case LoadDeferred: - m_loadMode = LoadDeferred; - break; - case LoadResuming: - Q_ASSERT(0); // should never happen - break; - }; + 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(); } void QNetworkReplyHandler::abort() { m_resourceHandle = 0; - if (m_reply) { - QNetworkReply* reply = release(); + if (QNetworkReply* reply = release()) { reply->abort(); reply->deleteLater(); } @@ -264,20 +341,16 @@ void QNetworkReplyHandler::abort() QNetworkReply* QNetworkReplyHandler::release() { - QNetworkReply* reply = m_reply; - if (m_reply) { - disconnect(m_reply, 0, this, 0); - // We have queued connections to the QNetworkReply. Make sure any - // posted meta call events that were the result of a signal emission - // don't reach the slots in our instance. - QCoreApplication::removePostedEvents(this, QEvent::MetaCall); - m_reply->setParent(0); - m_reply = 0; - } + if (!m_replyWrapper) + return 0; + + QNetworkReply* reply = m_replyWrapper->release(); + m_replyWrapper->deleteLater(); + m_replyWrapper = 0; return reply; } -static bool ignoreHttpError(QNetworkReply* reply, bool receivedData) +static bool shouldIgnoreHttpError(QNetworkReply* reply, bool receivedData) { int httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); @@ -292,66 +365,73 @@ static bool ignoreHttpError(QNetworkReply* reply, bool receivedData) void QNetworkReplyHandler::finish() { - m_shouldFinish = (m_loadMode != LoadNormal); - if (m_shouldFinish) + ASSERT(m_hasStarted); + + m_callFinishOnResume = m_deferred; + if (m_deferred) return; - if (!m_reply) + if (!m_replyWrapper || !m_replyWrapper->reply()) return; + sendResponseIfNeeded(); - if (!m_resourceHandle) + if (wasAborted()) return; + ResourceHandleClient* client = m_resourceHandle->client(); if (!client) { - m_reply->deleteLater(); - m_reply = 0; + m_replyWrapper->deleteLater(); + m_replyWrapper = 0; return; } - if (!m_redirected) { - if (!m_reply->error() || ignoreHttpError(m_reply, m_responseContainsData)) - client->didFinishLoading(m_resourceHandle, 0); - else { - QUrl url = m_reply->url(); - int httpStatusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - - if (httpStatusCode) { - ResourceError error("HTTP", httpStatusCode, url.toString(), m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString()); - client->didFail(m_resourceHandle, error); - } else { - ResourceError error("QtNetwork", m_reply->error(), url.toString(), m_reply->errorString()); - client->didFail(m_resourceHandle, error); - } - } - if (m_reply) { - m_reply->deleteLater(); - m_reply = 0; - } - } else { - if (m_reply) { - m_reply->deleteLater(); - m_reply = 0; - } + if (m_redirected) { resetState(); start(); + return; + } + + if (!m_replyWrapper->reply()->error() || shouldIgnoreHttpError(m_replyWrapper->reply(), m_responseContainsData)) + client->didFinishLoading(m_resourceHandle, 0); + else { + QUrl url = m_replyWrapper->reply()->url(); + int httpStatusCode = m_replyWrapper->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + if (httpStatusCode) { + ResourceError error("HTTP", httpStatusCode, url.toString(), m_replyWrapper->reply()->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString()); + client->didFail(m_resourceHandle, error); + } else { + ResourceError error("QtNetwork", m_replyWrapper->reply()->error(), url.toString(), m_replyWrapper->reply()->errorString()); + client->didFail(m_resourceHandle, error); + } + } + + if (m_replyWrapper) { + m_replyWrapper->deleteLater(); + m_replyWrapper = 0; } } void QNetworkReplyHandler::sendResponseIfNeeded() { - m_shouldSendResponse = (m_loadMode != LoadNormal); - if (m_shouldSendResponse) + ASSERT(m_hasStarted); + + m_callSendResponseIfNeededOnResume = m_deferred; + if (m_deferred) return; - if (!m_reply) + if (!m_replyWrapper || !m_replyWrapper->reply()) return; - if (m_reply->error() && !ignoreHttpError(m_reply, m_responseContainsData)) + if (m_replyWrapper->reply()->error() && !shouldIgnoreHttpError(m_replyWrapper->reply(), m_responseContainsData)) return; - if (m_responseSent || !m_resourceHandle) + if (wasAborted()) + return; + + if (m_responseSent) return; m_responseSent = true; @@ -359,18 +439,18 @@ void QNetworkReplyHandler::sendResponseIfNeeded() if (!client) return; - WTF::String contentType = m_reply->header(QNetworkRequest::ContentTypeHeader).toString(); + WTF::String contentType = m_replyWrapper->reply()->header(QNetworkRequest::ContentTypeHeader).toString(); WTF::String encoding = extractCharsetFromMediaType(contentType); WTF::String mimeType = extractMIMETypeFromMediaType(contentType); if (mimeType.isEmpty()) { // let's try to guess from the extension - mimeType = MIMETypeRegistry::getMIMETypeForPath(m_reply->url().path()); + mimeType = MIMETypeRegistry::getMIMETypeForPath(m_replyWrapper->reply()->url().path()); } - KURL url(m_reply->url()); + KURL url(m_replyWrapper->reply()->url()); ResourceResponse response(url, mimeType.lower(), - m_reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), + m_replyWrapper->reply()->header(QNetworkRequest::ContentLengthHeader).toLongLong(), encoding, String()); if (url.isLocalFile()) { @@ -379,10 +459,10 @@ void QNetworkReplyHandler::sendResponseIfNeeded() } // The status code is equal to 0 for protocols not in the HTTP family. - int statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + int statusCode = m_replyWrapper->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); if (url.protocolInHTTPFamily()) { - String suggestedFilename = filenameFromHTTPContentDisposition(QString::fromAscii(m_reply->rawHeader("Content-Disposition"))); + String suggestedFilename = filenameFromHTTPContentDisposition(QString::fromLatin1(m_replyWrapper->reply()->rawHeader("Content-Disposition"))); if (!suggestedFilename.isEmpty()) response.setSuggestedFilename(suggestedFilename); @@ -390,70 +470,79 @@ void QNetworkReplyHandler::sendResponseIfNeeded() response.setSuggestedFilename(url.lastPathComponent()); response.setHTTPStatusCode(statusCode); - response.setHTTPStatusText(m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray().constData()); + response.setHTTPStatusText(m_replyWrapper->reply()->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray().constData()); // Add remaining headers. -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) - foreach (const QNetworkReply::RawHeaderPair& pair, m_reply->rawHeaderPairs()) - response.setHTTPHeaderField(QString::fromAscii(pair.first), QString::fromAscii(pair.second)); -#else - foreach (const QByteArray& headerName, m_reply->rawHeaderList()) - response.setHTTPHeaderField(QString::fromAscii(headerName), QString::fromAscii(m_reply->rawHeader(headerName))); -#endif + foreach (const QNetworkReply::RawHeaderPair& pair, m_replyWrapper->reply()->rawHeaderPairs()) + response.setHTTPHeaderField(QString::fromLatin1(pair.first), QString::fromLatin1(pair.second)); } - QUrl redirection = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); + QUrl redirection = m_replyWrapper->reply()->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); if (redirection.isValid()) { - QUrl newUrl = m_reply->url().resolved(redirection); + redirect(response, redirection); + return; + } - m_redirectionTries--; - if (m_redirectionTries == 0) { // 10 or more redirections to the same url is considered infinite recursion - ResourceError error(newUrl.host(), 400 /*bad request*/, - newUrl.toString(), - QCoreApplication::translate("QWebPage", "Redirection limit reached")); - client->didFail(m_resourceHandle, error); - return; - } - m_redirected = true; + client->didReceiveResponse(m_resourceHandle, response); +} +void QNetworkReplyHandler::redirect(ResourceResponse& response, const QUrl& redirection) +{ + QUrl newUrl = m_replyWrapper->reply()->url().resolved(redirection); - // Status Code 301 (Moved Permanently), 302 (Moved Temporarily), 303 (See Other): - // - If original request is POST convert to GET and redirect automatically - // Status Code 307 (Temporary Redirect) and all other redirect status codes: - // - Use the HTTP method from the previous request - if ((statusCode >= 301 && statusCode <= 303) && m_resourceHandle->firstRequest().httpMethod() == "POST") - m_method = QNetworkAccessManager::GetOperation; + ResourceHandleClient* client = m_resourceHandle->client(); + ASSERT(client); + + int statusCode = m_replyWrapper->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - ResourceRequest newRequest = m_resourceHandle->firstRequest(); - newRequest.setHTTPMethod(httpMethod()); - newRequest.setURL(newUrl); + m_redirectionTries--; + if (!m_redirectionTries) { + ResourceError error(newUrl.host(), 400 /*bad request*/, + newUrl.toString(), + QCoreApplication::translate("QWebPage", "Redirection limit reached")); + client->didFail(m_resourceHandle, error); + return; + } + m_redirected = true; - // Should not set Referer after a redirect from a secure resource to non-secure one. - if (!newRequest.url().protocolIs("https") && protocolIs(newRequest.httpReferrer(), "https")) - newRequest.clearHTTPReferrer(); + // Status Code 301 (Moved Permanently), 302 (Moved Temporarily), 303 (See Other): + // - If original request is POST convert to GET and redirect automatically + // Status Code 307 (Temporary Redirect) and all other redirect status codes: + // - Use the HTTP method from the previous request + if ((statusCode >= 301 && statusCode <= 303) && m_resourceHandle->firstRequest().httpMethod() == "POST") + m_method = QNetworkAccessManager::GetOperation; - client->willSendRequest(m_resourceHandle, newRequest, response); - if (!m_resourceHandle) // network error did cancel the request - return; + ResourceRequest newRequest = m_resourceHandle->firstRequest(); + newRequest.setHTTPMethod(httpMethod()); + newRequest.setURL(newUrl); - QObject* originatingObject = 0; - if (m_resourceHandle->getInternal()->m_context) - originatingObject = m_resourceHandle->getInternal()->m_context->originatingObject(); + // Should not set Referer after a redirect from a secure resource to non-secure one. + if (!newRequest.url().protocolIs("https") && protocolIs(newRequest.httpReferrer(), "https")) + newRequest.clearHTTPReferrer(); - m_request = newRequest.toNetworkRequest(originatingObject); + client->willSendRequest(m_resourceHandle, newRequest, response); + if (wasAborted()) // Network error cancelled the request. return; - } - client->didReceiveResponse(m_resourceHandle, response); + QObject* originatingObject = 0; + if (m_resourceHandle->getInternal()->m_context) + originatingObject = m_resourceHandle->getInternal()->m_context->originatingObject(); + + m_request = newRequest.toNetworkRequest(originatingObject); } void QNetworkReplyHandler::forwardData() { - m_shouldForwardData = (m_loadMode != LoadNormal); - if (m_shouldForwardData) + ASSERT(m_hasStarted); + + m_callForwardDataOnResume = m_deferred; + if (m_deferred) return; - if (m_reply->bytesAvailable()) + if (!m_replyWrapper || !m_replyWrapper->reply()) + return; + + if (m_replyWrapper->reply()->bytesAvailable()) m_responseContainsData = true; sendResponseIfNeeded(); @@ -462,22 +551,25 @@ void QNetworkReplyHandler::forwardData() if (m_redirected) return; - if (!m_resourceHandle) + if (wasAborted()) return; - QByteArray data = m_reply->read(m_reply->bytesAvailable()); + QByteArray data = m_replyWrapper->reply()->read(m_replyWrapper->reply()->bytesAvailable()); ResourceHandleClient* client = m_resourceHandle->client(); if (!client) return; + // FIXME: https://bugs.webkit.org/show_bug.cgi?id=19793 + // -1 means we do not provide any data about transfer size to inspector so it would use + // Content-Length headers or content size to show transfer size. if (!data.isEmpty()) - client->didReceiveData(m_resourceHandle, data.constData(), data.length(), data.length() /*FixMe*/); + client->didReceiveData(m_resourceHandle, data.constData(), data.length(), -1); } void QNetworkReplyHandler::uploadProgress(qint64 bytesSent, qint64 bytesTotal) { - if (!m_resourceHandle) + if (wasAborted()) return; ResourceHandleClient* client = m_resourceHandle->client(); @@ -487,9 +579,10 @@ void QNetworkReplyHandler::uploadProgress(qint64 bytesSent, qint64 bytesTotal) client->didSendData(m_resourceHandle, bytesSent, bytesTotal); } -void QNetworkReplyHandler::start() +QNetworkReply* QNetworkReplyHandler::sendNetworkRequest() { - m_shouldStart = false; + if (m_loadType == SynchronousLoad) + m_request.setAttribute(gSynchronousNetworkRequestAttribute, true); ResourceHandleInternal* d = m_resourceHandle->getInternal(); @@ -498,7 +591,7 @@ void QNetworkReplyHandler::start() manager = d->m_context->networkAccessManager(); if (!manager) - return; + return 0; const QUrl url = m_request.url(); const QString scheme = url.scheme(); @@ -511,108 +604,61 @@ void QNetworkReplyHandler::start() switch (m_method) { case QNetworkAccessManager::GetOperation: - m_reply = manager->get(m_request); - break; + return manager->get(m_request); case QNetworkAccessManager::PostOperation: { - FormDataIODevice* postDevice = new FormDataIODevice(d->m_firstRequest.httpBody()); + FormDataIODevice* postDevice = new FormDataIODevice(d->m_firstRequest.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)); - m_reply = manager->post(m_request, postDevice); - postDevice->setParent(m_reply); - break; + QNetworkReply* result = manager->post(m_request, postDevice); + postDevice->setParent(result); + return result; } case QNetworkAccessManager::HeadOperation: - m_reply = manager->head(m_request); - break; + return manager->head(m_request); case QNetworkAccessManager::PutOperation: { - FormDataIODevice* putDevice = new FormDataIODevice(d->m_firstRequest.httpBody()); + FormDataIODevice* putDevice = new FormDataIODevice(d->m_firstRequest.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)); - m_reply = manager->put(m_request, putDevice); - putDevice->setParent(m_reply); - break; + QNetworkReply* result = manager->put(m_request, putDevice); + putDevice->setParent(result); + return result; } case QNetworkAccessManager::DeleteOperation: { - m_reply = manager->deleteResource(m_request); - break; + return manager->deleteResource(m_request); } -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) case QNetworkAccessManager::CustomOperation: - m_reply = manager->sendCustomRequest(m_request, m_resourceHandle->firstRequest().httpMethod().latin1().data()); - break; -#endif - case QNetworkAccessManager::UnknownOperation: { - m_reply = 0; - ResourceHandleClient* client = m_resourceHandle->client(); - if (client) { - ResourceError error(url.host(), 400 /*bad request*/, - url.toString(), - QCoreApplication::translate("QWebPage", "Bad HTTP request")); - client->didFail(m_resourceHandle, error); - } - return; - } - } - - m_reply->setParent(this); - - if (m_loadMode == LoadSynchronously && m_reply->isFinished()) { - // If supported, a synchronous request will be finished at this point, no need to hook up the signals. - return; - } - - connect(m_reply, SIGNAL(finished()), - this, SLOT(finish()), SIGNAL_CONN); - - // For http(s) we know that the headers are complete upon metaDataChanged() emission, so we - // can send the response as early as possible - if (scheme == QLatin1String("http") || scheme == QLatin1String("https")) - connect(m_reply, SIGNAL(metaDataChanged()), - this, SLOT(sendResponseIfNeeded()), SIGNAL_CONN); - - connect(m_reply, SIGNAL(readyRead()), - this, SLOT(forwardData()), SIGNAL_CONN); - - if (m_resourceHandle->firstRequest().reportUploadProgress()) { - connect(m_reply, SIGNAL(uploadProgress(qint64, qint64)), - this, SLOT(uploadProgress(qint64, qint64)), SIGNAL_CONN); + return manager->sendCustomRequest(m_request, m_resourceHandle->firstRequest().httpMethod().latin1().data()); + case QNetworkAccessManager::UnknownOperation: + ASSERT_NOT_REACHED(); + return 0; } - - // Make this a direct function call once we require 4.6.1+. - connect(this, SIGNAL(processQueuedItems()), - this, SLOT(sendQueuedItems()), SIGNAL_CONN); + return 0; } -void QNetworkReplyHandler::resetState() +void QNetworkReplyHandler::start() { - m_redirected = false; - m_responseSent = false; - m_responseContainsData = false; - m_shouldStart = true; - m_shouldFinish = false; - m_shouldSendResponse = false; - m_shouldForwardData = false; -} + ASSERT(!m_hasStarted); + m_hasStarted = true; -void QNetworkReplyHandler::sendQueuedItems() -{ - if (m_loadMode != LoadResuming) + QNetworkReply* reply = sendNetworkRequest(); + if (!reply) return; - m_loadMode = LoadNormal; - if (m_shouldStart) - start(); + m_replyWrapper = new QNetworkReplyWrapper(reply, this); - if (m_shouldSendResponse) - sendResponseIfNeeded(); + if (m_loadType == SynchronousLoad && m_replyWrapper->reply()->isFinished()) { + // If supported, a synchronous request will be finished at this point, no need to hook up the signals. + return; + } - if (m_shouldForwardData) - forwardData(); + 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_shouldFinish) - finish(); + 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 8c9bd08..61694d6 100644 --- a/Source/WebCore/platform/network/qt/QNetworkReplyHandler.h +++ b/Source/WebCore/platform/network/qt/QNetworkReplyHandler.h @@ -34,56 +34,90 @@ QT_END_NAMESPACE namespace WebCore { class ResourceHandle; +class ResourceResponse; + +class QNetworkReplyWrapper : public QObject { + Q_OBJECT +public: + QNetworkReplyWrapper(QNetworkReply*, QObject* parent = 0); + ~QNetworkReplyWrapper(); + + QNetworkReply* reply() const { return m_reply; } + QNetworkReply* release(); + + QUrl redirectionTargetUrl() const { return m_redirectionTargetUrl; } + QString encoding() const { return m_encoding; } + QString advertisedMimeType() const { return m_advertisedMimeType; } + +Q_SIGNALS: + void finished(); + void metaDataChanged(); + void readyRead(); + void uploadProgress(qint64 bytesSent, qint64 bytesTotal); + +private Q_SLOTS: + void receiveMetaData(); + void didReceiveFinished(); + +private: + void resetConnections(); + + QNetworkReply* m_reply; + QUrl m_redirectionTargetUrl; + + QString m_encoding; + QString m_advertisedMimeType; +}; class QNetworkReplyHandler : public QObject { Q_OBJECT public: - enum LoadMode { - LoadNormal, - LoadDeferred, - LoadResuming, - LoadSynchronously + enum LoadType { + AsynchronousLoad, + SynchronousLoad }; - QNetworkReplyHandler(ResourceHandle *handle, LoadMode); - void setLoadMode(LoadMode); + QNetworkReplyHandler(ResourceHandle*, LoadType, bool deferred = false); + void setLoadingDeferred(bool); - QNetworkReply* reply() const { return m_reply; } + QNetworkReply* reply() const { return m_replyWrapper ? m_replyWrapper->reply() : 0; } void abort(); QNetworkReply* release(); -signals: - void processQueuedItems(); - public slots: void finish(); void sendResponseIfNeeded(); void forwardData(); - void sendQueuedItems(); 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* m_reply; + QNetworkReplyWrapper* m_replyWrapper; ResourceHandle* m_resourceHandle; bool m_redirected; bool m_responseSent; bool m_responseContainsData; - LoadMode m_loadMode; + LoadType m_loadType; QNetworkAccessManager::Operation m_method; QNetworkRequest m_request; + bool m_deferred; + // defer state holding - bool m_shouldStart; - bool m_shouldFinish; - bool m_shouldSendResponse; - bool m_shouldForwardData; + bool m_hasStarted; + bool m_callFinishOnResume; + bool m_callSendResponseIfNeededOnResume; + bool m_callForwardDataOnResume; int m_redirectionTries; }; diff --git a/Source/WebCore/platform/network/qt/ResourceHandleQt.cpp b/Source/WebCore/platform/network/qt/ResourceHandleQt.cpp index cd17660..a6da432 100644 --- a/Source/WebCore/platform/network/qt/ResourceHandleQt.cpp +++ b/Source/WebCore/platform/network/qt/ResourceHandleQt.cpp @@ -42,9 +42,6 @@ #include "ResourceHandleInternal.h" #include "SharedBuffer.h" -// FIXME: WebCore including these headers from WebKit is a massive layering violation. -#include "qwebframe_p.h" - #include <QAbstractNetworkCache> #include <QCoreApplication> #include <QUrl> @@ -140,7 +137,7 @@ bool ResourceHandle::start(NetworkingContext* context) getInternal()->m_context = context; ResourceHandleInternal *d = getInternal(); - d->m_job = new QNetworkReplyHandler(this, QNetworkReplyHandler::LoadMode(d->m_defersLoading)); + d->m_job = new QNetworkReplyHandler(this, QNetworkReplyHandler::AsynchronousLoad, d->m_defersLoading); return true; } @@ -207,7 +204,7 @@ void ResourceHandle::loadResourceSynchronously(NetworkingContext* context, const d->m_firstRequest.setURL(urlWithCredentials); } d->m_context = context; - d->m_job = new QNetworkReplyHandler(handle.get(), QNetworkReplyHandler::LoadSynchronously); + 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. @@ -225,8 +222,9 @@ void ResourceHandle::loadResourceSynchronously(NetworkingContext* context, const void ResourceHandle::platformSetDefersLoading(bool defers) { - if (d->m_job) - d->m_job->setLoadMode(QNetworkReplyHandler::LoadMode(defers)); + if (!d->m_job) + return; + d->m_job->setLoadingDeferred(defers); } } // namespace WebCore diff --git a/Source/WebCore/platform/network/qt/ResourceRequestQt.cpp b/Source/WebCore/platform/network/qt/ResourceRequestQt.cpp index 7e162ed..498c90a 100644 --- a/Source/WebCore/platform/network/qt/ResourceRequestQt.cpp +++ b/Source/WebCore/platform/network/qt/ResourceRequestQt.cpp @@ -83,13 +83,11 @@ QNetworkRequest ResourceRequest::toNetworkRequest(QObject* originatingFrame) con break; } -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) if (!allowCookies()) { request.setAttribute(QNetworkRequest::CookieLoadControlAttribute, QNetworkRequest::Manual); request.setAttribute(QNetworkRequest::CookieSaveControlAttribute, QNetworkRequest::Manual); request.setAttribute(QNetworkRequest::AuthenticationReuseAttribute, QNetworkRequest::Manual); } -#endif return request; } diff --git a/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp b/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp index d410fa3..e5da0e3 100644 --- a/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp +++ b/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp @@ -364,7 +364,10 @@ static void gotChunkCallback(SoupMessage* msg, SoupBuffer* chunk, gpointer data) ASSERT(!d->m_response.isNull()); - client->didReceiveData(handle.get(), chunk->data, chunk->length, chunk->length); + // FIXME: https://bugs.webkit.org/show_bug.cgi?id=19793 + // -1 means we do not provide any data about transfer size to inspector so it would use + // Content-Length headers or content size to show transfer size. + client->didReceiveData(handle.get(), chunk->data, chunk->length, -1); } static SoupSession* createSoupSession() diff --git a/Source/WebCore/platform/network/win/ResourceHandleWin.cpp b/Source/WebCore/platform/network/win/ResourceHandleWin.cpp index f50540c..dc5adc8 100644 --- a/Source/WebCore/platform/network/win/ResourceHandleWin.cpp +++ b/Source/WebCore/platform/network/win/ResourceHandleWin.cpp @@ -242,8 +242,11 @@ bool ResourceHandle::onRequestComplete() resourceHandleClient->didReceiveResponse(this, response); } + // FIXME: https://bugs.webkit.org/show_bug.cgi?id=19793 + // -1 means we do not provide any data about transfer size to inspector so it would use + // Content-Length headers or content size to show transfer size. if (ResourceHandleClient* resourceHandleClient = client()) - resourceHandleClient->didReceiveData(this, buffer, buffers.dwBufferLength, 0); + resourceHandleClient->didReceiveData(this, buffer, buffers.dwBufferLength, -1); buffers.dwBufferLength = bufferSize; } @@ -385,8 +388,11 @@ void ResourceHandle::fileLoadTimer(Timer<ResourceHandle>*) const int bufferSize = 8192; char buffer[bufferSize]; result = ReadFile(fileHandle, &buffer, bufferSize, &bytesRead, 0); + // FIXME: https://bugs.webkit.org/show_bug.cgi?id=19793 + // -1 means we do not provide any data about transfer size to inspector so it would use + // Content-Length headers or content size to show transfer size. if (result && bytesRead) - client()->didReceiveData(this, buffer, bytesRead, 0); + client()->didReceiveData(this, buffer, bytesRead, -1); // Check for end of file. } while (result && bytesRead); diff --git a/Source/WebCore/platform/posix/FileSystemPOSIX.cpp b/Source/WebCore/platform/posix/FileSystemPOSIX.cpp index c035310..c44b1d2 100644 --- a/Source/WebCore/platform/posix/FileSystemPOSIX.cpp +++ b/Source/WebCore/platform/posix/FileSystemPOSIX.cpp @@ -30,14 +30,10 @@ #include "FileSystem.h" #include "PlatformString.h" -#ifdef ANDROID_PLUGINS #include <dirent.h> -#endif #include <errno.h> #include <fcntl.h> -#ifdef ANDROID_PLUGINS #include <fnmatch.h> -#endif #include <libgen.h> #include <sys/stat.h> #include <sys/types.h> @@ -235,10 +231,30 @@ String directoryName(const String& path) return dirname(fsRep.mutableData()); } -// OK to not implement listDirectory at the moment, because it's only used for plug-ins, and -// all platforms that use the shared plug-in implementation have implementations. We'd need -// to implement it if we wanted to use PluginDatabase.cpp on the Mac. Better to not implement -// at all and get a link error in case this arises, rather than having a stub here, because -// with a stub you learn about the problem at runtime instead of link time. +#if !PLATFORM(EFL) +Vector<String> listDirectory(const String& path, const String& filter) +{ + Vector<String> entries; + CString cpath = path.utf8(); + CString cfilter = filter.utf8(); + DIR* dir = opendir(cpath.data()); + if (dir) { + struct dirent* dp; + while ((dp = readdir(dir))) { + const char* name = dp->d_name; + if (!strcmp(name, ".") || !strcmp(name, "..")) + continue; + if (fnmatch(cfilter.data(), name, 0)) + continue; + char filePath[1024]; + if (static_cast<int>(sizeof(filePath) - 1) < snprintf(filePath, sizeof(filePath), "%s/%s", cpath.data(), name)) + continue; // buffer overflow + entries.append(filePath); + } + closedir(dir); + } + return entries; +} +#endif } // namespace WebCore diff --git a/Source/WebCore/platform/qt/CookieJarQt.cpp b/Source/WebCore/platform/qt/CookieJarQt.cpp index db4a42a..3c4cd42 100644 --- a/Source/WebCore/platform/qt/CookieJarQt.cpp +++ b/Source/WebCore/platform/qt/CookieJarQt.cpp @@ -91,8 +91,7 @@ String cookies(const Document* document, const KURL& url) foreach (QNetworkCookie networkCookie, cookies) { if (networkCookie.isHttpOnly()) continue; - resultCookies.append(QString::fromAscii( - networkCookie.toRawForm(QNetworkCookie::NameAndValueOnly).constData())); + resultCookies.append(QString::fromLatin1(networkCookie.toRawForm(QNetworkCookie::NameAndValueOnly).constData())); } return resultCookies.join(QLatin1String("; ")); @@ -110,10 +109,8 @@ String cookieRequestHeaderFieldValue(const Document* document, const KURL &url) return String(); QStringList resultCookies; - foreach (QNetworkCookie networkCookie, cookies) { - resultCookies.append(QString::fromAscii( - networkCookie.toRawForm(QNetworkCookie::NameAndValueOnly).constData())); - } + foreach (QNetworkCookie networkCookie, cookies) + resultCookies.append(QString::fromLatin1(networkCookie.toRawForm(QNetworkCookie::NameAndValueOnly).constData())); return resultCookies.join(QLatin1String("; ")); } diff --git a/Source/WebCore/platform/qt/FileSystemQt.cpp b/Source/WebCore/platform/qt/FileSystemQt.cpp index d88a967..32644d1 100644 --- a/Source/WebCore/platform/qt/FileSystemQt.cpp +++ b/Source/WebCore/platform/qt/FileSystemQt.cpp @@ -114,19 +114,19 @@ Vector<String> listDirectory(const String& path, const String& filter) return entries; } -CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle) +String openTemporaryFile(const String& prefix, PlatformFileHandle& handle) { #ifndef QT_NO_TEMPORARYFILE - QTemporaryFile* tempFile = new QTemporaryFile(QDir::tempPath() + QLatin1Char('/') + QLatin1String(prefix)); + QTemporaryFile* tempFile = new QTemporaryFile(QDir::tempPath() + QLatin1Char('/') + QString(prefix)); tempFile->setAutoRemove(false); QFile* temp = tempFile; if (temp->open(QIODevice::ReadWrite)) { handle = temp; - return String(temp->fileName()).utf8(); + return temp->fileName(); } #endif handle = invalidPlatformFileHandle; - return CString(); + return String(); } PlatformFileHandle openFile(const String& path, FileOpenMode mode) diff --git a/Source/WebCore/platform/qt/LanguageQt.cpp b/Source/WebCore/platform/qt/LanguageQt.cpp index 71e554f..5a1d707 100644 --- a/Source/WebCore/platform/qt/LanguageQt.cpp +++ b/Source/WebCore/platform/qt/LanguageQt.cpp @@ -35,7 +35,7 @@ namespace WebCore { String platformDefaultLanguage() { QLocale locale; - return locale.name().replace("_", "-"); + return locale.name().replace(QLatin1Char('_'), QLatin1Char('-')); } } diff --git a/Source/WebCore/platform/qt/PasteboardQt.cpp b/Source/WebCore/platform/qt/PasteboardQt.cpp index 6865fd7..850d68a 100644 --- a/Source/WebCore/platform/qt/PasteboardQt.cpp +++ b/Source/WebCore/platform/qt/PasteboardQt.cpp @@ -77,7 +77,7 @@ void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, QApplication::clipboard()->setMimeData(md, m_selectionMode ? QClipboard::Selection : QClipboard::Clipboard); #endif if (canSmartCopyOrDelete) - md->setData("application/vnd.qtwebkit.smartpaste", QByteArray()); + md->setData(QLatin1String("application/vnd.qtwebkit.smartpaste"), QByteArray()); } bool Pasteboard::canSmartReplace() diff --git a/Source/WebCore/platform/qt/RenderThemeQt.cpp b/Source/WebCore/platform/qt/RenderThemeQt.cpp index ca8c6dd..cc654d5 100644 --- a/Source/WebCore/platform/qt/RenderThemeQt.cpp +++ b/Source/WebCore/platform/qt/RenderThemeQt.cpp @@ -1368,7 +1368,6 @@ bool RenderThemeQt::paintMediaSliderTrack(RenderObject* o, const PaintInfo& pain paintMediaBackground(p.painter, r); -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) if (MediaPlayer* player = mediaElement->player()) { // Get the buffered parts of the media PassRefPtr<TimeRanges> buffered = player->buffered(); @@ -1386,7 +1385,6 @@ bool RenderThemeQt::paintMediaSliderTrack(RenderObject* o, const PaintInfo& pain } } } -#endif return false; } diff --git a/Source/WebCore/platform/text/BidiContext.cpp b/Source/WebCore/platform/text/BidiContext.cpp index fb6b8cf..f507514 100644 --- a/Source/WebCore/platform/text/BidiContext.cpp +++ b/Source/WebCore/platform/text/BidiContext.cpp @@ -21,48 +21,80 @@ #include "config.h" #include "BidiContext.h" +#include <wtf/Vector.h> namespace WebCore { using namespace WTF::Unicode; -inline PassRefPtr<BidiContext> BidiContext::createUncached(unsigned char level, Direction direction, bool override, BidiContext* parent) +inline PassRefPtr<BidiContext> BidiContext::createUncached(unsigned char level, Direction direction, bool override, BidiEmbeddingSource source, BidiContext* parent) { - return adoptRef(new BidiContext(level, direction, override, parent)); + return adoptRef(new BidiContext(level, direction, override, source, parent)); } -PassRefPtr<BidiContext> BidiContext::create(unsigned char level, Direction direction, bool override, BidiContext* parent) +PassRefPtr<BidiContext> BidiContext::create(unsigned char level, Direction direction, bool override, BidiEmbeddingSource source, BidiContext* parent) { ASSERT(direction == (level % 2 ? RightToLeft : LeftToRight)); if (parent) - return createUncached(level, direction, override, parent); + return createUncached(level, direction, override, source, parent); ASSERT(level <= 1); if (!level) { if (!override) { - static BidiContext* ltrContext = createUncached(0, LeftToRight, false, 0).releaseRef(); + static BidiContext* ltrContext = createUncached(0, LeftToRight, false, FromStyleOrDOM, 0).releaseRef(); return ltrContext; } - static BidiContext* ltrOverrideContext = createUncached(0, LeftToRight, true, 0).releaseRef(); + static BidiContext* ltrOverrideContext = createUncached(0, LeftToRight, true, FromStyleOrDOM, 0).releaseRef(); return ltrOverrideContext; } if (!override) { - static BidiContext* rtlContext = createUncached(1, RightToLeft, false, 0).releaseRef(); + static BidiContext* rtlContext = createUncached(1, RightToLeft, false, FromStyleOrDOM, 0).releaseRef(); return rtlContext; } - static BidiContext* rtlOverrideContext = createUncached(1, RightToLeft, true, 0).releaseRef(); + static BidiContext* rtlOverrideContext = createUncached(1, RightToLeft, true, FromStyleOrDOM, 0).releaseRef(); return rtlOverrideContext; } +static inline PassRefPtr<BidiContext> copyContextAndRebaselineLevel(BidiContext* context, BidiContext* parent) +{ + ASSERT(context); + unsigned char newLevel = parent ? parent->level() : 0; + if (context->dir() == RightToLeft) + newLevel = nextGreaterOddLevel(newLevel); + else if (parent) + newLevel = nextGreaterEvenLevel(newLevel); + + return BidiContext::create(newLevel, context->dir(), context->override(), context->source(), parent); +} + +// The BidiContext stack must be immutable -- they're re-used for re-layout after +// DOM modification/editing -- so we copy all the non-unicode contexts, and +// recalculate their levels. +PassRefPtr<BidiContext> BidiContext::copyStackRemovingUnicodeEmbeddingContexts() +{ + Vector<BidiContext*, 64> contexts; + for (BidiContext* iter = this; iter; iter = iter->parent()) { + if (iter->source() != FromUnicode) + contexts.append(iter); + } + ASSERT(contexts.size()); + + RefPtr<BidiContext> topContext = copyContextAndRebaselineLevel(contexts.last(), 0); + for (int i = contexts.size() - 1; i > 0; --i) + topContext = copyContextAndRebaselineLevel(contexts[i - 1], topContext.get()); + + return topContext.release(); +} + bool operator==(const BidiContext& c1, const BidiContext& c2) { if (&c1 == &c2) return true; - if (c1.level() != c2.level() || c1.override() != c2.override() || c1.dir() != c2.dir()) + if (c1.level() != c2.level() || c1.override() != c2.override() || c1.dir() != c2.dir() || c1.source() != c2.source()) return false; if (!c1.parent()) return !c2.parent(); diff --git a/Source/WebCore/platform/text/BidiContext.h b/Source/WebCore/platform/text/BidiContext.h index b52815f..9f45d65 100644 --- a/Source/WebCore/platform/text/BidiContext.h +++ b/Source/WebCore/platform/text/BidiContext.h @@ -30,33 +30,52 @@ namespace WebCore { +enum BidiEmbeddingSource { + FromStyleOrDOM, + FromUnicode +}; + // Used to keep track of explicit embeddings. class BidiContext : public RefCounted<BidiContext> { public: - static PassRefPtr<BidiContext> create(unsigned char level, WTF::Unicode::Direction direction, bool override = false, BidiContext* parent = 0); + static PassRefPtr<BidiContext> create(unsigned char level, WTF::Unicode::Direction, bool override = false, BidiEmbeddingSource = FromStyleOrDOM, BidiContext* parent = 0); BidiContext* parent() const { return m_parent.get(); } unsigned char level() const { return m_level; } WTF::Unicode::Direction dir() const { return static_cast<WTF::Unicode::Direction>(m_direction); } bool override() const { return m_override; } + BidiEmbeddingSource source() const { return static_cast<BidiEmbeddingSource>(m_source); } + PassRefPtr<BidiContext> copyStackRemovingUnicodeEmbeddingContexts(); private: - BidiContext(unsigned char level, WTF::Unicode::Direction direction, bool override, BidiContext* parent) + BidiContext(unsigned char level, WTF::Unicode::Direction direction, bool override, BidiEmbeddingSource source, BidiContext* parent) : m_level(level) , m_direction(direction) , m_override(override) + , m_source(source) , m_parent(parent) { } - static PassRefPtr<BidiContext> createUncached(unsigned char level, WTF::Unicode::Direction, bool override, BidiContext* parent); + static PassRefPtr<BidiContext> createUncached(unsigned char level, WTF::Unicode::Direction, bool override, BidiEmbeddingSource, BidiContext* parent); unsigned char m_level; unsigned m_direction : 5; // Direction bool m_override : 1; + unsigned m_source : 1; // BidiEmbeddingSource RefPtr<BidiContext> m_parent; }; +inline unsigned char nextGreaterOddLevel(unsigned char level) +{ + return (level + 1) | 1; +} + +inline unsigned char nextGreaterEvenLevel(unsigned char level) +{ + return (level + 2) & ~1; +} + bool operator==(const BidiContext&, const BidiContext&); } // namespace WebCore diff --git a/Source/WebCore/platform/text/BidiResolver.h b/Source/WebCore/platform/text/BidiResolver.h index 07e9274..5b92ee2 100644 --- a/Source/WebCore/platform/text/BidiResolver.h +++ b/Source/WebCore/platform/text/BidiResolver.h @@ -75,6 +75,21 @@ struct BidiStatus { RefPtr<BidiContext> context; }; +class BidiEmbedding { +public: + BidiEmbedding(WTF::Unicode::Direction direction, BidiEmbeddingSource source) + : m_direction(direction) + , m_source(source) + { + } + + WTF::Unicode::Direction direction() const { return m_direction; } + BidiEmbeddingSource source() const { return m_source; } +private: + WTF::Unicode::Direction m_direction; + BidiEmbeddingSource m_source; +}; + inline bool operator==(const BidiStatus& status1, const BidiStatus& status2) { return status1.eor == status2.eor && status1.last == status2.last && status1.lastStrong == status2.lastStrong && *(status1.context) == *(status2.context); @@ -134,10 +149,10 @@ enum VisualDirectionOverride { template <class Iterator, class Run> class BidiResolver { WTF_MAKE_NONCOPYABLE(BidiResolver); -public : +public: BidiResolver() : m_direction(WTF::Unicode::OtherNeutral) - , reachedEndOfLine(false) + , m_reachedEndOfLine(false) , emptyRun(true) , m_firstRun(0) , m_lastRun(0) @@ -146,10 +161,10 @@ public : { } - const Iterator& position() const { return current; } - void setPosition(const Iterator& position) { current = position; } + const Iterator& position() const { return m_current; } + void setPosition(const Iterator& position) { m_current = position; } - void increment() { current.increment(); } + void increment() { m_current.increment(); } BidiContext* context() const { return m_status.context.get(); } void setContext(PassRefPtr<BidiContext> c) { m_status.context = c; } @@ -166,7 +181,7 @@ public : MidpointState<Iterator>& midpointState() { return m_midpointState; } - void embed(WTF::Unicode::Direction); + void embed(WTF::Unicode::Direction, BidiEmbeddingSource); bool commitExplicitEmbedding(); void createBidiRunsForLine(const Iterator& end, VisualDirectionOverride = NoVisualOverride, bool hardLineBreak = false); @@ -188,14 +203,16 @@ protected: void appendRun(); void reverseRuns(unsigned start, unsigned end); - Iterator current; - Iterator sor; - Iterator eor; - Iterator last; + Iterator m_current; + // sor and eor are "start of run" and "end of run" respectively and correpond + // to abreviations used in UBA spec: http://unicode.org/reports/tr9/#BD7 + Iterator m_sor; + Iterator m_eor; + Iterator m_last; BidiStatus m_status; WTF::Unicode::Direction m_direction; Iterator endOfLine; - bool reachedEndOfLine; + bool m_reachedEndOfLine; Iterator lastBeforeET; bool emptyRun; @@ -210,7 +227,10 @@ private: void lowerExplicitEmbeddingLevel(WTF::Unicode::Direction from); void checkDirectionInLowerRaiseEmbeddingLevel(); - Vector<WTF::Unicode::Direction, 8> m_currentExplicitEmbeddingSequence; + void updateStatusLastFromCurrentDirection(WTF::Unicode::Direction); + void reorderRunsFromLevels(); + + Vector<BidiEmbedding, 8> m_currentExplicitEmbeddingSequence; }; template <class Iterator, class Run> @@ -286,20 +306,20 @@ inline void BidiResolver<Iterator, Run>::moveRunToBeginning(Run* run) template <class Iterator, class Run> void BidiResolver<Iterator, Run>::appendRun() { - if (!emptyRun && !eor.atEnd()) { - unsigned startOffset = sor.offset(); - unsigned endOffset = eor.offset(); + if (!emptyRun && !m_eor.atEnd()) { + unsigned startOffset = m_sor.offset(); + unsigned endOffset = m_eor.offset(); if (!endOfLine.atEnd() && endOffset >= endOfLine.offset()) { - reachedEndOfLine = true; + m_reachedEndOfLine = true; endOffset = endOfLine.offset(); } if (endOffset >= startOffset) addRun(new Run(startOffset, endOffset + 1, context(), m_direction)); - eor.increment(); - sor = eor; + m_eor.increment(); + m_sor = m_eor; } m_direction = WTF::Unicode::OtherNeutral; @@ -307,12 +327,12 @@ void BidiResolver<Iterator, Run>::appendRun() } template <class Iterator, class Run> -void BidiResolver<Iterator, Run>::embed(WTF::Unicode::Direction d) +void BidiResolver<Iterator, Run>::embed(WTF::Unicode::Direction dir, BidiEmbeddingSource source) { using namespace WTF::Unicode; - ASSERT(d == PopDirectionalFormat || d == LeftToRightEmbedding || d == LeftToRightOverride || d == RightToLeftEmbedding || d == RightToLeftOverride); - m_currentExplicitEmbeddingSequence.append(d); + ASSERT(dir == PopDirectionalFormat || dir == LeftToRightEmbedding || dir == LeftToRightOverride || dir == RightToLeftEmbedding || dir == RightToLeftOverride); + m_currentExplicitEmbeddingSequence.append(BidiEmbedding(dir, source)); } template <class Iterator, class Run> @@ -320,7 +340,7 @@ void BidiResolver<Iterator, Run>::checkDirectionInLowerRaiseEmbeddingLevel() { using namespace WTF::Unicode; - ASSERT(m_status.eor != OtherNeutral || eor.atEnd()); + ASSERT(m_status.eor != OtherNeutral || m_eor.atEnd()); ASSERT(m_status.last != NonSpacingMark && m_status.last != BoundaryNeutral && m_status.last != RightToLeftEmbedding @@ -337,7 +357,7 @@ void BidiResolver<Iterator, Run>::lowerExplicitEmbeddingLevel(WTF::Unicode::Dire { using namespace WTF::Unicode; - if (!emptyRun && eor != last) { + if (!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) { @@ -358,14 +378,14 @@ void BidiResolver<Iterator, Run>::lowerExplicitEmbeddingLevel(WTF::Unicode::Dire appendRun(); m_direction = RightToLeft; } - eor = last; + m_eor = m_last; } appendRun(); emptyRun = true; // sor for the new run is determined by the higher level (rule X10) setLastDir(from); setLastStrongDir(from); - eor = Iterator(); + m_eor = Iterator(); } template <class Iterator, class Run> @@ -373,7 +393,7 @@ void BidiResolver<Iterator, Run>::raiseExplicitEmbeddingLevel(WTF::Unicode::Dire { using namespace WTF::Unicode; - if (!emptyRun && eor != last) { + if (!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) { @@ -396,13 +416,13 @@ void BidiResolver<Iterator, Run>::raiseExplicitEmbeddingLevel(WTF::Unicode::Dire appendRun(); m_direction = RightToLeft; } - eor = last; + m_eor = m_last; } appendRun(); emptyRun = true; setLastDir(to); setLastStrongDir(to); - eor = Iterator(); + m_eor = Iterator(); } template <class Iterator, class Run> @@ -414,25 +434,20 @@ bool BidiResolver<Iterator, Run>::commitExplicitEmbedding() RefPtr<BidiContext> toContext = context(); for (size_t i = 0; i < m_currentExplicitEmbeddingSequence.size(); ++i) { - Direction embedding = m_currentExplicitEmbeddingSequence[i]; - if (embedding == PopDirectionalFormat) { + BidiEmbedding embedding = m_currentExplicitEmbeddingSequence[i]; + if (embedding.direction() == PopDirectionalFormat) { if (BidiContext* parentContext = toContext->parent()) toContext = parentContext; } else { - Direction direction = (embedding == RightToLeftEmbedding || embedding == RightToLeftOverride) ? RightToLeft : LeftToRight; - bool override = embedding == LeftToRightOverride || embedding == RightToLeftOverride; + Direction direction = (embedding.direction() == RightToLeftEmbedding || embedding.direction() == RightToLeftOverride) ? RightToLeft : LeftToRight; + bool override = embedding.direction() == LeftToRightOverride || embedding.direction() == RightToLeftOverride; unsigned char level = toContext->level(); - if (direction == RightToLeft) { - // Go to the least greater odd integer - level += 1; - level |= 1; - } else { - // Go to the least greater even integer - level += 2; - level &= ~1; - } + if (direction == RightToLeft) + level = nextGreaterOddLevel(level); + else + level = nextGreaterEvenLevel(level); if (level < 61) - toContext = BidiContext::create(level, direction, override, toContext.get()); + toContext = BidiContext::create(level, direction, override, embedding.source(), toContext.get()); } } @@ -520,6 +535,85 @@ void BidiResolver<Iterator, Run>::reverseRuns(unsigned start, unsigned end) } template <class Iterator, class Run> +inline void BidiResolver<Iterator, Run>::updateStatusLastFromCurrentDirection(WTF::Unicode::Direction dirCurrent) +{ + using namespace WTF::Unicode; + switch (dirCurrent) { + case EuropeanNumberTerminator: + if (m_status.last != EuropeanNumber) + m_status.last = EuropeanNumberTerminator; + break; + case EuropeanNumberSeparator: + case CommonNumberSeparator: + case SegmentSeparator: + case WhiteSpaceNeutral: + case OtherNeutral: + switch (m_status.last) { + case LeftToRight: + case RightToLeft: + case RightToLeftArabic: + case EuropeanNumber: + case ArabicNumber: + m_status.last = dirCurrent; + break; + default: + m_status.last = OtherNeutral; + } + break; + case NonSpacingMark: + case BoundaryNeutral: + case RightToLeftEmbedding: + case LeftToRightEmbedding: + case RightToLeftOverride: + case LeftToRightOverride: + case PopDirectionalFormat: + // ignore these + break; + case EuropeanNumber: + // fall through + default: + m_status.last = dirCurrent; + } +} + +template <class Iterator, class Run> +inline void BidiResolver<Iterator, Run>::reorderRunsFromLevels() +{ + unsigned char levelLow = 128; + unsigned char levelHigh = 0; + for (Run* run = firstRun(); run; run = run->next()) { + levelHigh = std::max(run->level(), levelHigh); + levelLow = std::min(run->level(), levelLow); + } + + // This implements reordering of the line (L2 according to Bidi spec): + // http://unicode.org/reports/tr9/#L2 + // L2. From the highest level found in the text to the lowest odd level on each line, + // reverse any contiguous sequence of characters that are at that level or higher. + + // Reversing is only done up to the lowest odd level. + if (!(levelLow % 2)) + levelLow++; + + unsigned count = runCount() - 1; + + while (levelHigh >= levelLow) { + unsigned i = 0; + Run* run = firstRun(); + while (i < count) { + for (;i < count && run && run->level() < levelHigh; i++) + run = run->next(); + unsigned start = i; + for (;i <= count && run && run->level() >= levelHigh; i++) + run = run->next(); + unsigned end = i - 1; + reverseRuns(start, end); + } + levelHigh--; + } +} + +template <class Iterator, class Run> void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, VisualDirectionOverride override, bool hardLineBreak) { using namespace WTF::Unicode; @@ -528,10 +622,10 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis if (override != NoVisualOverride) { emptyRun = false; - sor = current; - eor = Iterator(); - while (current != end && !current.atEnd()) { - eor = current; + m_sor = m_current; + m_eor = Iterator(); + while (m_current != end && !m_current.atEnd()) { + m_eor = m_current; increment(); } m_direction = override == VisualLeftToRightOverride ? LeftToRight : RightToLeft; @@ -544,29 +638,34 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis emptyRun = true; - eor = Iterator(); + m_eor = Iterator(); - last = current; + m_last = m_current; bool pastEnd = false; BidiResolver<Iterator, Run> stateAtEnd; while (true) { Direction dirCurrent; - if (pastEnd && (hardLineBreak || current.atEnd())) { + if (pastEnd && (hardLineBreak || m_current.atEnd())) { BidiContext* c = context(); - while (c->parent()) - c = c->parent(); - dirCurrent = c->dir(); if (hardLineBreak) { // A deviation from the Unicode Bidi Algorithm in order to match - // Mac OS X text and WinIE: a hard line break resets bidi state. - stateAtEnd.setContext(c); + // WinIE and user expectations: hard line breaks reset bidi state + // coming from unicode bidi control characters, but not those from + // DOM nodes with specified directionality + stateAtEnd.setContext(c->copyStackRemovingUnicodeEmbeddingContexts()); + + dirCurrent = stateAtEnd.context()->dir(); stateAtEnd.setEorDir(dirCurrent); stateAtEnd.setLastDir(dirCurrent); stateAtEnd.setLastStrongDir(dirCurrent); + } else { + while (c->parent()) + c = c->parent(); + dirCurrent = c->dir(); } } else { - dirCurrent = current.direction(); + dirCurrent = m_current.direction(); if (context()->override() && dirCurrent != RightToLeftEmbedding && dirCurrent != LeftToRightEmbedding @@ -578,7 +677,7 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis dirCurrent = m_status.last; } - ASSERT(m_status.eor != OtherNeutral || eor.atEnd()); + ASSERT(m_status.eor != OtherNeutral || m_eor.atEnd()); switch (dirCurrent) { // embedding and overrides (X1-X9 in the Bidi specs) @@ -587,7 +686,7 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis case RightToLeftOverride: case LeftToRightOverride: case PopDirectionalFormat: - embed(dirCurrent); + embed(dirCurrent, FromUnicode); commitExplicitEmbedding(); break; @@ -618,7 +717,7 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis appendRun(); if (context()->dir() != LeftToRight) { // the neutrals take the embedding direction, which is R - eor = last; + m_eor = m_last; m_direction = RightToLeft; appendRun(); } @@ -629,14 +728,14 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis appendRun(); if (context()->dir() != LeftToRight) { // the neutrals take the embedding direction, which is R - eor = last; + m_eor = m_last; m_direction = RightToLeft; appendRun(); } } else if (m_status.lastStrong != LeftToRight) { //last stuff takes embedding dir if (context()->dir() == RightToLeft) { - eor = last; + m_eor = m_last; m_direction = RightToLeft; } appendRun(); @@ -644,7 +743,7 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis default: break; } - eor = current; + m_eor = m_current; m_status.eor = LeftToRight; m_status.lastStrong = LeftToRight; m_direction = LeftToRight; @@ -669,19 +768,19 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis case OtherNeutral: if (m_status.eor == EuropeanNumber) { if (m_status.lastStrong == LeftToRight && context()->dir() == LeftToRight) - eor = last; + m_eor = m_last; appendRun(); } else if (m_status.eor == ArabicNumber) appendRun(); else if (m_status.lastStrong == LeftToRight) { if (context()->dir() == LeftToRight) - eor = last; + m_eor = m_last; appendRun(); } default: break; } - eor = current; + m_eor = m_current; m_status.eor = RightToLeft; m_status.lastStrong = dirCurrent; m_direction = RightToLeft; @@ -699,7 +798,7 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis case RightToLeft: case RightToLeftArabic: case ArabicNumber: - eor = last; + m_eor = m_last; appendRun(); m_direction = EuropeanNumber; break; @@ -719,7 +818,7 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis // Terminate the EN run. appendRun(); // Make an R run. - eor = m_status.last == EuropeanNumberTerminator ? lastBeforeET : last; + m_eor = m_status.last == EuropeanNumberTerminator ? lastBeforeET : m_last; m_direction = RightToLeft; appendRun(); // Begin a new EN run. @@ -730,7 +829,7 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis appendRun(); if (m_status.lastStrong == RightToLeft || context()->dir() == RightToLeft) { // Make an R run. - eor = m_status.last == EuropeanNumberTerminator ? lastBeforeET : last; + m_eor = m_status.last == EuropeanNumberTerminator ? lastBeforeET : m_last; m_direction = RightToLeft; appendRun(); // Begin a new EN run. @@ -738,7 +837,7 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis } } else if (m_status.lastStrong == RightToLeft) { // Extend the R run to include the neutrals. - eor = m_status.last == EuropeanNumberTerminator ? lastBeforeET : last; + m_eor = m_status.last == EuropeanNumberTerminator ? lastBeforeET : m_last; m_direction = RightToLeft; appendRun(); // Begin a new EN run. @@ -747,7 +846,7 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis default: break; } - eor = current; + m_eor = m_current; m_status.eor = EuropeanNumber; if (m_direction == OtherNeutral) m_direction = LeftToRight; @@ -765,7 +864,7 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis case RightToLeft: case RightToLeftArabic: case EuropeanNumber: - eor = last; + m_eor = m_last; appendRun(); break; case CommonNumberSeparator: @@ -787,12 +886,12 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis m_direction = RightToLeft; } else if (m_direction == OtherNeutral) m_direction = m_status.lastStrong == LeftToRight ? LeftToRight : RightToLeft; - eor = last; + m_eor = m_last; appendRun(); default: break; } - eor = current; + m_eor = m_current; m_status.eor = ArabicNumber; if (m_direction == OtherNeutral) m_direction = ArabicNumber; @@ -803,16 +902,16 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis case EuropeanNumberTerminator: if (m_status.last == EuropeanNumber) { dirCurrent = EuropeanNumber; - eor = current; + m_eor = m_current; m_status.eor = dirCurrent; } else if (m_status.last != EuropeanNumberTerminator) - lastBeforeET = emptyRun ? eor : last; + lastBeforeET = emptyRun ? m_eor : m_last; break; // boundary neutrals should be ignored case BoundaryNeutral: - if (eor == last) - eor = current; + if (m_eor == m_last) + m_eor = m_current; break; // neutrals case BlockSeparator: @@ -829,9 +928,9 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis break; } - if (pastEnd && eor == current) { - if (!reachedEndOfLine) { - eor = endOfLine; + if (pastEnd && m_eor == m_current) { + if (!m_reachedEndOfLine) { + m_eor = endOfLine; switch (m_status.eor) { case LeftToRight: case RightToLeft: @@ -846,60 +945,23 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis } appendRun(); } - current = end; + m_current = end; m_status = stateAtEnd.m_status; - sor = stateAtEnd.sor; - eor = stateAtEnd.eor; - last = stateAtEnd.last; - reachedEndOfLine = stateAtEnd.reachedEndOfLine; + m_sor = stateAtEnd.m_sor; + m_eor = stateAtEnd.m_eor; + m_last = stateAtEnd.m_last; + m_reachedEndOfLine = stateAtEnd.m_reachedEndOfLine; lastBeforeET = stateAtEnd.lastBeforeET; emptyRun = stateAtEnd.emptyRun; m_direction = OtherNeutral; break; } - // set m_status.last as needed. - switch (dirCurrent) { - case EuropeanNumberTerminator: - if (m_status.last != EuropeanNumber) - m_status.last = EuropeanNumberTerminator; - break; - case EuropeanNumberSeparator: - case CommonNumberSeparator: - case SegmentSeparator: - case WhiteSpaceNeutral: - case OtherNeutral: - switch(m_status.last) { - case LeftToRight: - case RightToLeft: - case RightToLeftArabic: - case EuropeanNumber: - case ArabicNumber: - m_status.last = dirCurrent; - break; - default: - m_status.last = OtherNeutral; - } - break; - case NonSpacingMark: - case BoundaryNeutral: - case RightToLeftEmbedding: - case LeftToRightEmbedding: - case RightToLeftOverride: - case LeftToRightOverride: - case PopDirectionalFormat: - // ignore these - break; - case EuropeanNumber: - // fall through - default: - m_status.last = dirCurrent; - } - - last = current; + updateStatusLastFromCurrentDirection(dirCurrent); + m_last = m_current; if (emptyRun) { - sor = current; + m_sor = m_current; emptyRun = false; } @@ -907,12 +969,12 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis if (!m_currentExplicitEmbeddingSequence.isEmpty()) { bool committed = commitExplicitEmbedding(); if (committed && pastEnd) { - current = end; + m_current = end; m_status = stateAtEnd.m_status; - sor = stateAtEnd.sor; - eor = stateAtEnd.eor; - last = stateAtEnd.last; - reachedEndOfLine = stateAtEnd.reachedEndOfLine; + m_sor = stateAtEnd.m_sor; + m_eor = stateAtEnd.m_eor; + m_last = stateAtEnd.m_last; + m_reachedEndOfLine = stateAtEnd.m_reachedEndOfLine; lastBeforeET = stateAtEnd.lastBeforeET; emptyRun = stateAtEnd.emptyRun; m_direction = OtherNeutral; @@ -920,64 +982,23 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis } } - if (!pastEnd && (current == end || current.atEnd())) { + if (!pastEnd && (m_current == end || m_current.atEnd())) { if (emptyRun) break; stateAtEnd.m_status = m_status; - stateAtEnd.sor = sor; - stateAtEnd.eor = eor; - stateAtEnd.last = last; - stateAtEnd.reachedEndOfLine = reachedEndOfLine; + 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; - endOfLine = last; + endOfLine = m_last; pastEnd = true; } } m_logicallyLastRun = m_lastRun; - - // reorder line according to run structure... - // first find highest and lowest levels - unsigned char levelLow = 128; - unsigned char levelHigh = 0; - Run* r = firstRun(); - while (r) { - if (r->m_level > levelHigh) - levelHigh = r->m_level; - if (r->m_level < levelLow) - levelLow = r->m_level; - r = r->next(); - } - - // implements reordering of the line (L2 according to Bidi spec): - // L2. From the highest level found in the text to the lowest odd level on each line, - // reverse any contiguous sequence of characters that are at that level or higher. - - // reversing is only done up to the lowest odd level - if (!(levelLow % 2)) - levelLow++; - - unsigned count = runCount() - 1; - - while (levelHigh >= levelLow) { - unsigned i = 0; - Run* currRun = firstRun(); - while (i < count) { - while (i < count && currRun && currRun->m_level < levelHigh) { - i++; - currRun = currRun->next(); - } - unsigned start = i; - while (i <= count && currRun && currRun->m_level >= levelHigh) { - i++; - currRun = currRun->next(); - } - unsigned end = i - 1; - reverseRuns(start, end); - } - levelHigh--; - } + reorderRunsFromLevels(); endOfLine = Iterator(); } diff --git a/Source/WebCore/platform/text/LocalizedNumber.h b/Source/WebCore/platform/text/LocalizedNumber.h index d70541f..01d2553 100644 --- a/Source/WebCore/platform/text/LocalizedNumber.h +++ b/Source/WebCore/platform/text/LocalizedNumber.h @@ -47,7 +47,9 @@ double parseLocalizedNumber(const String&); // current locale. If an implementation doesn't support localized // numbers or the input value is NaN or Infinitiy, the function should // return an empty string. -String formatLocalizedNumber(double); +// fractionDigits is the maximum length of the fractional parts of the +// resultant string. +String formatLocalizedNumber(double, unsigned fractionDigits); } // namespace WebCore diff --git a/Source/WebCore/platform/text/LocalizedNumberICU.cpp b/Source/WebCore/platform/text/LocalizedNumberICU.cpp index 189151e..7c4b1cb 100644 --- a/Source/WebCore/platform/text/LocalizedNumberICU.cpp +++ b/Source/WebCore/platform/text/LocalizedNumberICU.cpp @@ -34,6 +34,7 @@ #include <limits> #include <unicode/numfmt.h> #include <unicode/parsepos.h> +#include <wtf/MathExtras.h> #include <wtf/PassOwnPtr.h> using namespace std; @@ -73,12 +74,13 @@ double parseLocalizedNumber(const String& numberString) return U_SUCCESS(status) ? numericResult : numeric_limits<double>::quiet_NaN(); } -String formatLocalizedNumber(double number) +String formatLocalizedNumber(double number, unsigned fractionDigits) { NumberFormat* formatter = numberFormatter(); if (!formatter) return String(); UnicodeString result; + formatter->setMaximumFractionDigits(clampToInteger(fractionDigits)); formatter->format(number, result); return String(result.getBuffer(), result.length()); } diff --git a/Source/WebCore/platform/text/LocalizedNumberNone.cpp b/Source/WebCore/platform/text/LocalizedNumberNone.cpp index 729f2f1..c7a8ed2 100644 --- a/Source/WebCore/platform/text/LocalizedNumberNone.cpp +++ b/Source/WebCore/platform/text/LocalizedNumberNone.cpp @@ -42,7 +42,7 @@ double parseLocalizedNumber(const String&) return numeric_limits<double>::quiet_NaN(); } -String formatLocalizedNumber(double) +String formatLocalizedNumber(double, unsigned) { return String(); } diff --git a/Source/WebCore/platform/text/TextCheckerClient.h b/Source/WebCore/platform/text/TextCheckerClient.h index acaa02c..8abbed4 100644 --- a/Source/WebCore/platform/text/TextCheckerClient.h +++ b/Source/WebCore/platform/text/TextCheckerClient.h @@ -28,6 +28,8 @@ #ifndef TextCheckerClient_h #define TextCheckerClient_h +#include "TextChecking.h" + #include <wtf/Forward.h> #include <wtf/Vector.h> #include <wtf/text/WTFString.h> @@ -70,7 +72,7 @@ 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 PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +#if USE(UNIFIED_TEXT_CHECKING) virtual void checkTextOfParagraph(const UChar* text, int length, uint64_t checkingTypes, Vector<TextCheckingResult>& results) = 0; #endif diff --git a/Source/WebCore/platform/chromium/WindowsVersion.h b/Source/WebCore/platform/text/TextChecking.h index 3b2010a..022fb82 100644 --- a/Source/WebCore/platform/chromium/WindowsVersion.h +++ b/Source/WebCore/platform/text/TextChecking.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, Google Inc. All rights reserved. + * Copyright (c) 2011 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -28,13 +28,20 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef WindowsVersion_h -#define WindowsVersion_h +#ifndef TextChecking_h +#define TextChecking_h namespace WebCore { - bool isVistaOrNewer(); - -} // namespace WebCore +#if !defined(BUILDING_ON_TIGER) +#define WTF_USE_GRAMMAR_CHECKING 1 +#endif +#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +#define WTF_USE_UNIFIED_TEXT_CHECKING 1 +#define WTF_USE_AUTOMATIC_TEXT_REPLACEMENT 1 #endif + +} + +#endif // TextChecking_h diff --git a/Source/WebCore/platform/text/TextCodec.h b/Source/WebCore/platform/text/TextCodec.h index 35229a3..0c2a38a 100644 --- a/Source/WebCore/platform/text/TextCodec.h +++ b/Source/WebCore/platform/text/TextCodec.h @@ -52,7 +52,7 @@ namespace WebCore { // Encodes the character as en entity as above, but escaped // non-alphanumeric characters. This is used in URLs. // For example, U+6DE would be "%26%231758%3B". - URLEncodedEntitiesForUnencodables, + URLEncodedEntitiesForUnencodables }; typedef char UnencodableReplacementArray[32]; diff --git a/Source/WebCore/platform/text/TextCodecICU.cpp b/Source/WebCore/platform/text/TextCodecICU.cpp index d07b50e..0d99196 100644 --- a/Source/WebCore/platform/text/TextCodecICU.cpp +++ b/Source/WebCore/platform/text/TextCodecICU.cpp @@ -149,13 +149,6 @@ void TextCodecICU::registerEncodingNames(EncodingNameRegistrar registrar) registrar("x-windows-949", "windows-949"); registrar("x-uhc", "windows-949"); registrar("shift-jis", "Shift_JIS"); -#if !USE(BUILTIN_UTF8_CODEC) - registrar("unicode11utf8", "UTF-8"); - registrar("unicode20utf8", "UTF-8"); - registrar("x-unicode20utf8", "UTF-8"); - registrar("utf8", "UTF-8"); - registrar("UTF-8", "UTF-8"); -#endif // These aliases are present in modern versions of ICU, but use different codecs, and have no standard names. // They are not present in ICU 3.2. diff --git a/Source/WebCore/platform/text/TextEncodingRegistry.cpp b/Source/WebCore/platform/text/TextEncodingRegistry.cpp index f604227..d6450b1 100644 --- a/Source/WebCore/platform/text/TextEncodingRegistry.cpp +++ b/Source/WebCore/platform/text/TextEncodingRegistry.cpp @@ -223,10 +223,8 @@ static void buildBaseTextCodecMaps() TextCodecLatin1::registerEncodingNames(addToTextEncodingNameMap); TextCodecLatin1::registerCodecs(addToTextCodecMap); -#if USE(BUILTIN_UTF8_CODEC) TextCodecUTF8::registerEncodingNames(addToTextEncodingNameMap); TextCodecUTF8::registerCodecs(addToTextCodecMap); -#endif TextCodecUTF16::registerEncodingNames(addToTextEncodingNameMap); TextCodecUTF16::registerCodecs(addToTextCodecMap); diff --git a/Source/WebCore/platform/mac/WebCoreKeyGenerator.m b/Source/WebCore/platform/text/TextOrientation.h index a1e780c..e229f1e 100644 --- a/Source/WebCore/platform/mac/WebCoreKeyGenerator.m +++ b/Source/WebCore/platform/text/TextOrientation.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003 Apple Inc. All rights reserved. + * Copyright (C) 2011 Apple Computer, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,41 +23,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#import "config.h" -#import "WebCoreKeyGenerator.h" +#ifndef TextOrientation_h +#define TextOrientation_h -#import <wtf/Assertions.h> -#import <wtf/UnusedParam.h> +namespace WebCore { -static WebCoreKeyGenerator *sharedGenerator; +enum TextOrientation { TextOrientationVerticalRight, TextOrientationUpright }; -@implementation WebCoreKeyGenerator - -+ (WebCoreKeyGenerator *)sharedGenerator -{ - return sharedGenerator; -} - -- init -{ - ASSERT(!sharedGenerator); - [super init]; - sharedGenerator = [self retain]; - return self; -} - -- (NSArray *)strengthMenuItemTitles -{ - return nil; -} - -- (NSString *)signedPublicKeyAndChallengeStringWithStrengthIndex:(unsigned)unusedIndex challenge:(NSString *)unusedChallenge pageURL:(NSURL *)unusedPageURL -{ - UNUSED_PARAM(unusedIndex); - UNUSED_PARAM(unusedChallenge); - UNUSED_PARAM(unusedPageURL); - - return nil; } -@end +#endif diff --git a/Source/WebCore/platform/text/mac/LocalizedNumberMac.mm b/Source/WebCore/platform/text/mac/LocalizedNumberMac.mm index 8cfe200..826f707 100644 --- a/Source/WebCore/platform/text/mac/LocalizedNumberMac.mm +++ b/Source/WebCore/platform/text/mac/LocalizedNumberMac.mm @@ -65,10 +65,12 @@ double parseLocalizedNumber(const String& numberString) return [number doubleValue]; } -String formatLocalizedNumber(double inputNumber) +String formatLocalizedNumber(double inputNumber, unsigned fractionDigits) { RetainPtr<NSNumber> number(AdoptNS, [[NSNumber alloc] initWithDouble:inputNumber]); - return String([numberFormatter() stringFromNumber:number.get()]); + RetainPtr<NSNumberFormatter> formatter = numberFormatter(); + [formatter.get() setMaximumFractionDigits:fractionDigits]; + return String([formatter.get() stringFromNumber:number.get()]); } } // namespace WebCore diff --git a/Source/WebCore/platform/text/qt/TextBreakIteratorQt.cpp b/Source/WebCore/platform/text/qt/TextBreakIteratorQt.cpp index 3fae657..1fe400c 100644 --- a/Source/WebCore/platform/text/qt/TextBreakIteratorQt.cpp +++ b/Source/WebCore/platform/text/qt/TextBreakIteratorQt.cpp @@ -22,6 +22,7 @@ #include "TextBreakIterator.h" #include <QtCore/qtextboundaryfinder.h> +#include <algorithm> #include <qdebug.h> // #define DEBUG_TEXT_ITERATORS @@ -89,7 +90,7 @@ const char* currentTextBreakLocaleID() TextBreakIterator* lineBreakIterator = 0; if (staticLineBreakIterator) { setUpIterator(*staticLineBreakIterator, QTextBoundaryFinder::Line, string, length); - swap(staticLineBreakIterator, lineBreakIterator); + std::swap(staticLineBreakIterator, lineBreakIterator); } if (!lineBreakIterator && string && length) diff --git a/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp b/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp index 513992d..33d8ccd 100644 --- a/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp +++ b/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp @@ -130,7 +130,7 @@ static bool getWebLocData(const DragDataMap* dataObject, String& url, String* ti if (!dataObject->contains(cfHDropFormat()->cfFormat)) return false; - wcscpy(filename, dataObject->get(cfHDropFormat()->cfFormat)[0].characters()); + wcscpy(filename, dataObject->get(cfHDropFormat()->cfFormat)[0].charactersWithNullTermination()); if (_wcsicmp(PathFindExtensionW(filename), L".url")) return false; diff --git a/Source/WebCore/platform/win/CursorWin.cpp b/Source/WebCore/platform/win/CursorWin.cpp index 0036388..3a8cc09 100644 --- a/Source/WebCore/platform/win/CursorWin.cpp +++ b/Source/WebCore/platform/win/CursorWin.cpp @@ -30,6 +30,7 @@ #include "BitmapInfo.h" #include "Image.h" #include "IntPoint.h" +#include "SystemInfo.h" #include <wtf/OwnPtr.h> @@ -39,20 +40,12 @@ namespace WebCore { -static inline bool supportsAlphaCursors() -{ - OSVERSIONINFO osinfo = {0}; - osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&osinfo); - return osinfo.dwMajorVersion > 5 || (osinfo.dwMajorVersion == 5 && osinfo.dwMinorVersion > 0); -} - static PassRefPtr<SharedCursor> createSharedCursor(Image* img, const IntPoint& hotSpot) { RefPtr<SharedCursor> impl; IntPoint effectiveHotSpot = determineHotSpot(img, hotSpot); - static bool doAlpha = supportsAlphaCursors(); + static bool doAlpha = windowsVersion() >= WindowsXP; BitmapInfo cursorImage = BitmapInfo::create(IntSize(img->width(), img->height())); HDC dc = GetDC(0); diff --git a/Source/WebCore/platform/win/FileSystemWin.cpp b/Source/WebCore/platform/win/FileSystemWin.cpp index 5ee3b8e..03a2eaf 100644 --- a/Source/WebCore/platform/win/FileSystemWin.cpp +++ b/Source/WebCore/platform/win/FileSystemWin.cpp @@ -31,9 +31,11 @@ #include "FileSystem.h" #include "NotImplemented.h" +#include "PathWalker.h" #include "PlatformString.h" #include <wtf/HashMap.h> #include <wtf/text/CString.h> +#include <wtf/text/StringConcatenate.h> #include <windows.h> #include <winbase.h> @@ -184,18 +186,18 @@ static String cachedStorageDirectory(DWORD pathIdentifier) return directory; } -CString openTemporaryFile(const char*, PlatformFileHandle& handle) +String openTemporaryFile(const String&, PlatformFileHandle& handle) { handle = INVALID_HANDLE_VALUE; char tempPath[MAX_PATH]; int tempPathLength = ::GetTempPathA(WTF_ARRAY_LENGTH(tempPath), tempPath); if (tempPathLength <= 0 || tempPathLength > WTF_ARRAY_LENGTH(tempPath)) - return CString(); + return String(); HCRYPTPROV hCryptProv = 0; if (!CryptAcquireContext(&hCryptProv, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) - return CString(); + return String(); char proposedPath[MAX_PATH]; while (1) { @@ -226,9 +228,28 @@ CString openTemporaryFile(const char*, PlatformFileHandle& handle) CryptReleaseContext(hCryptProv, 0); if (!isHandleValid(handle)) - return CString(); + return String(); - return proposedPath; + return String::fromUTF8(proposedPath); +} + +PlatformFileHandle openFile(const String& path, FileOpenMode mode) +{ + DWORD desiredAccess = 0; + DWORD creationDisposition = 0; + switch (mode) { + case OpenForRead: + desiredAccess = GENERIC_READ; + creationDisposition = OPEN_EXISTING; + case OpenForWrite: + desiredAccess = GENERIC_WRITE; + creationDisposition = CREATE_ALWAYS; + default: + ASSERT_NOT_REACHED(); + } + + String destination = path; + return CreateFile(destination.charactersWithNullTermination(), desiredAccess, 0, 0, creationDisposition, FILE_ATTRIBUTE_NORMAL, 0); } void closeFile(PlatformFileHandle& handle) @@ -297,10 +318,21 @@ bool safeCreateFile(const String& path, CFDataRef data) return true; } -Vector<String> listDirectory(const String& path, const String& filter) +Vector<String> listDirectory(const String& directory, const String& filter) { Vector<String> entries; - notImplemented(); + + PathWalker walker(directory, filter); + if (!walker.isValid()) + return entries; + + do { + if (walker.data().dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + continue; + + entries.append(makeString(directory, "\\", reinterpret_cast<const UChar*>(walker.data().cFileName))); + } while (walker.step()); + return entries; } diff --git a/Source/WebCore/platform/win/LocalizedStringsWin.cpp b/Source/WebCore/platform/win/LocalizedStringsWin.cpp new file mode 100644 index 0000000..67de0fc --- /dev/null +++ b/Source/WebCore/platform/win/LocalizedStringsWin.cpp @@ -0,0 +1,39 @@ +/* + * 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 "LocalizedStrings.h" + +#include <wtf/text/WTFString.h> + +namespace WebCore { + +String localizedString(const char* key) +{ + // FIXME: <rdar://problem/9119405> Win: WebKit2 needs to be made localizable + return String::fromUTF8(key, strlen(key)); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/win/PathWalker.cpp b/Source/WebCore/platform/win/PathWalker.cpp new file mode 100644 index 0000000..cb4fccb --- /dev/null +++ b/Source/WebCore/platform/win/PathWalker.cpp @@ -0,0 +1,51 @@ +/* + * 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 "PathWalker.h" + +#include <wtf/text/StringConcatenate.h> + +namespace WebCore { + +PathWalker::PathWalker(const String& directory, const String& pattern) +{ + String path = makeString(directory, "\\", pattern); + m_handle = ::FindFirstFileW(path.charactersWithNullTermination(), &m_data); +} + +PathWalker::~PathWalker() +{ + if (!isValid()) + return; + ::FindClose(m_handle); +} + +bool PathWalker::step() +{ + return ::FindNextFileW(m_handle, &m_data); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/win/PathWalker.h b/Source/WebCore/platform/win/PathWalker.h new file mode 100644 index 0000000..219c837 --- /dev/null +++ b/Source/WebCore/platform/win/PathWalker.h @@ -0,0 +1,51 @@ +/* + * 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 <Windows.h> +#include <wtf/Noncopyable.h> + +namespace WTF { + class String; +} + +namespace WebCore { + +class PathWalker { + WTF_MAKE_NONCOPYABLE(PathWalker); +public: + PathWalker(const WTF::String& directory, const WTF::String& pattern); + ~PathWalker(); + + bool isValid() const { return m_handle != INVALID_HANDLE_VALUE; } + const WIN32_FIND_DATAW& data() const { return m_data; } + + bool step(); + +private: + HANDLE m_handle; + WIN32_FIND_DATAW m_data; +}; + +} // namespace WebCore diff --git a/Source/WebCore/platform/win/SSLKeyGeneratorWin.cpp b/Source/WebCore/platform/win/SSLKeyGeneratorWin.cpp index 50aee8e..b10961b 100644 --- a/Source/WebCore/platform/win/SSLKeyGeneratorWin.cpp +++ b/Source/WebCore/platform/win/SSLKeyGeneratorWin.cpp @@ -30,6 +30,7 @@ namespace WebCore { void WebCore::getSupportedKeySizes(Vector<String>& v) { + // FIXME: Strings should be localizable. v.append("High Grade"); v.append("Medium Grade"); } diff --git a/Source/WebCore/platform/win/ScrollbarThemeWin.cpp b/Source/WebCore/platform/win/ScrollbarThemeWin.cpp index ff3aaa4..576cd92 100644 --- a/Source/WebCore/platform/win/ScrollbarThemeWin.cpp +++ b/Source/WebCore/platform/win/ScrollbarThemeWin.cpp @@ -100,7 +100,7 @@ ScrollbarThemeWin::ScrollbarThemeWin() if (!initialized) { initialized = true; checkAndInitScrollbarTheme(); - runningVista = isRunningOnVistaOrLater(); + runningVista = (windowsVersion() >= WindowsVista); } } diff --git a/Source/WebCore/platform/win/SystemInfo.cpp b/Source/WebCore/platform/win/SystemInfo.cpp index f2fe62b..878a6cc 100644 --- a/Source/WebCore/platform/win/SystemInfo.cpp +++ b/Source/WebCore/platform/win/SystemInfo.cpp @@ -27,30 +27,155 @@ #include "SystemInfo.h" #include <windows.h> +#include <wtf/text/StringConcatenate.h> namespace WebCore { -bool isRunningOnVistaOrLater() +WindowsVersion windowsVersion(int* major, int* minor) { + static bool initialized = false; + static WindowsVersion version; + static int majorVersion, minorVersion; + + if (!initialized) { + initialized = true; +#if OS(WINCE) + OSVERSIONINFO versionInfo; +#else + OSVERSIONINFOEX versionInfo; +#endif + ZeroMemory(&versionInfo, sizeof(versionInfo)); + versionInfo.dwOSVersionInfoSize = sizeof(versionInfo); + GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&versionInfo)); + majorVersion = versionInfo.dwMajorVersion; + minorVersion = versionInfo.dwMinorVersion; + #if OS(WINCE) - return false; + if (majorVersion >= 1 && majorVersion <= 7) + version = static_cast<WindowsVersion>(WindowsCE1 + (majorVersion - 1)); + else + version = (majorVersion < 1) ? WindowsCE1 : WindowsCE7; #else - static bool isVistaOrLater; - static bool initialized; + if (versionInfo.dwPlatformId == VER_PLATFORM_WIN32s) + version = Windows3_1; + else if (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { + if (!minorVersion) + version = Windows95; + else + version = (minorVersion == 10) ? Windows98 : WindowsME; + } else { + if (majorVersion == 5) { + if (!minorVersion) + version = Windows2000; + else + version = (minorVersion == 1) ? WindowsXP : WindowsServer2003; + } else if (majorVersion >= 6) { + if (versionInfo.wProductType == VER_NT_WORKSTATION) + version = (majorVersion == 6 && !minorVersion) ? WindowsVista : Windows7; + else + version = WindowsServer2008; + } else + version = (majorVersion == 4) ? WindowsNT4 : WindowsNT3; + } +#endif + } - if (initialized) - return isVistaOrLater; + if (major) + *major = majorVersion; + if (minor) + *minor = minorVersion; + return version; +} + +static String osVersionForUAString() +{ + int major, minor; + WindowsVersion version = windowsVersion(&major, &minor); + switch (version) { + case WindowsCE1: + case WindowsCE2: + case WindowsCE3: + return "Windows CE"; + case WindowsCE4: + return "Windows CE .NET"; + case Windows3_1: + return "Windows 3.1"; + case Windows95: + return "Windows 95"; + case Windows98: + return "Windows 98"; + case WindowsME: + return "Windows 98; Win 9x 4.90"; + case WindowsNT4: + return "WinNT4.0"; + } - initialized = true; + const char* familyName = (version >= WindowsNT3) ? "Windows NT " : "Windows CE "; + return makeString(familyName, String::number(major), '.', String::number(minor)); +} - OSVERSIONINFOEX vi = {0}; - vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&vi)); +#if !OS(WINCE) +static bool isWOW64() +{ + static bool initialized = false; + static bool wow64 = false; - isVistaOrLater = vi.dwMajorVersion >= 6; + if (!initialized) { + initialized = true; + HMODULE kernel32Module = GetModuleHandleA("kernel32.dll"); + if (!kernel32Module) + return wow64; + typedef BOOL (WINAPI* IsWow64ProcessFunc)(HANDLE, PBOOL); + IsWow64ProcessFunc isWOW64Process = reinterpret_cast<IsWow64ProcessFunc>(GetProcAddress(kernel32Module, "IsWow64Process")); + if (isWOW64Process) { + BOOL result = FALSE; + wow64 = isWOW64Process(GetCurrentProcess(), &result) && result; + } + } - return isVistaOrLater; + return wow64; +} + +static WORD processorArchitecture() +{ + static bool initialized = false; + static WORD architecture = PROCESSOR_ARCHITECTURE_INTEL; + + if (!initialized) { + initialized = true; + HMODULE kernel32Module = GetModuleHandleA("kernel32.dll"); + if (!kernel32Module) + return architecture; + typedef VOID (WINAPI* GetNativeSystemInfoFunc)(LPSYSTEM_INFO); + GetNativeSystemInfoFunc getNativeSystemInfo = reinterpret_cast<GetNativeSystemInfoFunc>(GetProcAddress(kernel32Module, "GetNativeSystemInfo")); + if (getNativeSystemInfo) { + SYSTEM_INFO systemInfo; + ZeroMemory(&systemInfo, sizeof(systemInfo)); + getNativeSystemInfo(&systemInfo); + architecture = systemInfo.wProcessorArchitecture; + } + } + + return architecture; +} #endif + +static String architectureTokenForUAString() +{ +#if !OS(WINCE) + if (isWOW64()) + return "; WOW64"; + if (processorArchitecture() == PROCESSOR_ARCHITECTURE_AMD64) + return "; Win64; x64"; + if (processorArchitecture() == PROCESSOR_ARCHITECTURE_IA64) + return "; Win64; IA64"; +#endif + return String(); +} + +String windowsVersionForUAString() +{ + return makeString(osVersionForUAString(), architectureTokenForUAString()); } } // namespace WebCore diff --git a/Source/WebCore/platform/win/SystemInfo.h b/Source/WebCore/platform/win/SystemInfo.h index 9f2c2a0..2631ace 100644 --- a/Source/WebCore/platform/win/SystemInfo.h +++ b/Source/WebCore/platform/win/SystemInfo.h @@ -26,9 +26,44 @@ #ifndef SystemInfo_h #define SystemInfo_h +#include <wtf/text/WTFString.h> + namespace WebCore { -bool isRunningOnVistaOrLater(); +// NOTE: Keep these in order so callers can do things like +// "if (windowsVersion() >= WindowsVista) ...". It's OK to change or add values, +// though. +enum WindowsVersion { + // CE-based versions + WindowsCE1 = 0, + WindowsCE2, + WindowsCE3, + WindowsCE4, + WindowsCE5, + WindowsCE6, + WindowsCE7, + // 3.x-based versions + Windows3_1, + // 9x-based versions + Windows95, + Windows98, + WindowsME, + // NT-based versions + WindowsNT3, + WindowsNT4, + Windows2000, + WindowsXP, + WindowsServer2003, + WindowsVista, + WindowsServer2008, + Windows7, +}; + +// If supplied, |major| and |minor| are set to the OSVERSIONINFO::dwMajorVersion +// and dwMinorVersion field values, respectively. +WindowsVersion windowsVersion(int* major = 0, int* minor = 0); + +String windowsVersionForUAString(); } // namespace WebCore diff --git a/Source/WebCore/platform/wince/FileSystemWinCE.cpp b/Source/WebCore/platform/wince/FileSystemWinCE.cpp index 49acf12..3e28a01 100644 --- a/Source/WebCore/platform/wince/FileSystemWinCE.cpp +++ b/Source/WebCore/platform/wince/FileSystemWinCE.cpp @@ -187,18 +187,18 @@ String directoryName(const String& path) return path.left(pos); } -CString openTemporaryFile(const char*, PlatformFileHandle& handle) +String openTemporaryFile(const String&, PlatformFileHandle& handle) { handle = INVALID_HANDLE_VALUE; wchar_t tempPath[MAX_PATH]; int tempPathLength = ::GetTempPath(WTF_ARRAY_LENGTH(tempPath), tempPath); if (tempPathLength <= 0 || tempPathLength > WTF_ARRAY_LENGTH(tempPath)) - return CString(); + return String(); HCRYPTPROV hCryptProv = 0; if (!CryptAcquireContext(&hCryptProv, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) - return CString(); + return String(); String proposedPath; while (1) { @@ -229,9 +229,28 @@ CString openTemporaryFile(const char*, PlatformFileHandle& handle) CryptReleaseContext(hCryptProv, 0); if (!isHandleValid(handle)) - return CString(); + return String(); + + return proposedPath; +} + +PlatformFileHandle openFile(const String& path, FileOpenMode mode) +{ + DWORD desiredAccess = 0; + DWORD creationDisposition = 0; + switch (mode) { + case OpenForRead: + desiredAccess = GENERIC_READ; + creationDisposition = OPEN_EXISTING; + case OpenForWrite: + desiredAccess = GENERIC_WRITE; + creationDisposition = CREATE_ALWAYS; + default: + ASSERT_NOT_REACHED(); + } - return proposedPath.latin1(); + String destination = path; + return CreateFile(destination.charactersWithNullTermination(), desiredAccess, 0, 0, creationDisposition, FILE_ATTRIBUTE_NORMAL, 0); } void closeFile(PlatformFileHandle& handle) diff --git a/Source/WebCore/platform/wx/FileSystemWx.cpp b/Source/WebCore/platform/wx/FileSystemWx.cpp index bfcaf88..3c2b453 100644 --- a/Source/WebCore/platform/wx/FileSystemWx.cpp +++ b/Source/WebCore/platform/wx/FileSystemWx.cpp @@ -107,11 +107,11 @@ String directoryName(const String& path) return wxFileName(path).GetPath(); } -CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle) +String openTemporaryFile(const String&, PlatformFileHandle& handle) { notImplemented(); handle = invalidPlatformFileHandle; - return CString(); + return String(); } void closeFile(PlatformFileHandle&) diff --git a/Source/WebCore/platform/wx/LocalizedStringsWx.cpp b/Source/WebCore/platform/wx/LocalizedStringsWx.cpp index 835c3cd..8ec791e 100644 --- a/Source/WebCore/platform/wx/LocalizedStringsWx.cpp +++ b/Source/WebCore/platform/wx/LocalizedStringsWx.cpp @@ -212,7 +212,7 @@ String contextMenuItemTagSearchWeb() return String("Search Web"); } -String contextMenuItemTagLookUpInDictionary() +String contextMenuItemTagLookUpInDictionary(const String&) { return String("Look Up in Dictionary"); } |