diff options
Diffstat (limited to 'WebCore/platform')
558 files changed, 11672 insertions, 8360 deletions
diff --git a/WebCore/platform/ContextMenu.cpp b/WebCore/platform/ContextMenu.cpp index 93cdfdf..a51d818 100644 --- a/WebCore/platform/ContextMenu.cpp +++ b/WebCore/platform/ContextMenu.cpp @@ -1,7 +1,5 @@ /* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. - * Copyright (C) 2008 Christian Dywan <christian@imendio.com> - * Copyright (C) 2010 Igalia S.L + * 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 @@ -12,879 +10,52 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "ContextMenu.h" -#if ENABLE(CONTEXT_MENUS) - -#include "BackForwardController.h" -#include "ContextMenuController.h" -#include "ContextMenuClient.h" -#include "CSSComputedStyleDeclaration.h" -#include "CSSProperty.h" -#include "CSSPropertyNames.h" -#include "Document.h" -#include "DocumentLoader.h" -#include "Editor.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "InspectorController.h" -#include "KURL.h" -#include "LocalizedStrings.h" -#include "Node.h" -#include "Page.h" -#include "ResourceRequest.h" -#include "SelectionController.h" -#include "Settings.h" -#include "TextIterator.h" -#include <wtf/text/CString.h> - -using namespace std; -using namespace WTF; -using namespace Unicode; +#if USE(CROSS_PLATFORM_CONTEXT_MENUS) namespace WebCore { -ContextMenuController* ContextMenu::controller() const -{ - if (Node* node = m_hitTestResult.innerNonSharedNode()) - if (Frame* frame = node->document()->frame()) - if (Page* page = frame->page()) - return page->contextMenuController(); - return 0; -} - -static PassOwnPtr<ContextMenuItem> separatorItem() -{ - return new ContextMenuItem(SeparatorType, ContextMenuItemTagNoAction, String()); -} - -static void createAndAppendFontSubMenu(const HitTestResult& result, ContextMenuItem& fontMenuItem) -{ - ContextMenu fontMenu(result); - -#if PLATFORM(MAC) - ContextMenuItem showFonts(ActionType, ContextMenuItemTagShowFonts, contextMenuItemTagShowFonts()); -#endif - ContextMenuItem bold(CheckableActionType, ContextMenuItemTagBold, contextMenuItemTagBold()); - ContextMenuItem italic(CheckableActionType, ContextMenuItemTagItalic, contextMenuItemTagItalic()); - ContextMenuItem underline(CheckableActionType, ContextMenuItemTagUnderline, contextMenuItemTagUnderline()); - ContextMenuItem outline(ActionType, ContextMenuItemTagOutline, contextMenuItemTagOutline()); -#if PLATFORM(MAC) - ContextMenuItem styles(ActionType, ContextMenuItemTagStyles, contextMenuItemTagStyles()); - ContextMenuItem showColors(ActionType, ContextMenuItemTagShowColors, contextMenuItemTagShowColors()); -#endif - -#if PLATFORM(MAC) - fontMenu.appendItem(showFonts); -#endif - fontMenu.appendItem(bold); - fontMenu.appendItem(italic); - fontMenu.appendItem(underline); - fontMenu.appendItem(outline); -#if PLATFORM(MAC) - fontMenu.appendItem(styles); - fontMenu.appendItem(*separatorItem()); - fontMenu.appendItem(showColors); -#endif - - fontMenuItem.setSubMenu(&fontMenu); -} - -#if !defined(BUILDING_ON_TIGER) - -#if !PLATFORM(GTK) - -static void createAndAppendSpellingAndGrammarSubMenu(const HitTestResult& result, ContextMenuItem& spellingAndGrammarMenuItem) -{ - ContextMenu spellingAndGrammarMenu(result); - - ContextMenuItem showSpellingPanel(ActionType, ContextMenuItemTagShowSpellingPanel, - contextMenuItemTagShowSpellingPanel(true)); - ContextMenuItem checkSpelling(ActionType, ContextMenuItemTagCheckSpelling, - contextMenuItemTagCheckSpelling()); - ContextMenuItem checkAsYouType(CheckableActionType, ContextMenuItemTagCheckSpellingWhileTyping, - contextMenuItemTagCheckSpellingWhileTyping()); - ContextMenuItem grammarWithSpelling(CheckableActionType, ContextMenuItemTagCheckGrammarWithSpelling, - contextMenuItemTagCheckGrammarWithSpelling()); -#if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD) - ContextMenuItem correctSpelling(CheckableActionType, ContextMenuItemTagCorrectSpellingAutomatically, - contextMenuItemTagCorrectSpellingAutomatically()); -#endif - - spellingAndGrammarMenu.appendItem(showSpellingPanel); - spellingAndGrammarMenu.appendItem(checkSpelling); -#if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD) - spellingAndGrammarMenu.appendItem(*separatorItem()); -#endif - spellingAndGrammarMenu.appendItem(checkAsYouType); - spellingAndGrammarMenu.appendItem(grammarWithSpelling); -#if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD) - spellingAndGrammarMenu.appendItem(correctSpelling); -#endif - - spellingAndGrammarMenuItem.setSubMenu(&spellingAndGrammarMenu); -} - -#endif // !PLATFORM(GTK) - -#else - -static void createAndAppendSpellingSubMenu(const HitTestResult& result, ContextMenuItem& spellingMenuItem) -{ - ContextMenu spellingMenu(result); - - ContextMenuItem showSpellingPanel(ActionType, ContextMenuItemTagShowSpellingPanel, - contextMenuItemTagShowSpellingPanel(true)); - ContextMenuItem checkSpelling(ActionType, ContextMenuItemTagCheckSpelling, - contextMenuItemTagCheckSpelling()); - ContextMenuItem checkAsYouType(CheckableActionType, ContextMenuItemTagCheckSpellingWhileTyping, - contextMenuItemTagCheckSpellingWhileTyping()); - - spellingMenu.appendItem(showSpellingPanel); - spellingMenu.appendItem(checkSpelling); - spellingMenu.appendItem(checkAsYouType); - - spellingMenuItem.setSubMenu(&spellingMenu); -} - -#endif - -#if PLATFORM(MAC) - -static void createAndAppendSpeechSubMenu(const HitTestResult& result, ContextMenuItem& speechMenuItem) -{ - ContextMenu speechMenu(result); - - ContextMenuItem start(ActionType, ContextMenuItemTagStartSpeaking, contextMenuItemTagStartSpeaking()); - ContextMenuItem stop(ActionType, ContextMenuItemTagStopSpeaking, contextMenuItemTagStopSpeaking()); - - speechMenu.appendItem(start); - speechMenu.appendItem(stop); - - speechMenuItem.setSubMenu(&speechMenu); -} - -#endif - -#if !PLATFORM(GTK) - -static void createAndAppendWritingDirectionSubMenu(const HitTestResult& result, ContextMenuItem& writingDirectionMenuItem) -{ - ContextMenu writingDirectionMenu(result); - - ContextMenuItem defaultItem(ActionType, ContextMenuItemTagDefaultDirection, - contextMenuItemTagDefaultDirection()); - ContextMenuItem ltr(CheckableActionType, ContextMenuItemTagLeftToRight, contextMenuItemTagLeftToRight()); - ContextMenuItem rtl(CheckableActionType, ContextMenuItemTagRightToLeft, contextMenuItemTagRightToLeft()); - - writingDirectionMenu.appendItem(defaultItem); - writingDirectionMenu.appendItem(ltr); - writingDirectionMenu.appendItem(rtl); - - writingDirectionMenuItem.setSubMenu(&writingDirectionMenu); -} - -static void createAndAppendTextDirectionSubMenu(const HitTestResult& result, ContextMenuItem& textDirectionMenuItem) -{ - ContextMenu textDirectionMenu(result); - - ContextMenuItem defaultItem(ActionType, ContextMenuItemTagTextDirectionDefault, contextMenuItemTagDefaultDirection()); - ContextMenuItem ltr(CheckableActionType, ContextMenuItemTagTextDirectionLeftToRight, contextMenuItemTagLeftToRight()); - ContextMenuItem rtl(CheckableActionType, ContextMenuItemTagTextDirectionRightToLeft, contextMenuItemTagRightToLeft()); - - textDirectionMenu.appendItem(defaultItem); - textDirectionMenu.appendItem(ltr); - textDirectionMenu.appendItem(rtl); - - textDirectionMenuItem.setSubMenu(&textDirectionMenu); -} - -#endif - -#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) - -static void createAndAppendSubstitutionsSubMenu(const HitTestResult& result, ContextMenuItem& substitutionsMenuItem) -{ - ContextMenu substitutionsMenu(result); - - ContextMenuItem showSubstitutions(ActionType, ContextMenuItemTagShowSubstitutions, contextMenuItemTagShowSubstitutions(true)); - ContextMenuItem smartCopyPaste(CheckableActionType, ContextMenuItemTagSmartCopyPaste, contextMenuItemTagSmartCopyPaste()); - ContextMenuItem smartQuotes(CheckableActionType, ContextMenuItemTagSmartQuotes, contextMenuItemTagSmartQuotes()); - ContextMenuItem smartDashes(CheckableActionType, ContextMenuItemTagSmartDashes, contextMenuItemTagSmartDashes()); - ContextMenuItem smartLinks(CheckableActionType, ContextMenuItemTagSmartLinks, contextMenuItemTagSmartLinks()); - ContextMenuItem textReplacement(CheckableActionType, ContextMenuItemTagTextReplacement, contextMenuItemTagTextReplacement()); - - substitutionsMenu.appendItem(showSubstitutions); - substitutionsMenu.appendItem(*separatorItem()); - substitutionsMenu.appendItem(smartCopyPaste); - substitutionsMenu.appendItem(smartQuotes); - substitutionsMenu.appendItem(smartDashes); - substitutionsMenu.appendItem(smartLinks); - substitutionsMenu.appendItem(textReplacement); - - substitutionsMenuItem.setSubMenu(&substitutionsMenu); -} - -static void createAndAppendTransformationsSubMenu(const HitTestResult& result, ContextMenuItem& transformationsMenuItem) +ContextMenu::ContextMenu() { - ContextMenu transformationsMenu(result); - - ContextMenuItem makeUpperCase(ActionType, ContextMenuItemTagMakeUpperCase, contextMenuItemTagMakeUpperCase()); - ContextMenuItem makeLowerCase(ActionType, ContextMenuItemTagMakeLowerCase, contextMenuItemTagMakeLowerCase()); - ContextMenuItem capitalize(ActionType, ContextMenuItemTagCapitalize, contextMenuItemTagCapitalize()); - - transformationsMenu.appendItem(makeUpperCase); - transformationsMenu.appendItem(makeLowerCase); - transformationsMenu.appendItem(capitalize); - - transformationsMenuItem.setSubMenu(&transformationsMenu); } -#endif - -static bool selectionContainsPossibleWord(Frame* frame) +static const ContextMenuItem* findItemWithAction(unsigned action, const Vector<ContextMenuItem>& items) { - // Current algorithm: look for a character that's not just a separator. - for (TextIterator it(frame->selection()->toNormalizedRange().get()); !it.atEnd(); it.advance()) { - int length = it.length(); - const UChar* characters = it.characters(); - for (int i = 0; i < length; ++i) - if (!(category(characters[i]) & (Separator_Space | Separator_Line | Separator_Paragraph))) - return true; + for (size_t i = 0; i < items.size(); ++i) { + const ContextMenuItem& item = items[i]; + if (item.action() == action) + return &item; + if (item.type() != SubmenuType) + continue; + if (const ContextMenuItem* subMenuItem = findItemWithAction(action, item.subMenuItems())) + return subMenuItem; } - return false; -} - -void ContextMenu::populate() -{ - ContextMenuItem OpenLinkItem(ActionType, ContextMenuItemTagOpenLink, contextMenuItemTagOpenLink()); - ContextMenuItem OpenLinkInNewWindowItem(ActionType, ContextMenuItemTagOpenLinkInNewWindow, - contextMenuItemTagOpenLinkInNewWindow()); - ContextMenuItem DownloadFileItem(ActionType, ContextMenuItemTagDownloadLinkToDisk, - contextMenuItemTagDownloadLinkToDisk()); - ContextMenuItem CopyLinkItem(ActionType, ContextMenuItemTagCopyLinkToClipboard, - contextMenuItemTagCopyLinkToClipboard()); - ContextMenuItem OpenImageInNewWindowItem(ActionType, ContextMenuItemTagOpenImageInNewWindow, - contextMenuItemTagOpenImageInNewWindow()); - ContextMenuItem DownloadImageItem(ActionType, ContextMenuItemTagDownloadImageToDisk, - contextMenuItemTagDownloadImageToDisk()); - ContextMenuItem CopyImageItem(ActionType, ContextMenuItemTagCopyImageToClipboard, - contextMenuItemTagCopyImageToClipboard()); - ContextMenuItem OpenMediaInNewWindowItem(ActionType, ContextMenuItemTagOpenMediaInNewWindow, String()); - ContextMenuItem CopyMediaLinkItem(ActionType, ContextMenuItemTagCopyMediaLinkToClipboard, - String()); - ContextMenuItem MediaPlayPause(ActionType, ContextMenuItemTagMediaPlayPause, - contextMenuItemTagMediaPlay()); - ContextMenuItem MediaMute(ActionType, ContextMenuItemTagMediaMute, - contextMenuItemTagMediaMute()); - ContextMenuItem ToggleMediaControls(CheckableActionType, ContextMenuItemTagToggleMediaControls, - contextMenuItemTagToggleMediaControls()); - ContextMenuItem ToggleMediaLoop(CheckableActionType, ContextMenuItemTagToggleMediaLoop, - contextMenuItemTagToggleMediaLoop()); - ContextMenuItem EnterVideoFullscreen(ActionType, ContextMenuItemTagEnterVideoFullscreen, - contextMenuItemTagEnterVideoFullscreen()); -#if PLATFORM(MAC) - ContextMenuItem SearchSpotlightItem(ActionType, ContextMenuItemTagSearchInSpotlight, - contextMenuItemTagSearchInSpotlight()); - ContextMenuItem LookInDictionaryItem(ActionType, ContextMenuItemTagLookUpInDictionary, - contextMenuItemTagLookUpInDictionary()); -#endif -#if !PLATFORM(GTK) - ContextMenuItem SearchWebItem(ActionType, ContextMenuItemTagSearchWeb, contextMenuItemTagSearchWeb()); -#endif - ContextMenuItem CopyItem(ActionType, ContextMenuItemTagCopy, contextMenuItemTagCopy()); - ContextMenuItem BackItem(ActionType, ContextMenuItemTagGoBack, contextMenuItemTagGoBack()); - ContextMenuItem ForwardItem(ActionType, ContextMenuItemTagGoForward, contextMenuItemTagGoForward()); - ContextMenuItem StopItem(ActionType, ContextMenuItemTagStop, contextMenuItemTagStop()); - ContextMenuItem ReloadItem(ActionType, ContextMenuItemTagReload, contextMenuItemTagReload()); - ContextMenuItem OpenFrameItem(ActionType, ContextMenuItemTagOpenFrameInNewWindow, - contextMenuItemTagOpenFrameInNewWindow()); - ContextMenuItem NoGuessesItem(ActionType, ContextMenuItemTagNoGuessesFound, - contextMenuItemTagNoGuessesFound()); - ContextMenuItem IgnoreSpellingItem(ActionType, ContextMenuItemTagIgnoreSpelling, - contextMenuItemTagIgnoreSpelling()); - ContextMenuItem LearnSpellingItem(ActionType, ContextMenuItemTagLearnSpelling, - contextMenuItemTagLearnSpelling()); - ContextMenuItem IgnoreGrammarItem(ActionType, ContextMenuItemTagIgnoreGrammar, - contextMenuItemTagIgnoreGrammar()); - ContextMenuItem CutItem(ActionType, ContextMenuItemTagCut, contextMenuItemTagCut()); - ContextMenuItem PasteItem(ActionType, ContextMenuItemTagPaste, contextMenuItemTagPaste()); -#if PLATFORM(GTK) - ContextMenuItem DeleteItem(ActionType, ContextMenuItemTagDelete, contextMenuItemTagDelete()); - ContextMenuItem SelectAllItem(ActionType, ContextMenuItemTagSelectAll, contextMenuItemTagSelectAll()); -#endif - - HitTestResult result = hitTestResult(); - - Node* node = m_hitTestResult.innerNonSharedNode(); - if (!node) - return; -#if PLATFORM(GTK) - if (!result.isContentEditable() && (node->isElementNode() && static_cast<Element*>(node)->isFormControlElement())) - return; -#endif - Frame* frame = node->document()->frame(); - if (!frame) - return; - - if (!result.isContentEditable()) { - FrameLoader* loader = frame->loader(); - KURL linkURL = result.absoluteLinkURL(); - if (!linkURL.isEmpty()) { - if (loader->canHandleRequest(ResourceRequest(linkURL))) { - appendItem(OpenLinkItem); - appendItem(OpenLinkInNewWindowItem); - appendItem(DownloadFileItem); - } - appendItem(CopyLinkItem); - } - - KURL imageURL = result.absoluteImageURL(); - if (!imageURL.isEmpty()) { - if (!linkURL.isEmpty()) - appendItem(*separatorItem()); - - appendItem(OpenImageInNewWindowItem); - appendItem(DownloadImageItem); - if (imageURL.isLocalFile() || m_hitTestResult.image()) - appendItem(CopyImageItem); - } - - KURL mediaURL = result.absoluteMediaURL(); - if (!mediaURL.isEmpty()) { - if (!linkURL.isEmpty() || !imageURL.isEmpty()) - appendItem(*separatorItem()); - appendItem(MediaPlayPause); - appendItem(MediaMute); - appendItem(ToggleMediaControls); - appendItem(ToggleMediaLoop); - appendItem(EnterVideoFullscreen); - - appendItem(*separatorItem()); - appendItem(CopyMediaLinkItem); - appendItem(OpenMediaInNewWindowItem); - } - - if (imageURL.isEmpty() && linkURL.isEmpty() && mediaURL.isEmpty()) { - if (result.isSelected()) { - if (selectionContainsPossibleWord(frame)) { -#if PLATFORM(MAC) - appendItem(SearchSpotlightItem); -#endif -#if !PLATFORM(GTK) - appendItem(SearchWebItem); - appendItem(*separatorItem()); -#endif -#if PLATFORM(MAC) - appendItem(LookInDictionaryItem); - appendItem(*separatorItem()); -#endif - } - appendItem(CopyItem); -#if PLATFORM(MAC) - appendItem(*separatorItem()); - ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu()); - createAndAppendSpeechSubMenu(m_hitTestResult, SpeechMenuItem); - appendItem(SpeechMenuItem); -#endif - } else { -#if ENABLE(INSPECTOR) - if (!(frame->page() && frame->page()->inspectorController()->hasInspectorFrontendClient())) { -#endif - if (frame->page() && frame->page()->backForward()->canGoBackOrForward(-1)) - appendItem(BackItem); - - if (frame->page() && frame->page()->backForward()->canGoBackOrForward(1)) - appendItem(ForwardItem); - - // use isLoadingInAPISense rather than isLoading because Stop/Reload are - // intended to match WebKit's API, not WebCore's internal notion of loading status - if (loader->documentLoader()->isLoadingInAPISense()) - appendItem(StopItem); - else - appendItem(ReloadItem); -#if ENABLE(INSPECTOR) - } -#endif - - if (frame->page() && frame != frame->page()->mainFrame()) - appendItem(OpenFrameItem); - } - } - } else { // Make an editing context menu - SelectionController* selection = frame->selection(); - bool inPasswordField = selection->isInPasswordField(); - bool spellCheckingEnabled = frame->editor()->isSpellCheckingEnabledFor(node); - - if (!inPasswordField && spellCheckingEnabled) { - // Consider adding spelling-related or grammar-related context menu items (never both, since a single selected range - // is never considered a misspelling and bad grammar at the same time) - bool misspelling; - bool badGrammar; - Vector<String> guesses = frame->editor()->guessesForMisspelledOrUngrammaticalSelection(misspelling, badGrammar); - if (misspelling || badGrammar) { - size_t size = guesses.size(); - if (size == 0) { - // If there's bad grammar but no suggestions (e.g., repeated word), just leave off the suggestions - // list and trailing separator rather than adding a "No Guesses Found" item (matches AppKit) - if (misspelling) { - appendItem(NoGuessesItem); - appendItem(*separatorItem()); - } - } else { - for (unsigned i = 0; i < size; i++) { - const String &guess = guesses[i]; - if (!guess.isEmpty()) { - ContextMenuItem item(ActionType, ContextMenuItemTagSpellingGuess, guess); - appendItem(item); - } - } - appendItem(*separatorItem()); - } - - if (misspelling) { - appendItem(IgnoreSpellingItem); - appendItem(LearnSpellingItem); - } else - appendItem(IgnoreGrammarItem); - appendItem(*separatorItem()); -#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) - } else { - // If the string was autocorrected, generate a contextual menu item allowing it to be changed back. - String replacedString = result.replacedString(); - if (!replacedString.isEmpty()) { - ContextMenuItem item(ActionType, ContextMenuItemTagChangeBack, contextMenuItemTagChangeBack(replacedString)); - appendItem(item); - appendItem(*separatorItem()); - } -#endif - } - } - - FrameLoader* loader = frame->loader(); - KURL linkURL = result.absoluteLinkURL(); - if (!linkURL.isEmpty()) { - if (loader->canHandleRequest(ResourceRequest(linkURL))) { - appendItem(OpenLinkItem); - appendItem(OpenLinkInNewWindowItem); - appendItem(DownloadFileItem); - } - appendItem(CopyLinkItem); - appendItem(*separatorItem()); - } - - if (result.isSelected() && !inPasswordField && selectionContainsPossibleWord(frame)) { -#if PLATFORM(MAC) - appendItem(SearchSpotlightItem); -#endif -#if !PLATFORM(GTK) - appendItem(SearchWebItem); - appendItem(*separatorItem()); -#endif - -#if PLATFORM(MAC) - appendItem(LookInDictionaryItem); - appendItem(*separatorItem()); -#endif - } - - appendItem(CutItem); - appendItem(CopyItem); - appendItem(PasteItem); -#if PLATFORM(GTK) - appendItem(DeleteItem); - appendItem(*separatorItem()); - appendItem(SelectAllItem); -#endif - - if (!inPasswordField) { - appendItem(*separatorItem()); -#ifndef BUILDING_ON_TIGER -#if !PLATFORM(GTK) - ContextMenuItem SpellingAndGrammarMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu, - contextMenuItemTagSpellingMenu()); - createAndAppendSpellingAndGrammarSubMenu(m_hitTestResult, SpellingAndGrammarMenuItem); - appendItem(SpellingAndGrammarMenuItem); -#endif -#else - ContextMenuItem SpellingMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu, - contextMenuItemTagSpellingMenu()); - createAndAppendSpellingSubMenu(m_hitTestResult, SpellingMenuItem); - appendItem(SpellingMenuItem); -#endif -#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) - ContextMenuItem substitutionsMenuItem(SubmenuType, ContextMenuItemTagSubstitutionsMenu, - contextMenuItemTagSubstitutionsMenu()); - createAndAppendSubstitutionsSubMenu(m_hitTestResult, substitutionsMenuItem); - appendItem(substitutionsMenuItem); - ContextMenuItem transformationsMenuItem(SubmenuType, ContextMenuItemTagTransformationsMenu, - contextMenuItemTagTransformationsMenu()); - createAndAppendTransformationsSubMenu(m_hitTestResult, transformationsMenuItem); - appendItem(transformationsMenuItem); -#endif -#if PLATFORM(GTK) - bool shouldShowFontMenu = frame->editor()->canEditRichly(); -#else - bool shouldShowFontMenu = true; -#endif - if (shouldShowFontMenu) { - ContextMenuItem FontMenuItem(SubmenuType, ContextMenuItemTagFontMenu, - contextMenuItemTagFontMenu()); - createAndAppendFontSubMenu(m_hitTestResult, FontMenuItem); - appendItem(FontMenuItem); - } -#if PLATFORM(MAC) - ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu()); - createAndAppendSpeechSubMenu(m_hitTestResult, SpeechMenuItem); - appendItem(SpeechMenuItem); -#endif -#if !PLATFORM(GTK) - ContextMenuItem WritingDirectionMenuItem(SubmenuType, ContextMenuItemTagWritingDirectionMenu, - contextMenuItemTagWritingDirectionMenu()); - createAndAppendWritingDirectionSubMenu(m_hitTestResult, WritingDirectionMenuItem); - appendItem(WritingDirectionMenuItem); - if (Page* page = frame->page()) { - if (Settings* settings = page->settings()) { - bool includeTextDirectionSubmenu = settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAlwaysIncluded - || (settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAutomaticallyIncluded && frame->editor()->hasBidiSelection()); - if (includeTextDirectionSubmenu) { - ContextMenuItem TextDirectionMenuItem(SubmenuType, ContextMenuItemTagTextDirectionMenu, - contextMenuItemTagTextDirectionMenu()); - createAndAppendTextDirectionSubMenu(m_hitTestResult, TextDirectionMenuItem); - appendItem(TextDirectionMenuItem); - } - } - } -#endif - } - } -} - -#if ENABLE(INSPECTOR) -void ContextMenu::addInspectElementItem() -{ - Node* node = m_hitTestResult.innerNonSharedNode(); - if (!node) - return; - - Frame* frame = node->document()->frame(); - if (!frame) - return; - - Page* page = frame->page(); - if (!page) - return; - - if (!page->inspectorController()) - return; - - ContextMenuItem InspectElementItem(ActionType, ContextMenuItemTagInspectElement, contextMenuItemTagInspectElement()); - appendItem(*separatorItem()); - appendItem(InspectElementItem); + return 0; } -#endif // ENABLE(INSPECTOR) -void ContextMenu::checkOrEnableIfNeeded(ContextMenuItem& item) const +ContextMenuItem* ContextMenu::itemWithAction(unsigned action) { - if (item.type() == SeparatorType) - return; - - Frame* frame = m_hitTestResult.innerNonSharedNode()->document()->frame(); - if (!frame) - return; - - // Custom items already have proper checked and enabled values. - if (ContextMenuItemBaseCustomTag <= item.action() && item.action() <= ContextMenuItemLastCustomTag) - return; - - bool shouldEnable = true; - bool shouldCheck = false; - - switch (item.action()) { - case ContextMenuItemTagCheckSpelling: - shouldEnable = frame->editor()->canEdit(); - break; - case ContextMenuItemTagDefaultDirection: - shouldCheck = false; - shouldEnable = false; - break; - case ContextMenuItemTagLeftToRight: - case ContextMenuItemTagRightToLeft: { - ExceptionCode ec = 0; - RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration(); - String direction = item.action() == ContextMenuItemTagLeftToRight ? "ltr" : "rtl"; - style->setProperty(CSSPropertyDirection, direction, false, ec); - shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState; - shouldEnable = true; - break; - } - case ContextMenuItemTagTextDirectionDefault: { - Editor::Command command = frame->editor()->command("MakeTextWritingDirectionNatural"); - shouldCheck = command.state() == TrueTriState; - shouldEnable = command.isEnabled(); - break; - } - case ContextMenuItemTagTextDirectionLeftToRight: { - Editor::Command command = frame->editor()->command("MakeTextWritingDirectionLeftToRight"); - shouldCheck = command.state() == TrueTriState; - shouldEnable = command.isEnabled(); - break; - } - case ContextMenuItemTagTextDirectionRightToLeft: { - Editor::Command command = frame->editor()->command("MakeTextWritingDirectionRightToLeft"); - shouldCheck = command.state() == TrueTriState; - shouldEnable = command.isEnabled(); - break; - } - case ContextMenuItemTagCopy: - shouldEnable = frame->editor()->canDHTMLCopy() || frame->editor()->canCopy(); - break; - case ContextMenuItemTagCut: - shouldEnable = frame->editor()->canDHTMLCut() || frame->editor()->canCut(); - break; - case ContextMenuItemTagIgnoreSpelling: - case ContextMenuItemTagLearnSpelling: - shouldEnable = frame->selection()->isRange(); - break; - case ContextMenuItemTagPaste: - shouldEnable = frame->editor()->canDHTMLPaste() || frame->editor()->canPaste(); - break; -#if PLATFORM(GTK) - case ContextMenuItemTagDelete: - shouldEnable = frame->editor()->canDelete(); - break; - case ContextMenuItemTagSelectAll: - case ContextMenuItemTagInputMethods: - case ContextMenuItemTagUnicode: - shouldEnable = true; - break; -#endif - case ContextMenuItemTagUnderline: { - ExceptionCode ec = 0; - RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration(); - style->setProperty(CSSPropertyWebkitTextDecorationsInEffect, "underline", false, ec); - shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState; - shouldEnable = frame->editor()->canEditRichly(); - break; - } - case ContextMenuItemTagLookUpInDictionary: - shouldEnable = frame->selection()->isRange(); - break; - case ContextMenuItemTagCheckGrammarWithSpelling: -#ifndef BUILDING_ON_TIGER - if (frame->editor()->isGrammarCheckingEnabled()) - shouldCheck = true; - shouldEnable = true; -#endif - break; - case ContextMenuItemTagItalic: { - ExceptionCode ec = 0; - RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration(); - style->setProperty(CSSPropertyFontStyle, "italic", false, ec); - shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState; - shouldEnable = frame->editor()->canEditRichly(); - break; - } - case ContextMenuItemTagBold: { - ExceptionCode ec = 0; - RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration(); - style->setProperty(CSSPropertyFontWeight, "bold", false, ec); - shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState; - shouldEnable = frame->editor()->canEditRichly(); - break; - } - case ContextMenuItemTagOutline: - shouldEnable = false; - break; - case ContextMenuItemTagShowSpellingPanel: -#ifndef BUILDING_ON_TIGER - if (frame->editor()->spellingPanelIsShowing()) - item.setTitle(contextMenuItemTagShowSpellingPanel(false)); - else - item.setTitle(contextMenuItemTagShowSpellingPanel(true)); -#endif - shouldEnable = frame->editor()->canEdit(); - break; - case ContextMenuItemTagNoGuessesFound: - shouldEnable = false; - break; - case ContextMenuItemTagCheckSpellingWhileTyping: - shouldCheck = frame->editor()->isContinuousSpellCheckingEnabled(); - break; -#if PLATFORM(MAC) - case ContextMenuItemTagSubstitutionsMenu: - case ContextMenuItemTagTransformationsMenu: - break; - case ContextMenuItemTagShowSubstitutions: -#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) - if (frame->editor()->substitutionsPanelIsShowing()) - item.setTitle(contextMenuItemTagShowSubstitutions(false)); - else - item.setTitle(contextMenuItemTagShowSubstitutions(true)); - shouldEnable = frame->editor()->canEdit(); -#endif - break; - case ContextMenuItemTagMakeUpperCase: - case ContextMenuItemTagMakeLowerCase: - case ContextMenuItemTagCapitalize: - case ContextMenuItemTagChangeBack: - shouldEnable = frame->editor()->canEdit(); - break; - case ContextMenuItemTagCorrectSpellingAutomatically: -#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) - shouldCheck = frame->editor()->isAutomaticSpellingCorrectionEnabled(); -#endif - break; - case ContextMenuItemTagSmartCopyPaste: -#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) - shouldCheck = frame->editor()->smartInsertDeleteEnabled(); -#endif - break; - case ContextMenuItemTagSmartQuotes: -#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) - shouldCheck = frame->editor()->isAutomaticQuoteSubstitutionEnabled(); -#endif - break; - case ContextMenuItemTagSmartDashes: -#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) - shouldCheck = frame->editor()->isAutomaticDashSubstitutionEnabled(); -#endif - break; - case ContextMenuItemTagSmartLinks: -#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) - shouldCheck = frame->editor()->isAutomaticLinkDetectionEnabled(); -#endif - break; - case ContextMenuItemTagTextReplacement: -#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) - shouldCheck = frame->editor()->isAutomaticTextReplacementEnabled(); -#endif - break; - case ContextMenuItemTagStopSpeaking: - shouldEnable = controller() && controller()->client() && controller()->client()->isSpeaking(); - break; -#else // PLATFORM(MAC) ends here - case ContextMenuItemTagStopSpeaking: - break; -#endif -#if PLATFORM(GTK) - case ContextMenuItemTagGoBack: - shouldEnable = frame->page() && frame->page()->backForward()->canGoBackOrForward(-1); - break; - case ContextMenuItemTagGoForward: - shouldEnable = frame->page() && frame->page()->backForward()->canGoBackOrForward(1); - break; - case ContextMenuItemTagStop: - shouldEnable = frame->loader()->documentLoader()->isLoadingInAPISense(); - break; - case ContextMenuItemTagReload: - shouldEnable = !frame->loader()->documentLoader()->isLoadingInAPISense(); - break; - case ContextMenuItemTagFontMenu: - shouldEnable = frame->editor()->canEditRichly(); - break; -#else - case ContextMenuItemTagGoBack: - case ContextMenuItemTagGoForward: - case ContextMenuItemTagStop: - case ContextMenuItemTagReload: - case ContextMenuItemTagFontMenu: -#endif - case ContextMenuItemTagNoAction: - case ContextMenuItemTagOpenLinkInNewWindow: - case ContextMenuItemTagDownloadLinkToDisk: - case ContextMenuItemTagCopyLinkToClipboard: - case ContextMenuItemTagOpenImageInNewWindow: - case ContextMenuItemTagDownloadImageToDisk: - case ContextMenuItemTagCopyImageToClipboard: - break; - case ContextMenuItemTagOpenMediaInNewWindow: - if (m_hitTestResult.mediaIsVideo()) - item.setTitle(contextMenuItemTagOpenVideoInNewWindow()); - else - item.setTitle(contextMenuItemTagOpenAudioInNewWindow()); - break; - case ContextMenuItemTagCopyMediaLinkToClipboard: - if (m_hitTestResult.mediaIsVideo()) - item.setTitle(contextMenuItemTagCopyVideoLinkToClipboard()); - else - item.setTitle(contextMenuItemTagCopyAudioLinkToClipboard()); - break; - case ContextMenuItemTagToggleMediaControls: - shouldCheck = m_hitTestResult.mediaControlsEnabled(); - break; - case ContextMenuItemTagToggleMediaLoop: - shouldCheck = m_hitTestResult.mediaLoopEnabled(); - break; - case ContextMenuItemTagEnterVideoFullscreen: - shouldEnable = m_hitTestResult.mediaSupportsFullscreen(); - break; - case ContextMenuItemTagOpenFrameInNewWindow: - case ContextMenuItemTagSpellingGuess: - case ContextMenuItemTagOther: - case ContextMenuItemTagSearchInSpotlight: - case ContextMenuItemTagSearchWeb: - case ContextMenuItemTagOpenWithDefaultApplication: - case ContextMenuItemPDFActualSize: - case ContextMenuItemPDFZoomIn: - case ContextMenuItemPDFZoomOut: - case ContextMenuItemPDFAutoSize: - case ContextMenuItemPDFSinglePage: - case ContextMenuItemPDFFacingPages: - case ContextMenuItemPDFContinuous: - case ContextMenuItemPDFNextPage: - case ContextMenuItemPDFPreviousPage: - case ContextMenuItemTagOpenLink: - case ContextMenuItemTagIgnoreGrammar: - case ContextMenuItemTagSpellingMenu: - case ContextMenuItemTagShowFonts: - case ContextMenuItemTagStyles: - case ContextMenuItemTagShowColors: - case ContextMenuItemTagSpeechMenu: - case ContextMenuItemTagStartSpeaking: - case ContextMenuItemTagWritingDirectionMenu: - case ContextMenuItemTagTextDirectionMenu: - case ContextMenuItemTagPDFSinglePageScrolling: - case ContextMenuItemTagPDFFacingPagesScrolling: -#if ENABLE(INSPECTOR) - case ContextMenuItemTagInspectElement: -#endif - case ContextMenuItemBaseCustomTag: - case ContextMenuItemCustomTagNoAction: - case ContextMenuItemLastCustomTag: - case ContextMenuItemBaseApplicationTag: - break; - case ContextMenuItemTagMediaPlayPause: - if (m_hitTestResult.mediaPlaying()) - item.setTitle(contextMenuItemTagMediaPause()); - else - item.setTitle(contextMenuItemTagMediaPlay()); - break; - case ContextMenuItemTagMediaMute: - shouldEnable = m_hitTestResult.mediaHasAudio(); - shouldCheck = shouldEnable && m_hitTestResult.mediaMuted(); - break; - } - - item.setChecked(shouldCheck); - item.setEnabled(shouldEnable); + // FIXME: When more platforms switch over, this fucntion should return a const ContextMenuItem*'s, and the const_cast + // won't be needed anymore. + return const_cast<ContextMenuItem*>(findItemWithAction(action, m_items)); } } // namespace WebCore -#endif // ENABLE(CONTEXT_MENUS) +#endif // USE(CROSS_PLATFORM_CONTEXT_MENUS) diff --git a/WebCore/platform/ContextMenu.h b/WebCore/platform/ContextMenu.h index 5321ed6..575c86d 100644 --- a/WebCore/platform/ContextMenu.h +++ b/WebCore/platform/ContextMenu.h @@ -29,7 +29,6 @@ #include <wtf/Noncopyable.h> #include "ContextMenuItem.h" -#include "HitTestResult.h" #include "PlatformMenuDescription.h" #include "PlatformString.h" #if PLATFORM(MAC) @@ -41,41 +40,60 @@ namespace WebCore { class ContextMenuController; -#if PLATFORM(EFL) - class ContextMenuClientEfl; -#endif class ContextMenu : public Noncopyable { public: - ContextMenu(const HitTestResult&); - ContextMenu(const HitTestResult&, const PlatformMenuDescription); - ~ContextMenu(); + ContextMenu(); + + ContextMenuItem* itemWithAction(unsigned); + +#if USE(CROSS_PLATFORM_CONTEXT_MENUS) +#if PLATFORM(WIN) + typedef HMENU NativeMenu; +#elif PLATFORM(EFL) + typedef void* NativeMenu; +#endif + explicit ContextMenu(NativeMenu); - void populate(); - void addInspectElementItem(); - void checkOrEnableIfNeeded(ContextMenuItem&) const; + NativeMenu nativeMenu() const; + + static NativeMenu createNativeMenuFromItems(const Vector<ContextMenuItem>&); + static void getContextMenuItems(NativeMenu, Vector<ContextMenuItem>&); + + // FIXME: When more platforms switch over, this should return const ContextMenuItem*'s. + ContextMenuItem* itemAtIndex(unsigned index) { return &m_items[index]; } + + void setItems(const Vector<ContextMenuItem>& items) { m_items = items; } + const Vector<ContextMenuItem>& items() const { return m_items; } + + void appendItem(const ContextMenuItem& item) { m_items.append(item); } +#else + ContextMenu(const PlatformMenuDescription); + ~ContextMenu(); void insertItem(unsigned position, ContextMenuItem&); void appendItem(ContextMenuItem&); - - ContextMenuItem* itemWithAction(unsigned); + ContextMenuItem* itemAtIndex(unsigned, const PlatformMenuDescription); unsigned itemCount() const; - HitTestResult hitTestResult() const { return m_hitTestResult; } - ContextMenuController* controller() const; - PlatformMenuDescription platformDescription() const; void setPlatformDescription(PlatformMenuDescription); PlatformMenuDescription releasePlatformDescription(); + #if PLATFORM(WX) static ContextMenuItem* itemWithId(int); #endif + +#endif // USE(CROSS_PLATFORM_CONTEXT_MENUS) + private: - HitTestResult m_hitTestResult; +#if USE(CROSS_PLATFORM_CONTEXT_MENUS) + Vector<ContextMenuItem> m_items; +#else #if PLATFORM(MAC) // Keep this in sync with the PlatformMenuDescription typedef RetainPtr<NSMutableArray> m_platformDescription; @@ -83,19 +101,20 @@ namespace WebCore { QList<ContextMenuItem> m_items; #elif PLATFORM(CHROMIUM) Vector<ContextMenuItem> m_items; -#elif PLATFORM(EFL) - ContextMenuClientEfl* m_contextMenuClient; - PlatformMenuDescription m_platformDescription; #else PlatformMenuDescription m_platformDescription; #if OS(WINCE) unsigned m_itemCount; #endif #endif + +#endif // USE(CROSS_PLATFORM_CONTEXT_MENUS) }; +#if !USE(CROSS_PLATFORM_CONTEXT_MENUS) Vector<ContextMenuItem> contextMenuItemVector(PlatformMenuDescription); PlatformMenuDescription platformMenuDescription(Vector<ContextMenuItem>&); +#endif } diff --git a/WebCore/platform/ContextMenuItem.cpp b/WebCore/platform/ContextMenuItem.cpp new file mode 100644 index 0000000..0c2a6ea --- /dev/null +++ b/WebCore/platform/ContextMenuItem.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ContextMenuItem.h" + +#include "ContextMenu.h" + +#if USE(CROSS_PLATFORM_CONTEXT_MENUS) + +namespace WebCore { + +ContextMenuItem::ContextMenuItem(ContextMenuItemType type, ContextMenuAction action, const String& title, ContextMenu* subMenu) + : m_type(type) + , m_action(action) + , m_title(title) + , m_enabled(true) + , m_checked(false) +{ + if (subMenu) + setSubMenu(subMenu); +} + +ContextMenuItem::ContextMenuItem(ContextMenuItemType type, ContextMenuAction action, const String& title, bool enabled, bool checked) + : m_type(type) + , m_action(action) + , m_title(title) + , m_enabled(enabled) + , m_checked(checked) +{ +} + +ContextMenuItem::ContextMenuItem(ContextMenuAction action, const String& title, bool enabled, bool checked, const Vector<ContextMenuItem>& subMenuItems) + : m_type(SubmenuType) + , m_action(action) + , m_title(title) + , m_enabled(enabled) + , m_checked(checked) + , m_subMenuItems(subMenuItems) +{ +} + +ContextMenuItem::~ContextMenuItem() +{ +} + +void ContextMenuItem::setSubMenu(ContextMenu* subMenu) +{ + if (subMenu) { + m_type = SubmenuType; + m_subMenuItems = subMenu->items(); + } else { + m_type = ActionType; + m_subMenuItems.clear(); + } +} + +void ContextMenuItem::setType(ContextMenuItemType type) +{ + m_type = type; +} + +ContextMenuItemType ContextMenuItem::type() const +{ + return m_type; +} + +void ContextMenuItem::setAction(ContextMenuAction action) +{ + m_action = action; +} + +ContextMenuAction ContextMenuItem::action() const +{ + return m_action; +} + +void ContextMenuItem::setChecked(bool checked) +{ + m_checked = checked; +} + +bool ContextMenuItem::checked() const +{ + return m_checked; +} + +void ContextMenuItem::setEnabled(bool enabled) +{ + m_enabled = enabled; +} + +bool ContextMenuItem::enabled() const +{ + return m_enabled; +} + +} // namespace WebCore + +#endif // USE(CROSS_PLATFORM_CONTEXT_MENUS) diff --git a/WebCore/platform/ContextMenuItem.h b/WebCore/platform/ContextMenuItem.h index 063788b..2d29010 100644 --- a/WebCore/platform/ContextMenuItem.h +++ b/WebCore/platform/ContextMenuItem.h @@ -40,8 +40,9 @@ class NSMenuItem; #endif #elif PLATFORM(WIN) -typedef struct tagMENUITEMINFOW* LPMENUITEMINFO; +typedef struct tagMENUITEMINFOW MENUITEMINFO; #elif PLATFORM(GTK) +#include <GRefPtr.h> typedef struct _GtkMenuItem GtkMenuItem; #elif PLATFORM(QT) #include <QAction> @@ -166,8 +167,6 @@ namespace WebCore { #if PLATFORM(MAC) typedef NSMenuItem* PlatformMenuItemDescription; -#elif PLATFORM(WIN) - typedef LPMENUITEMINFO PlatformMenuItemDescription; #elif PLATFORM(QT) struct PlatformMenuItemDescription { PlatformMenuItemDescription() @@ -185,6 +184,7 @@ namespace WebCore { bool enabled; }; #elif PLATFORM(GTK) +<<<<<<< HEAD struct PlatformMenuItemDescription { PlatformMenuItemDescription() : type(ActionType) @@ -203,6 +203,9 @@ namespace WebCore { }; #elif defined ANDROID typedef void* PlatformMenuItemDescription; +======= + typedef GtkMenuItem* PlatformMenuItemDescription; +>>>>>>> webkit.org at r74534 (trunk) #elif PLATFORM(WX) struct PlatformMenuItemDescription { PlatformMenuItemDescription() @@ -234,53 +237,22 @@ namespace WebCore { bool checked; bool enabled; }; -#elif PLATFORM(EFL) - struct PlatformMenuItemDescription { - PlatformMenuItemDescription() - : type(ActionType) - , action(ContextMenuItemTagNoAction) - , title("") - , subMenu(0) - , checked(false) - , enabled(true) { } - ContextMenuItemType type; - ContextMenuAction action; - String title; - ContextMenu* subMenu; - bool checked; - bool enabled; - }; #else typedef void* PlatformMenuItemDescription; #endif class ContextMenuItem : public FastAllocBase { public: - ContextMenuItem(PlatformMenuItemDescription); - ContextMenuItem(ContextMenu* subMenu = 0); - ContextMenuItem(ContextMenuItemType type, ContextMenuAction action, const String& title, ContextMenu* subMenu = 0); - + ContextMenuItem(ContextMenuItemType, ContextMenuAction, const String&, ContextMenu* subMenu = 0); ContextMenuItem(ContextMenuItemType, ContextMenuAction, const String&, bool enabled, bool checked); - ContextMenuItem(ContextMenuAction, const String&, bool enabled, bool checked, Vector<ContextMenuItem>& submenuItems); -#if PLATFORM(GTK) - ContextMenuItem(GtkMenuItem*); -#endif - ~ContextMenuItem(); - PlatformMenuItemDescription releasePlatformDescription(); + ~ContextMenuItem(); - ContextMenuItemType type() const; void setType(ContextMenuItemType); + ContextMenuItemType type() const; - ContextMenuAction action() const; void setAction(ContextMenuAction); - - String title() const; - void setTitle(const String&); - - PlatformMenuDescription platformSubMenu() const; - void setSubMenu(ContextMenu*); - void setSubMenu(Vector<ContextMenuItem>&); + ContextMenuAction action() const; void setChecked(bool = true); bool checked() const; @@ -288,17 +260,57 @@ namespace WebCore { void setEnabled(bool = true); bool enabled() const; - // FIXME: Do we need a keyboard accelerator here? -#if PLATFORM(GTK) - static GtkMenuItem* createNativeMenuItem(const PlatformMenuItemDescription&); + void setSubMenu(ContextMenu*); + +#if USE(CROSS_PLATFORM_CONTEXT_MENUS) +#if PLATFORM(WIN) + typedef MENUITEMINFO NativeItem; +#elif PLATFORM(EFL) + typedef void* NativeItem; #endif + ContextMenuItem(ContextMenuAction, const String&, bool enabled, bool checked, const Vector<ContextMenuItem>& subMenuItems); + explicit ContextMenuItem(const NativeItem&); + + // On Windows, the title (dwTypeData of the MENUITEMINFO) is not set in this function. Callers can set the title themselves, + // and handle the lifetime of the title, if they need it. + NativeItem nativeMenuItem() const; + + void setTitle(const String& title) { m_title = title; } + const String& title() const { return m_title; } + + const Vector<ContextMenuItem>& subMenuItems() const { return m_subMenuItems; } +#else + public: + ContextMenuItem(PlatformMenuItemDescription); + ContextMenuItem(ContextMenu* subMenu = 0); + ContextMenuItem(ContextMenuAction, const String&, bool enabled, bool checked, Vector<ContextMenuItem>& submenuItems); + + PlatformMenuItemDescription releasePlatformDescription(); + + String title() const; + void setTitle(const String&); + PlatformMenuDescription platformSubMenu() const; + void setSubMenu(Vector<ContextMenuItem>&); + +#endif // USE(CROSS_PLATFORM_CONTEXT_MENUS) private: +#if USE(CROSS_PLATFORM_CONTEXT_MENUS) + String m_title; + bool m_enabled; + bool m_checked; + ContextMenuAction m_action; + ContextMenuItemType m_type; + Vector<ContextMenuItem> m_subMenuItems; +#else #if PLATFORM(MAC) RetainPtr<NSMenuItem> m_platformDescription; +#elif PLATFORM(GTK) + PlatformRefPtr<GtkMenuItem> m_platformDescription; #else PlatformMenuItemDescription m_platformDescription; #endif +#endif // USE(CROSS_PLATFORM_CONTEXT_MENUS) }; } diff --git a/WebCore/platform/PlatformMenuDescription.h b/WebCore/platform/PlatformMenuDescription.h index c986207..5e3541a 100644 --- a/WebCore/platform/PlatformMenuDescription.h +++ b/WebCore/platform/PlatformMenuDescription.h @@ -32,8 +32,6 @@ #else class NSMutableArray; #endif -#elif PLATFORM(WIN) -typedef struct HMENU__* HMENU; #elif PLATFORM(QT) #include <qlist.h> #elif PLATFORM(GTK) @@ -46,10 +44,9 @@ class BMenu; namespace WebCore { +#if !USE(CROSS_PLATFORM_CONTEXT_MENUS) #if PLATFORM(MAC) typedef NSMutableArray* PlatformMenuDescription; -#elif PLATFORM(WIN) - typedef HMENU PlatformMenuDescription; #elif PLATFORM(QT) class ContextMenuItem; typedef const QList<ContextMenuItem>* PlatformMenuDescription; @@ -65,6 +62,7 @@ namespace WebCore { #else typedef void* PlatformMenuDescription; #endif +#endif // !USE(CROSS_PLATFORM_CONTEXT_MENUS) } // namespace diff --git a/WebCore/platform/ScrollTypes.h b/WebCore/platform/ScrollTypes.h index eba9055..f07fb1a 100644 --- a/WebCore/platform/ScrollTypes.h +++ b/WebCore/platform/ScrollTypes.h @@ -35,6 +35,72 @@ namespace WebCore { ScrollRight }; + enum ScrollLogicalDirection { + ScrollBlockDirectionBackward, + ScrollBlockDirectionForward, + ScrollInlineDirectionBackward, + ScrollInlineDirectionForward + }; + + + inline ScrollDirection logicalToPhysical(ScrollLogicalDirection direction, bool isVertical, bool isFlipped) + { + switch (direction) { + case ScrollBlockDirectionBackward: { + if (isVertical) { + if (!isFlipped) + return ScrollUp; + return ScrollDown; + } else { + if (!isFlipped) + return ScrollLeft; + return ScrollRight; + } + break; + } + case ScrollBlockDirectionForward: { + if (isVertical) { + if (!isFlipped) + return ScrollDown; + return ScrollUp; + } else { + if (!isFlipped) + return ScrollRight; + return ScrollLeft; + } + break; + } + case ScrollInlineDirectionBackward: { + if (isVertical) { + if (!isFlipped) + return ScrollLeft; + return ScrollRight; + } else { + if (!isFlipped) + return ScrollUp; + return ScrollDown; + } + break; + } + case ScrollInlineDirectionForward: { + if (isVertical) { + if (!isFlipped) + return ScrollRight; + return ScrollLeft; + } else { + if (!isFlipped) + return ScrollDown; + return ScrollUp; + } + break; + } + default: + ASSERT_NOT_REACHED(); + break; + } + return ScrollUp; + } + enum ScrollGranularity { ScrollByLine, ScrollByPage, diff --git a/WebCore/platform/ScrollView.cpp b/WebCore/platform/ScrollView.cpp index 4f83794..ddce20c 100644 --- a/WebCore/platform/ScrollView.cpp +++ b/WebCore/platform/ScrollView.cpp @@ -54,7 +54,6 @@ ScrollView::ScrollView() , m_useFixedLayout(false) , m_paintsEntireContents(false) , m_delegatesScrolling(false) - , m_scrollOriginX(0) { platformInit(); } @@ -309,14 +308,14 @@ int ScrollView::actualScrollY() const IntPoint ScrollView::maximumScrollPosition() const { - IntPoint maximumOffset(contentsWidth() - visibleWidth() - m_scrollOriginX, contentsHeight() - visibleHeight()); + IntPoint maximumOffset(contentsWidth() - visibleWidth() - m_scrollOrigin.x(), contentsHeight() - visibleHeight() - m_scrollOrigin.y()); maximumOffset.clampNegativeToZero(); return maximumOffset; } IntPoint ScrollView::minimumScrollPosition() const { - return IntPoint(-m_scrollOriginX, 0); + return IntPoint(-m_scrollOrigin.x(), -m_scrollOrigin.y()); } IntPoint ScrollView::adjustScrollPositionWithinRange(const IntPoint& scrollPoint) const @@ -346,9 +345,9 @@ void ScrollView::valueChanged(Scrollbar* scrollbar) IntSize newOffset = m_scrollOffset; if (scrollbar) { if (scrollbar->orientation() == HorizontalScrollbar) - newOffset.setWidth(scrollbar->value() - m_scrollOriginX); + newOffset.setWidth(scrollbar->value() - m_scrollOrigin.x()); else if (scrollbar->orientation() == VerticalScrollbar) - newOffset.setHeight(scrollbar->value()); + newOffset.setHeight(scrollbar->value() - m_scrollOrigin.y()); } IntSize scrollDelta = newOffset - m_scrollOffset; @@ -403,7 +402,7 @@ bool ScrollView::scroll(ScrollDirection direction, ScrollGranularity granularity { if (platformWidget()) return platformScroll(direction, granularity); - + if (direction == ScrollUp || direction == ScrollDown) { if (m_verticalScrollbar) return m_verticalScrollbar->scroll(direction, granularity); @@ -414,6 +413,11 @@ bool ScrollView::scroll(ScrollDirection direction, ScrollGranularity granularity return false; } +bool ScrollView::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity) +{ + return scroll(logicalToPhysical(direction, isVerticalDocument(), isFlippedDocument()), granularity); +} + void ScrollView::windowResizerRectChanged() { if (platformWidget()) @@ -482,11 +486,15 @@ void ScrollView::updateScrollbars(const IntSize& desiredOffset) newHasHorizontalScrollbar = false; if (hasHorizontalScrollbar != newHasHorizontalScrollbar) { + if (m_scrollOrigin.y() && !newHasHorizontalScrollbar) + m_scrollOrigin.setY(m_scrollOrigin.y() - m_horizontalScrollbar->height()); setHasHorizontalScrollbar(newHasHorizontalScrollbar); sendContentResizedNotification = true; } if (hasVerticalScrollbar != newHasVerticalScrollbar) { + if (m_scrollOrigin.x() && !newHasVerticalScrollbar) + m_scrollOrigin.setX(m_scrollOrigin.x() - m_verticalScrollbar->width()); setHasVerticalScrollbar(newHasVerticalScrollbar); sendContentResizedNotification = true; } @@ -533,7 +541,7 @@ void ScrollView::updateScrollbars(const IntSize& desiredOffset) m_horizontalScrollbar->setSuppressInvalidation(true); m_horizontalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep); m_horizontalScrollbar->setProportion(clientWidth, contentsWidth()); - m_horizontalScrollbar->setValue(scroll.width() + m_scrollOriginX, Scrollbar::NotFromScrollAnimator); + m_horizontalScrollbar->setValue(scroll.width() + m_scrollOrigin.x(), Scrollbar::NotFromScrollAnimator); if (m_scrollbarsSuppressed) m_horizontalScrollbar->setSuppressInvalidation(false); } @@ -555,7 +563,7 @@ void ScrollView::updateScrollbars(const IntSize& desiredOffset) m_verticalScrollbar->setSuppressInvalidation(true); m_verticalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep); m_verticalScrollbar->setProportion(clientHeight, contentsHeight()); - m_verticalScrollbar->setValue(scroll.height(), Scrollbar::NotFromScrollAnimator); + m_verticalScrollbar->setValue(scroll.height() + m_scrollOrigin.y(), Scrollbar::NotFromScrollAnimator); if (m_scrollbarsSuppressed) m_verticalScrollbar->setSuppressInvalidation(false); } @@ -1061,19 +1069,21 @@ void ScrollView::removePanScrollIcon() hostWindow()->invalidateContentsAndWindow(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)), true /*immediate*/); } -void ScrollView::setScrollOriginX(int x) +void ScrollView::setScrollOrigin(const IntPoint& origin, bool updatePosition) { - if (platformWidget()) - platformSetScrollOriginX(x); + if (m_scrollOrigin == origin) + return; - m_scrollOriginX = x; -} + m_scrollOrigin = origin; -void ScrollView::updateScrollbars() -{ - if (!platformWidget()) + if (platformWidget()) { + platformSetScrollOrigin(origin, updatePosition); + return; + } + + // Update if the scroll origin changes, since our position will be different if the content size did not change. + if (updatePosition) updateScrollbars(scrollOffset()); - // FIXME: need corresponding functionality from platformWidget. } #if !PLATFORM(WX) && !PLATFORM(GTK) && !PLATFORM(EFL) @@ -1106,7 +1116,7 @@ void ScrollView::platformSetScrollbarsSuppressed(bool) { } -void ScrollView::platformSetScrollOriginX(int) +void ScrollView::platformSetScrollOrigin(const IntPoint&, bool updatePosition) { } diff --git a/WebCore/platform/ScrollView.h b/WebCore/platform/ScrollView.h index 3627283..6f7ec8b 100644 --- a/WebCore/platform/ScrollView.h +++ b/WebCore/platform/ScrollView.h @@ -168,7 +168,7 @@ public: IntSize scrollOffset() const { return visibleContentRect().location() - IntPoint(); } // Gets the scrolled position as an IntSize. Convenient for adding to other sizes. IntPoint maximumScrollPosition() const; // The maximum position we can be scrolled to. IntPoint minimumScrollPosition() const; // The minimum position we can be scrolled to. - // Adjust the pass in scroll position within the minimum and maximum positions. + // Adjust the passed in scroll position to keep it between the minimum and maximum positions. IntPoint adjustScrollPositionWithinRange(const IntPoint&) const; int scrollX() const { return scrollPosition().x(); } int scrollY() const { return scrollPosition().y(); } @@ -179,7 +179,10 @@ public: // This function scrolls by lines, pages or pixels. bool scroll(ScrollDirection, ScrollGranularity); - + + // A logical scroll that just ends up calling the corresponding physical scroll() based off the document's writing mode. + bool logicalScroll(ScrollLogicalDirection, ScrollGranularity); + // Scroll the actual contents of the view (either blitting or invalidating as needed). void scrollContents(const IntSize& scrollDelta); @@ -289,9 +292,12 @@ protected: // Scroll the content by invalidating everything. virtual void scrollContentsSlowPath(const IntRect& updateRect); - void setScrollOriginX(int); - int scrollOriginX() { return m_scrollOriginX; } - void updateScrollbars(); + void setScrollOrigin(const IntPoint&, bool updatePosition); + IntPoint scrollOrigin() { return m_scrollOrigin; } + + // Subclassed by FrameView to check the writing-mode of the document. + virtual bool isVerticalDocument() const { return true; } + virtual bool isFlippedDocument() const { return false; } private: RefPtr<Scrollbar> m_horizontalScrollbar; @@ -328,10 +334,18 @@ private: bool m_paintsEntireContents; bool m_delegatesScrolling; - // m_scrollOriginX is 0 for LTR page. And it is negative of left layout - // overflow for RTL page. It is mainly used to set the horizontal scrollbar - // position for RTL page. - int m_scrollOriginX; + // 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; void init(); void destroy(); @@ -361,7 +375,7 @@ private: void platformRepaintContentRectangle(const IntRect&, bool now); bool platformIsOffscreen() const; - void platformSetScrollOriginX(int); + void platformSetScrollOrigin(const IntPoint&, bool updatePosition); #if PLATFORM(ANDROID) int platformActualWidth() const; diff --git a/WebCore/platform/ThemeTypes.h b/WebCore/platform/ThemeTypes.h index 3567004..ec45cb7 100644 --- a/WebCore/platform/ThemeTypes.h +++ b/WebCore/platform/ThemeTypes.h @@ -56,9 +56,9 @@ enum ControlPart { SliderHorizontalPart, SliderVerticalPart, SliderThumbHorizontalPart, SliderThumbVerticalPart, CaretPart, SearchFieldPart, SearchFieldDecorationPart, SearchFieldResultsDecorationPart, SearchFieldResultsButtonPart, - SearchFieldCancelButtonPart, TextFieldPart, CapsLockIndicatorPart, + SearchFieldCancelButtonPart, TextFieldPart, RelevancyLevelIndicatorPart, ContinuousCapacityLevelIndicatorPart, DiscreteCapacityLevelIndicatorPart, RatingLevelIndicatorPart, - TextAreaPart + TextAreaPart, CapsLockIndicatorPart }; enum SelectionPart { diff --git a/WebCore/platform/UUID.cpp b/WebCore/platform/UUID.cpp index faad008..5c2e076 100644 --- a/WebCore/platform/UUID.cpp +++ b/WebCore/platform/UUID.cpp @@ -55,7 +55,7 @@ static const int uuidVersionIdentifierIndex = 14; String createCanonicalUUIDString() { -#if PLATFORM(QT) +#if PLATFORM(QT) && !defined(QT_NO_QUUID_STRING) QUuid uuid = QUuid::createUuid(); String canonicalUuidStr = uuid.toString().mid(1, 36).toLower(); // remove opening and closing bracket and make it lower. ASSERT(canonicalUuidStr[uuidVersionIdentifierIndex] == uuidVersionRequired); diff --git a/WebCore/platform/Widget.h b/WebCore/platform/Widget.h index 85612ed..8d29aaa 100644 --- a/WebCore/platform/Widget.h +++ b/WebCore/platform/Widget.h @@ -65,7 +65,6 @@ typedef HWND PlatformWidget; #endif #if PLATFORM(GTK) -typedef struct _GdkDrawable GdkDrawable; typedef struct _GtkWidget GtkWidget; typedef struct _GtkContainer GtkContainer; typedef GtkWidget* PlatformWidget; @@ -116,6 +115,8 @@ class PlatformMouseEvent; class ScrollView; class WidgetPrivate; +enum WidgetNotification { WillPaintFlattened, DidPaintFlattened }; + // The Widget class serves as a base class for three kinds of objects: // (1) Scrollable areas (ScrollView) // (2) Scrollbars (Scrollbar) @@ -194,6 +195,8 @@ public: virtual void handleEvent(Event*) { } + virtual void notifyWidget(WidgetNotification) { } + // It is important for cross-platform code to realize that Mac has flipped coordinates. Therefore any code // that tries to convert the location of a rect using the point-based convertFromContainingWindow will end // up with an inaccurate rect. Always make sure to use the rect-based convertFromContainingWindow method diff --git a/WebCore/platform/android/TemporaryLinkStubs.cpp b/WebCore/platform/android/TemporaryLinkStubs.cpp index bcb5bfc..98e8812 100644 --- a/WebCore/platform/android/TemporaryLinkStubs.cpp +++ b/WebCore/platform/android/TemporaryLinkStubs.cpp @@ -74,7 +74,6 @@ #include "ScrollbarTheme.h" #include "SmartReplace.h" #include "Widget.h" -#include "loader.h" #include <stdio.h> #include <stdlib.h> #include <wtf/text/CString.h> @@ -166,7 +165,7 @@ Pasteboard::~Pasteboard() } -ContextMenu::ContextMenu(const HitTestResult& result) : m_hitTestResult(result) +ContextMenu::ContextMenu() { ASSERT_NOT_REACHED(); notImplemented(); diff --git a/WebCore/platform/audio/AudioResampler.cpp b/WebCore/platform/audio/AudioResampler.cpp index 7f8221e..ba5b58e 100644 --- a/WebCore/platform/audio/AudioResampler.cpp +++ b/WebCore/platform/audio/AudioResampler.cpp @@ -30,7 +30,7 @@ #include "AudioBus.h" #include <algorithm> -#include <math.h> +#include <wtf/MathExtras.h> using namespace std; diff --git a/WebCore/platform/audio/AudioUtilities.cpp b/WebCore/platform/audio/AudioUtilities.cpp index 32f4335..7a4b32e 100644 --- a/WebCore/platform/audio/AudioUtilities.cpp +++ b/WebCore/platform/audio/AudioUtilities.cpp @@ -24,9 +24,10 @@ #include "config.h" -#include "AudioUtilities.h" +#if ENABLE(WEB_AUDIO) -#include <math.h> +#include "AudioUtilities.h" +#include <wtf/MathExtras.h> namespace WebCore { @@ -50,9 +51,13 @@ double linearToDecibels(double linear) double discreteTimeConstantForSampleRate(double timeConstant, double sampleRate) { - return 1.0 - pow(1.0 / M_E, 1.0 / (sampleRate * timeConstant)); + // hardcoded value is temporary build fix for Windows. + // FIXME: replace hardcode 2.718282 with M_E until the correct MathExtras.h solution is determined. + return 1.0 - pow(1.0 / 2.718282, 1.0 / (sampleRate * timeConstant)); } } // AudioUtilites } // WebCore + +#endif // ENABLE(WEB_AUDIO) diff --git a/WebCore/platform/audio/Biquad.cpp b/WebCore/platform/audio/Biquad.cpp index 49f010b..20143e3 100644 --- a/WebCore/platform/audio/Biquad.cpp +++ b/WebCore/platform/audio/Biquad.cpp @@ -33,9 +33,8 @@ #include "Biquad.h" #include <algorithm> -#include <float.h> -#include <math.h> #include <stdio.h> +#include <wtf/MathExtras.h> #if OS(DARWIN) #include <Accelerate/Accelerate.h> @@ -197,7 +196,7 @@ void Biquad::setLowpassParams(double cutoff, double resonance) double d = sqrt((4.0 - sqrt(16.0 - 16.0 / (g * g))) / 2.0); // Compute biquad coefficients for lopass filter - double theta = M_PI * cutoff; + double theta = piDouble * cutoff; double sn = 0.5 * d * sin(theta); double beta = 0.5 * (1.0 - sn) / (1.0 + sn); double gamma = (0.5 + beta) * cos(theta); @@ -218,7 +217,7 @@ void Biquad::setHighpassParams(double cutoff, double resonance) double d = sqrt((4.0 - sqrt(16.0 - 16.0 / (g * g))) / 2.0); // Compute biquad coefficients for highpass filter - double theta = M_PI * cutoff; + double theta = piDouble * cutoff; double sn = 0.5 * d * sin(theta); double beta = 0.5 * (1.0 - sn) / (1.0 + sn); double gamma = (0.5 + beta) * cos(theta); @@ -233,7 +232,7 @@ void Biquad::setHighpassParams(double cutoff, double resonance) void Biquad::setLowShelfParams(double cutoff, double dbGain) { - double theta = M_PI * cutoff; + double theta = piDouble * cutoff; double A = pow(10.0, dbGain / 40.0); double S = 1.0; // filter slope (1.0 is max value) diff --git a/WebCore/platform/audio/Cone.cpp b/WebCore/platform/audio/Cone.cpp index 91813ab..f514cde 100644 --- a/WebCore/platform/audio/Cone.cpp +++ b/WebCore/platform/audio/Cone.cpp @@ -31,6 +31,7 @@ #if ENABLE(WEB_AUDIO) #include "Cone.h" +#include <wtf/MathExtras.h> namespace WebCore { @@ -41,21 +42,21 @@ ConeEffect::ConeEffect() { } -double ConeEffect::gain(Vector3 sourcePosition, Vector3 sourceOrientation, Vector3 listenerPosition) +double ConeEffect::gain(FloatPoint3D sourcePosition, FloatPoint3D sourceOrientation, FloatPoint3D listenerPosition) { if (sourceOrientation.isZero() || ((m_innerAngle == 360.0) && (m_outerAngle == 360.0))) return 1.0; // no cone specified - unity gain // Normalized source-listener vector - Vector3 sourceToListener = listenerPosition - sourcePosition; + FloatPoint3D sourceToListener = listenerPosition - sourcePosition; sourceToListener.normalize(); - Vector3 normalizedSourceOrientation = sourceOrientation; + FloatPoint3D normalizedSourceOrientation = sourceOrientation; normalizedSourceOrientation.normalize(); // Angle between the source orientation vector and the source-listener vector - double dotProduct = dot(sourceToListener, normalizedSourceOrientation); - double angle = 180.0 * acos(dotProduct) / M_PI; + double dotProduct = sourceToListener.dot(normalizedSourceOrientation); + double angle = 180.0 * acos(dotProduct) / piDouble; double absAngle = fabs(angle); // Divide by 2.0 here since API is entire angle (not half-angle) diff --git a/WebCore/platform/audio/Cone.h b/WebCore/platform/audio/Cone.h index 9936f28..f566018 100644 --- a/WebCore/platform/audio/Cone.h +++ b/WebCore/platform/audio/Cone.h @@ -29,7 +29,7 @@ #ifndef Cone_h #define Cone_h -#include <wtf/Vector3.h> +#include "FloatPoint3D.h" namespace WebCore { @@ -40,7 +40,7 @@ public: ConeEffect(); // Returns scalar gain for the given source/listener positions/orientations - double gain(Vector3 sourcePosition, Vector3 sourceOrientation, Vector3 listenerPosition); + double gain(FloatPoint3D sourcePosition, FloatPoint3D sourceOrientation, FloatPoint3D listenerPosition); // Angles in degrees void setInnerAngle(double innerAngle) { m_innerAngle = innerAngle; } diff --git a/WebCore/platform/audio/EqualPowerPanner.cpp b/WebCore/platform/audio/EqualPowerPanner.cpp index 2e4e10f..002b7c6 100644 --- a/WebCore/platform/audio/EqualPowerPanner.cpp +++ b/WebCore/platform/audio/EqualPowerPanner.cpp @@ -30,7 +30,7 @@ #include "AudioBus.h" #include "AudioUtilities.h" -#include <math.h> +#include <wtf/MathExtras.h> // Use a 50ms smoothing / de-zippering time-constant. const double SmoothingTimeConstant = 0.050; @@ -76,7 +76,7 @@ void EqualPowerPanner::pan(double azimuth, double /*elevation*/, AudioBus* input else desiredPanPosition = (azimuth + 30.0) / 60.0; - double desiredGainL = 0.5 * cos(M_PI * desiredPanPosition) + 0.5; + double desiredGainL = 0.5 * cos(piDouble * desiredPanPosition) + 0.5; double desiredGainR = sqrt(1.0 - desiredGainL*desiredGainL); // Don't de-zipper on first render call. diff --git a/WebCore/platform/audio/FFTFrame.cpp b/WebCore/platform/audio/FFTFrame.cpp index 17292b6..d9979d9 100644 --- a/WebCore/platform/audio/FFTFrame.cpp +++ b/WebCore/platform/audio/FFTFrame.cpp @@ -134,32 +134,32 @@ void FFTFrame::interpolateFrequencyComponents(const FFTFrame& frame1, const FFTF lastPhase2 = phase2; // Unwrap phase deltas - if (deltaPhase1 > M_PI) - deltaPhase1 -= 2.0 * M_PI; - if (deltaPhase1 < -M_PI) - deltaPhase1 += 2.0 * M_PI; - if (deltaPhase2 > M_PI) - deltaPhase2 -= 2.0 * M_PI; - if (deltaPhase2 < -M_PI) - deltaPhase2 += 2.0 * M_PI; + if (deltaPhase1 > piDouble) + deltaPhase1 -= 2.0 * piDouble; + if (deltaPhase1 < -piDouble) + deltaPhase1 += 2.0 * piDouble; + if (deltaPhase2 > piDouble) + deltaPhase2 -= 2.0 * piDouble; + if (deltaPhase2 < -piDouble) + deltaPhase2 += 2.0 * piDouble; // Blend group-delays double deltaPhaseBlend; - if (deltaPhase1 - deltaPhase2 > M_PI) - deltaPhaseBlend = s1 * deltaPhase1 + s2 * (2.0 * M_PI + deltaPhase2); - else if (deltaPhase2 - deltaPhase1 > M_PI) - deltaPhaseBlend = s1 * (2.0 * M_PI + deltaPhase1) + s2 * deltaPhase2; + if (deltaPhase1 - deltaPhase2 > piDouble) + deltaPhaseBlend = s1 * deltaPhase1 + s2 * (2.0 * piDouble + deltaPhase2); + else if (deltaPhase2 - deltaPhase1 > piDouble) + deltaPhaseBlend = s1 * (2.0 * piDouble + deltaPhase1) + s2 * deltaPhase2; else deltaPhaseBlend = s1 * deltaPhase1 + s2 * deltaPhase2; phaseAccum += deltaPhaseBlend; // Unwrap - if (phaseAccum > M_PI) - phaseAccum -= 2.0 * M_PI; - if (phaseAccum < -M_PI) - phaseAccum += 2.0 * M_PI; + if (phaseAccum > piDouble) + phaseAccum -= 2.0 * piDouble; + if (phaseAccum < -piDouble) + phaseAccum += 2.0 * piDouble; Complex c = complexFromMagnitudePhase(mag, phaseAccum); @@ -179,7 +179,7 @@ double FFTFrame::extractAverageGroupDelay() int halfSize = fftSize() / 2; - const double kSamplePhaseDelay = (2.0 * M_PI) / double(fftSize()); + const double kSamplePhaseDelay = (2.0 * piDouble) / double(fftSize()); // Calculate weighted average group delay for (int i = 0; i < halfSize; i++) { @@ -191,10 +191,10 @@ double FFTFrame::extractAverageGroupDelay() lastPhase = phase; // Unwrap - if (deltaPhase < -M_PI) - deltaPhase += 2.0 * M_PI; - if (deltaPhase > M_PI) - deltaPhase -= 2.0 * M_PI; + if (deltaPhase < -piDouble) + deltaPhase += 2.0 * piDouble; + if (deltaPhase > piDouble) + deltaPhase -= 2.0 * piDouble; aveSum += mag * deltaPhase; weightSum += mag; @@ -224,7 +224,7 @@ void FFTFrame::addConstantGroupDelay(double sampleFrameDelay) float* realP = realData(); float* imagP = imagData(); - const double kSamplePhaseDelay = (2.0 * M_PI) / double(fftSize()); + const double kSamplePhaseDelay = (2.0 * piDouble) / double(fftSize()); double phaseAdj = -sampleFrameDelay * kSamplePhaseDelay; diff --git a/WebCore/platform/audio/FFTFrame.h b/WebCore/platform/audio/FFTFrame.h index 6147fc1..1a82ef0 100644 --- a/WebCore/platform/audio/FFTFrame.h +++ b/WebCore/platform/audio/FFTFrame.h @@ -35,6 +35,10 @@ #include <Accelerate/Accelerate.h> #endif +#if !OS(DARWIN) && USE(WEBAUDIO_MKL) +#include "mkl_dfti.h" +#endif + #include <wtf/PassOwnPtr.h> #include <wtf/Platform.h> @@ -95,6 +99,23 @@ private: AudioFloatArray m_realData; AudioFloatArray m_imagData; #endif // OS(DARWIN) +#if !OS(DARWIN) && USE(WEBAUDIO_MKL) + // Interleaves the planar real and imaginary data and returns a + // pointer to the resulting storage which can be used for in-place + // or out-of-place operations. FIXME: ideally all of the MKL + // routines would operate on planar data and this method would be + // removed. + float* getUpToDateComplexData(); + + static DFTI_DESCRIPTOR_HANDLE descriptorHandleForSize(unsigned fftSize); + + static DFTI_DESCRIPTOR_HANDLE* descriptorHandles; + + DFTI_DESCRIPTOR_HANDLE m_handle; + AudioFloatArray m_complexData; + AudioFloatArray m_realData; + AudioFloatArray m_imagData; +#endif // !OS(DARWIN) && USE(WEBAUDIO_MKL) }; } // namespace WebCore diff --git a/WebCore/platform/audio/HRTFElevation.cpp b/WebCore/platform/audio/HRTFElevation.cpp index ab722cd..06d03ea 100644 --- a/WebCore/platform/audio/HRTFElevation.cpp +++ b/WebCore/platform/audio/HRTFElevation.cpp @@ -34,7 +34,6 @@ #include "AudioBus.h" #include "AudioFileReader.h" -#include "AudioResources.h" #include "Biquad.h" #include "FFTFrame.h" #include "HRTFPanner.h" @@ -108,9 +107,10 @@ bool HRTFElevation::calculateKernelsForAzimuthElevation(int azimuth, int elevati return false; size_t responseLength = impulseResponse->length(); + size_t expectedLength = static_cast<size_t>(256 * (sampleRate / 44100.0)); // Check number of channels and length. For now these are fixed and known. - bool isBusGood = responseLength == 512 && impulseResponse->numberOfChannels() == 2; + bool isBusGood = responseLength == expectedLength && impulseResponse->numberOfChannels() == 2; ASSERT(isBusGood); if (!isBusGood) return false; diff --git a/WebCore/platform/audio/HRTFKernel.cpp b/WebCore/platform/audio/HRTFKernel.cpp index 852cdbf..22d4b12 100644 --- a/WebCore/platform/audio/HRTFKernel.cpp +++ b/WebCore/platform/audio/HRTFKernel.cpp @@ -35,6 +35,7 @@ #include "AudioChannel.h" #include "Biquad.h" #include "FFTFrame.h" +#include <wtf/MathExtras.h> using namespace std; diff --git a/WebCore/platform/audio/HRTFPanner.cpp b/WebCore/platform/audio/HRTFPanner.cpp index 56f06f1..68bc505 100644 --- a/WebCore/platform/audio/HRTFPanner.cpp +++ b/WebCore/platform/audio/HRTFPanner.cpp @@ -33,7 +33,7 @@ #include "HRTFDatabase.h" #include "HRTFDatabaseLoader.h" #include <algorithm> -#include <math.h> +#include <wtf/MathExtras.h> #include <wtf/RefPtr.h> using namespace std; diff --git a/WebCore/platform/audio/chromium/AudioBusChromium.cpp b/WebCore/platform/audio/chromium/AudioBusChromium.cpp new file mode 100644 index 0000000..a93703d --- /dev/null +++ b/WebCore/platform/audio/chromium/AudioBusChromium.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2010, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 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" + +#if ENABLE(WEB_AUDIO) + +#include "AudioBus.h" + +#include "AudioFileReader.h" +#include "ChromiumBridge.h" +#include <wtf/PassOwnPtr.h> + +namespace WebCore { + +// We will use this version of loadPlatformResource() once the resources are checked into Chromium. + +// PassOwnPtr<AudioBus> AudioBus::loadPlatformResource(const char* name, double sampleRate) +// { +// return ChromiumBridge::loadPlatformAudioResource(name, sampleRate); +// } + +PassOwnPtr<AudioBus> createBusFromInMemoryAudioFile(const void* data, size_t dataSize, bool mixToMono, double sampleRate) +{ + OwnPtr<AudioBus> audioBus = ChromiumBridge::decodeAudioFileData(static_cast<const char*>(data), dataSize, sampleRate); + if (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(); + } + + return audioBus.release(); +} + +} // namespace WebCore + +#endif // ENABLE(WEB_AUDIO) diff --git a/WebCore/platform/audio/mac/AudioBusMac.mm b/WebCore/platform/audio/mac/AudioBusMac.mm index 3f3185a..3d454a9 100644 --- a/WebCore/platform/audio/mac/AudioBusMac.mm +++ b/WebCore/platform/audio/mac/AudioBusMac.mm @@ -47,7 +47,7 @@ PassOwnPtr<AudioBus> AudioBus::loadPlatformResource(const char* name, double sam NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSBundle *bundle = [NSBundle bundleForClass:[WebCoreAudioBundleClass class]]; - NSString *audioFilePath = [bundle pathForResource:[NSString stringWithUTF8String:name] ofType:@"aif" inDirectory:@"audio"]; + NSString *audioFilePath = [bundle pathForResource:[NSString stringWithUTF8String:name] ofType:@"wav" inDirectory:@"audio"]; NSData *audioData = [NSData dataWithContentsOfFile:audioFilePath]; if (audioData) { diff --git a/WebCore/platform/audio/mkl/FFTFrameMKL.cpp b/WebCore/platform/audio/mkl/FFTFrameMKL.cpp new file mode 100644 index 0000000..f66a485 --- /dev/null +++ b/WebCore/platform/audio/mkl/FFTFrameMKL.cpp @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 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. + */ + +// FFTFrame implementation using Intel's Math Kernel Library (MKL), +// suitable for use on Windows and Linux. + +#include "config.h" + +#if ENABLE(WEB_AUDIO) + +#include "FFTFrame.h" + +#include "mkl_vml.h" +#include <wtf/MathExtras.h> + +namespace { + +DFTI_DESCRIPTOR_HANDLE createDescriptorHandle(int fftSize) +{ + DFTI_DESCRIPTOR_HANDLE handle = 0; + + // Create DFTI descriptor for 1D single precision transform. + MKL_LONG status = DftiCreateDescriptor(&handle, DFTI_SINGLE, DFTI_REAL, 1, fftSize); + ASSERT(DftiErrorClass(status, DFTI_NO_ERROR)); + + // Set placement of result to DFTI_NOT_INPLACE. + status = DftiSetValue(handle, DFTI_PLACEMENT, DFTI_NOT_INPLACE); + ASSERT(DftiErrorClass(status, DFTI_NO_ERROR)); + + // Set packing format to PERM; this produces the layout which + // matches Accelerate.framework's on the Mac, though interleaved. + status = DftiSetValue(handle, DFTI_PACKED_FORMAT, DFTI_PERM_FORMAT); + ASSERT(DftiErrorClass(status, DFTI_NO_ERROR)); + + // Set the forward scale factor to 2 to match Accelerate.framework's. + // FIXME: FFTFrameMac's scaling factor could be fixed to be 1.0, + // in which case this code would need to be changed as well. + status = DftiSetValue(handle, DFTI_FORWARD_SCALE, 2.0); + ASSERT(DftiErrorClass(status, DFTI_NO_ERROR)); + + // Set the backward scale factor to 1 / 2n to match Accelerate.framework's. + // FIXME: if the above scaling factor is fixed then this needs to be as well. + double scale = 1.0 / (2.0 * fftSize); + status = DftiSetValue(handle, DFTI_BACKWARD_SCALE, scale); + ASSERT(DftiErrorClass(status, DFTI_NO_ERROR)); + + // Use the default DFTI_CONJUGATE_EVEN_STORAGE = DFTI_COMPLEX_REAL. + + // Commit DFTI descriptor. + status = DftiCommitDescriptor(handle); + ASSERT(DftiErrorClass(status, DFTI_NO_ERROR)); + + return handle; +} + +} // anonymous namespace + +namespace WebCore { + +const int kMaxFFTPow2Size = 24; + +DFTI_DESCRIPTOR_HANDLE* FFTFrame::descriptorHandles = 0; + +// Normal constructor: allocates for a given fftSize. +FFTFrame::FFTFrame(unsigned fftSize) + : m_FFTSize(fftSize) + , m_log2FFTSize(static_cast<unsigned>(log2(fftSize))) + , m_handle(0) + , m_complexData(fftSize) + , m_realData(fftSize / 2) + , m_imagData(fftSize / 2) +{ + // We only allow power of two. + ASSERT(1UL << m_log2FFTSize == m_FFTSize); + + m_handle = descriptorHandleForSize(fftSize); +} + +// Creates a blank/empty frame (interpolate() must later be called). +FFTFrame::FFTFrame() + : m_FFTSize(0) + , m_log2FFTSize(0) + , m_handle(0) +{ +} + +// Copy constructor. +FFTFrame::FFTFrame(const FFTFrame& frame) + : m_FFTSize(frame.m_FFTSize) + , m_log2FFTSize(frame.m_log2FFTSize) + , m_handle(0) + , m_complexData(frame.m_FFTSize) + , m_realData(frame.m_FFTSize / 2) + , m_imagData(frame.m_FFTSize / 2) +{ + m_handle = descriptorHandleForSize(m_FFTSize); + + // Copy/setup frame data. + unsigned nbytes = sizeof(float) * (m_FFTSize / 2); + memcpy(realData(), frame.realData(), nbytes); + memcpy(imagData(), frame.imagData(), nbytes); +} + +FFTFrame::~FFTFrame() +{ +} + +void FFTFrame::multiply(const FFTFrame& frame) +{ + FFTFrame& frame1 = *this; + FFTFrame& frame2 = const_cast<FFTFrame&>(frame); + + float* realP1 = frame1.realData(); + float* imagP1 = frame1.imagData(); + const float* realP2 = frame2.realData(); + const float* imagP2 = frame2.imagData(); + + // Scale accounts for vecLib's peculiar scaling. + // This ensures the right scaling all the way back to inverse FFT. + // FIXME: this scaling factor will be 1.0f if the above 2.0 -> 1.0 + // scaling factor is fixed. + float scale = 0.5f; + + // Multiply packed DC/nyquist component. + realP1[0] *= scale * realP2[0]; + imagP1[0] *= scale * imagP2[0]; + + // Multiply the rest, skipping packed DC/Nyquist components. + float* interleavedData1 = frame1.getUpToDateComplexData(); + float* interleavedData2 = frame2.getUpToDateComplexData(); + + unsigned halfSize = m_FFTSize / 2; + + // Complex multiply. + vcMul(halfSize - 1, + reinterpret_cast<MKL_Complex8*>(interleavedData1) + 1, + reinterpret_cast<MKL_Complex8*>(interleavedData2) + 1, + reinterpret_cast<MKL_Complex8*>(interleavedData1) + 1); + + // De-interleave and scale the rest of the data. + // FIXME: find an MKL routine to do at least the scaling more efficiently. + for (unsigned i = 1; i < halfSize; ++i) { + int baseComplexIndex = 2 * i; + realP1[i] = scale * interleavedData1[baseComplexIndex]; + imagP1[i] = scale * interleavedData1[baseComplexIndex + 1]; + } +} + +void FFTFrame::doFFT(float* data) +{ + // Compute Forward transform. + MKL_LONG status = DftiComputeForward(m_handle, data, m_complexData.data()); + ASSERT(DftiErrorClass(status, DFTI_NO_ERROR)); + + // De-interleave to separate real and complex arrays. FIXME: + // figure out if it's possible to get MKL to use split-complex + // form for 1D real-to-complex out-of-place FFTs. + int len = m_FFTSize / 2; + for (int i = 0; i < len; ++i) { + int baseComplexIndex = 2 * i; + // m_realData[0] is the DC component and m_imagData[0] the + // Nyquist component since the interleaved complex data is + // packed. + m_realData[i] = m_complexData[baseComplexIndex]; + m_imagData[i] = m_complexData[baseComplexIndex + 1]; + } +} + +void FFTFrame::doInverseFFT(float* data) +{ + // Prepare interleaved data. FIXME: figure out if it's possible to + // get MKL to use split-complex form for 1D backward + // (complex-to-real) out-of-place FFTs. + float* interleavedData = getUpToDateComplexData(); + + // Compute backward transform. + MKL_LONG status = DftiComputeBackward(m_handle, interleavedData, data); + ASSERT(DftiErrorClass(status, DFTI_NO_ERROR)); +} + +void FFTFrame::cleanup() +{ + if (!descriptorHandles) + return; + + for (int i = 0; i < kMaxFFTPow2Size; ++i) { + if (descriptorHandles[i]) { + MKL_LONG status = DftiFreeDescriptor(&descriptorHandles[i]); + ASSERT(DftiErrorClass(status, DFTI_NO_ERROR)); + } + } + + delete[] descriptorHandles; + descriptorHandles = 0; +} + +float* FFTFrame::realData() const +{ + return const_cast<float*>(m_realData.data()); +} + +float* FFTFrame::imagData() const +{ + return const_cast<float*>(m_imagData.data()); +} + +float* FFTFrame::getUpToDateComplexData() +{ + // FIXME: if we can't completely get rid of this method, SSE + // optimization could be considered if it shows up hot on profiles. + int len = m_FFTSize / 2; + for (int i = 0; i < len; ++i) { + int baseComplexIndex = 2 * i; + m_complexData[baseComplexIndex] = m_realData[i]; + m_complexData[baseComplexIndex + 1] = m_imagData[i]; + } + return const_cast<float*>(m_complexData.data()); +} + +DFTI_DESCRIPTOR_HANDLE FFTFrame::descriptorHandleForSize(unsigned fftSize) +{ + if (!descriptorHandles) { + descriptorHandles = new DFTI_DESCRIPTOR_HANDLE[kMaxFFTPow2Size]; + for (int i = 0; i < kMaxFFTPow2Size; ++i) + descriptorHandles[i] = 0; + } + + ASSERT(fftSize); + int pow2size = static_cast<int>(log2(fftSize)); + ASSERT(pow2size < kMaxFFTPow2Size); + if (!descriptorHandles[pow2size]) + descriptorHandles[pow2size] = createDescriptorHandle(fftSize); + return descriptorHandles[pow2size]; +} + +} // namespace WebCore + +#endif // ENABLE(WEB_AUDIO) diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P000.wav Binary files differnew file mode 100644 index 0000000..57f2ef3 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P015.wav Binary files differnew file mode 100644 index 0000000..3ecea33 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P030.wav Binary files differnew file mode 100644 index 0000000..7320802 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P045.wav Binary files differnew file mode 100644 index 0000000..1a10d9a --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P060.wav Binary files differnew file mode 100644 index 0000000..9b12c22 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P075.wav Binary files differnew file mode 100644 index 0000000..3153bb8 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P090.wav Binary files differnew file mode 100644 index 0000000..3282da9 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P315.wav Binary files differnew file mode 100644 index 0000000..b999852 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P330.wav Binary files differnew file mode 100644 index 0000000..53a03b6 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P345.wav Binary files differnew file mode 100644 index 0000000..16d5766 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P345.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P000.wav Binary files differnew file mode 100644 index 0000000..3788e16 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P015.wav Binary files differnew file mode 100644 index 0000000..ad2efb6 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P030.wav Binary files differnew file mode 100644 index 0000000..ee86702 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P045.wav Binary files differnew file mode 100644 index 0000000..98ff82e --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P060.wav Binary files differnew file mode 100644 index 0000000..98ff82e --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P075.wav Binary files differnew file mode 100644 index 0000000..98ff82e --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P090.wav Binary files differnew file mode 100644 index 0000000..98ff82e --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P315.wav Binary files differnew file mode 100644 index 0000000..10bdf78 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P330.wav Binary files differnew file mode 100644 index 0000000..c8398a4 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P345.wav Binary files differnew file mode 100644 index 0000000..82b92a8 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P345.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P000.wav Binary files differnew file mode 100644 index 0000000..8b8714c --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P015.wav Binary files differnew file mode 100644 index 0000000..882efd4 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P030.wav Binary files differnew file mode 100644 index 0000000..abd99e6 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P045.wav Binary files differnew file mode 100644 index 0000000..28765be --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P060.wav Binary files differnew file mode 100644 index 0000000..42c1445 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P075.wav Binary files differnew file mode 100644 index 0000000..42c1445 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P090.wav Binary files differnew file mode 100644 index 0000000..42c1445 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P315.wav Binary files differnew file mode 100644 index 0000000..99b00f7 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P330.wav Binary files differnew file mode 100644 index 0000000..f81bee2 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P345.wav Binary files differnew file mode 100644 index 0000000..139d0cb --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P345.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P000.wav Binary files differnew file mode 100644 index 0000000..68b7b4f --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P015.wav Binary files differnew file mode 100644 index 0000000..d6773ae --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P030.wav Binary files differnew file mode 100644 index 0000000..9e786bb --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P045.wav Binary files differnew file mode 100644 index 0000000..fbef2f3 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P060.wav Binary files differnew file mode 100644 index 0000000..fbef2f3 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P075.wav Binary files differnew file mode 100644 index 0000000..fbef2f3 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P090.wav Binary files differnew file mode 100644 index 0000000..fbef2f3 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P315.wav Binary files differnew file mode 100644 index 0000000..3c53b76 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P330.wav Binary files differnew file mode 100644 index 0000000..e4524c0 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P345.wav Binary files differnew file mode 100644 index 0000000..ff12535 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P345.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P000.wav Binary files differnew file mode 100644 index 0000000..5bb1b17 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P015.wav Binary files differnew file mode 100644 index 0000000..47e0209 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P030.wav Binary files differnew file mode 100644 index 0000000..536b4ac --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P045.wav Binary files differnew file mode 100644 index 0000000..05152ad --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P060.wav Binary files differnew file mode 100644 index 0000000..221637b --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P075.wav Binary files differnew file mode 100644 index 0000000..7d6d07f --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P090.wav Binary files differnew file mode 100644 index 0000000..7d6d07f --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P315.wav Binary files differnew file mode 100644 index 0000000..a4eca78 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P330.wav Binary files differnew file mode 100644 index 0000000..37393c2 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P345.wav Binary files differnew file mode 100644 index 0000000..3d56e26 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P345.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P000.wav Binary files differnew file mode 100644 index 0000000..2159f3d --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P015.wav Binary files differnew file mode 100644 index 0000000..8b689f6 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P030.wav Binary files differnew file mode 100644 index 0000000..9ee8ac5 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P045.wav Binary files differnew file mode 100644 index 0000000..88124e9 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P060.wav Binary files differnew file mode 100644 index 0000000..88124e9 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P075.wav Binary files differnew file mode 100644 index 0000000..88124e9 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P090.wav Binary files differnew file mode 100644 index 0000000..88124e9 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P315.wav Binary files differnew file mode 100644 index 0000000..59441a6 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P330.wav Binary files differnew file mode 100644 index 0000000..7cac0f5 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P345.wav Binary files differnew file mode 100644 index 0000000..dc28d64 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P345.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P000.wav Binary files differnew file mode 100644 index 0000000..ae7e583 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P015.wav Binary files differnew file mode 100644 index 0000000..509449e --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P030.wav Binary files differnew file mode 100644 index 0000000..e23b20c --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P045.wav Binary files differnew file mode 100644 index 0000000..cf247b9 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P060.wav Binary files differnew file mode 100644 index 0000000..f49d520 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P075.wav Binary files differnew file mode 100644 index 0000000..f49d520 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P090.wav Binary files differnew file mode 100644 index 0000000..f49d520 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P315.wav Binary files differnew file mode 100644 index 0000000..e5472f1 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P330.wav Binary files differnew file mode 100644 index 0000000..8e1af83 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P345.wav Binary files differnew file mode 100644 index 0000000..c477193 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P345.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P000.wav Binary files differnew file mode 100644 index 0000000..4236e08 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P015.wav Binary files differnew file mode 100644 index 0000000..2461fb0 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P030.wav Binary files differnew file mode 100644 index 0000000..11d549b --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P045.wav Binary files differnew file mode 100644 index 0000000..0aa100e --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P060.wav Binary files differnew file mode 100644 index 0000000..0aa100e --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P075.wav Binary files differnew file mode 100644 index 0000000..0aa100e --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P090.wav Binary files differnew file mode 100644 index 0000000..0aa100e --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P315.wav Binary files differnew file mode 100644 index 0000000..572e602 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P330.wav Binary files differnew file mode 100644 index 0000000..7f41da3 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P345.wav Binary files differnew file mode 100644 index 0000000..d0101b8 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P345.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P000.wav Binary files differnew file mode 100644 index 0000000..800fbd7 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P015.wav Binary files differnew file mode 100644 index 0000000..9b35e72 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P030.wav Binary files differnew file mode 100644 index 0000000..bb58c4e --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P045.wav Binary files differnew file mode 100644 index 0000000..8963e3e --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P060.wav Binary files differnew file mode 100644 index 0000000..22241ee --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P075.wav Binary files differnew file mode 100644 index 0000000..9e4fee0 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P090.wav Binary files differnew file mode 100644 index 0000000..9e4fee0 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P315.wav Binary files differnew file mode 100644 index 0000000..95976c6 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P330.wav Binary files differnew file mode 100644 index 0000000..8fc55f1 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P345.wav Binary files differnew file mode 100644 index 0000000..eeeb702 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P345.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P000.wav Binary files differnew file mode 100644 index 0000000..1847d8d --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P015.wav Binary files differnew file mode 100644 index 0000000..52e812c --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P030.wav Binary files differnew file mode 100644 index 0000000..32ca344 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P045.wav Binary files differnew file mode 100644 index 0000000..3de60c8 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P060.wav Binary files differnew file mode 100644 index 0000000..3de60c8 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P075.wav Binary files differnew file mode 100644 index 0000000..3de60c8 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P090.wav Binary files differnew file mode 100644 index 0000000..3de60c8 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P315.wav Binary files differnew file mode 100644 index 0000000..2668e41 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P330.wav Binary files differnew file mode 100644 index 0000000..e69670b --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P345.wav Binary files differnew file mode 100644 index 0000000..1cc48ee --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P345.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P000.wav Binary files differnew file mode 100644 index 0000000..252968b --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P015.wav Binary files differnew file mode 100644 index 0000000..50aff3c --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P030.wav Binary files differnew file mode 100644 index 0000000..3abd6e8 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P045.wav Binary files differnew file mode 100644 index 0000000..3f0d5ef --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P060.wav Binary files differnew file mode 100644 index 0000000..616f760 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P075.wav Binary files differnew file mode 100644 index 0000000..616f760 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P090.wav Binary files differnew file mode 100644 index 0000000..616f760 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P315.wav Binary files differnew file mode 100644 index 0000000..bfb6032 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P330.wav Binary files differnew file mode 100644 index 0000000..1983cdb --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P345.wav Binary files differnew file mode 100644 index 0000000..27c0762 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P345.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P000.wav Binary files differnew file mode 100644 index 0000000..b04391b --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P015.wav Binary files differnew file mode 100644 index 0000000..5955612 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P030.wav Binary files differnew file mode 100644 index 0000000..af5d83a --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P045.wav Binary files differnew file mode 100644 index 0000000..a592f71 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P060.wav Binary files differnew file mode 100644 index 0000000..a592f71 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P075.wav Binary files differnew file mode 100644 index 0000000..a592f71 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P090.wav Binary files differnew file mode 100644 index 0000000..a592f71 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P315.wav Binary files differnew file mode 100644 index 0000000..a985aa1 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P330.wav Binary files differnew file mode 100644 index 0000000..a8b83d1 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P345.wav Binary files differnew file mode 100644 index 0000000..7e649a3 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P345.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P000.wav Binary files differnew file mode 100644 index 0000000..b74985c --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P015.wav Binary files differnew file mode 100644 index 0000000..e112ee0 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P030.wav Binary files differnew file mode 100644 index 0000000..ac842cc --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P045.wav Binary files differnew file mode 100644 index 0000000..95c3a6d --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P060.wav Binary files differnew file mode 100644 index 0000000..610eedb --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P075.wav Binary files differnew file mode 100644 index 0000000..d4a57bf --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P090.wav Binary files differnew file mode 100644 index 0000000..d4a57bf --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P315.wav Binary files differnew file mode 100644 index 0000000..bd6e4f8 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P330.wav Binary files differnew file mode 100644 index 0000000..7d4be6f --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P345.wav Binary files differnew file mode 100644 index 0000000..b7ef81a --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P345.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P000.wav Binary files differnew file mode 100644 index 0000000..0c4af2a --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P015.wav Binary files differnew file mode 100644 index 0000000..dd7a505 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P030.wav Binary files differnew file mode 100644 index 0000000..e169049 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P045.wav Binary files differnew file mode 100644 index 0000000..49008a0 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P060.wav Binary files differnew file mode 100644 index 0000000..49008a0 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P075.wav Binary files differnew file mode 100644 index 0000000..49008a0 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P090.wav Binary files differnew file mode 100644 index 0000000..49008a0 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P315.wav Binary files differnew file mode 100644 index 0000000..1e7d478 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P330.wav Binary files differnew file mode 100644 index 0000000..2a77d74 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P345.wav Binary files differnew file mode 100644 index 0000000..843b928 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P345.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P000.wav Binary files differnew file mode 100644 index 0000000..770af17 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P015.wav Binary files differnew file mode 100644 index 0000000..437a1c6 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P030.wav Binary files differnew file mode 100644 index 0000000..f0d9d8e --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P045.wav Binary files differnew file mode 100644 index 0000000..cd4ae55 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P060.wav Binary files differnew file mode 100644 index 0000000..7dd5a1a --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P075.wav Binary files differnew file mode 100644 index 0000000..7dd5a1a --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P090.wav Binary files differnew file mode 100644 index 0000000..7dd5a1a --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P315.wav Binary files differnew file mode 100644 index 0000000..bfac19d --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P330.wav Binary files differnew file mode 100644 index 0000000..8b3e086 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P345.wav Binary files differnew file mode 100644 index 0000000..8b4da46 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P345.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P000.wav Binary files differnew file mode 100644 index 0000000..b6d4703 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P015.wav Binary files differnew file mode 100644 index 0000000..0ff35e9 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P030.wav Binary files differnew file mode 100644 index 0000000..e934c78 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P045.wav Binary files differnew file mode 100644 index 0000000..c931e3c --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P060.wav Binary files differnew file mode 100644 index 0000000..c931e3c --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P075.wav Binary files differnew file mode 100644 index 0000000..c931e3c --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P090.wav Binary files differnew file mode 100644 index 0000000..c931e3c --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P315.wav Binary files differnew file mode 100644 index 0000000..f999966 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P330.wav Binary files differnew file mode 100644 index 0000000..d958590 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P345.wav Binary files differnew file mode 100644 index 0000000..ac06260 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P345.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P000.wav Binary files differnew file mode 100644 index 0000000..b720ed1 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P015.wav Binary files differnew file mode 100644 index 0000000..b48852a --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P030.wav Binary files differnew file mode 100644 index 0000000..92c7ef0 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P045.wav Binary files differnew file mode 100644 index 0000000..2d5ff65 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P060.wav Binary files differnew file mode 100644 index 0000000..07dcfde --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P075.wav Binary files differnew file mode 100644 index 0000000..283e250 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P090.wav Binary files differnew file mode 100644 index 0000000..283e250 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P315.wav Binary files differnew file mode 100644 index 0000000..b99ad7d --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P330.wav Binary files differnew file mode 100644 index 0000000..4886915 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P345.wav Binary files differnew file mode 100644 index 0000000..c932833 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P345.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P000.wav Binary files differnew file mode 100644 index 0000000..b204def --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P015.wav Binary files differnew file mode 100644 index 0000000..fa48113 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P030.wav Binary files differnew file mode 100644 index 0000000..2e2de70 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P045.wav Binary files differnew file mode 100644 index 0000000..685f102 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P060.wav Binary files differnew file mode 100644 index 0000000..685f102 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P075.wav Binary files differnew file mode 100644 index 0000000..685f102 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P090.wav Binary files differnew file mode 100644 index 0000000..685f102 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P315.wav Binary files differnew file mode 100644 index 0000000..c7cce6e --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P330.wav Binary files differnew file mode 100644 index 0000000..93a6b8a --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P345.wav Binary files differnew file mode 100644 index 0000000..efc72bc --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P345.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P000.wav Binary files differnew file mode 100644 index 0000000..8f49078 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P015.wav Binary files differnew file mode 100644 index 0000000..96510f7 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P030.wav Binary files differnew file mode 100644 index 0000000..60b84f4 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P045.wav Binary files differnew file mode 100644 index 0000000..ec995e6 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P060.wav Binary files differnew file mode 100644 index 0000000..e287d0e --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P075.wav Binary files differnew file mode 100644 index 0000000..e287d0e --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P090.wav Binary files differnew file mode 100644 index 0000000..e287d0e --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P315.wav Binary files differnew file mode 100644 index 0000000..01f0921 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P330.wav Binary files differnew file mode 100644 index 0000000..380e707 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P345.wav Binary files differnew file mode 100644 index 0000000..124a534 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P345.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P000.wav Binary files differnew file mode 100644 index 0000000..1a577f3 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P015.wav Binary files differnew file mode 100644 index 0000000..ce698bb --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P030.wav Binary files differnew file mode 100644 index 0000000..8d5134f --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P045.wav Binary files differnew file mode 100644 index 0000000..583c6ed --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P060.wav Binary files differnew file mode 100644 index 0000000..583c6ed --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P075.wav Binary files differnew file mode 100644 index 0000000..583c6ed --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P090.wav Binary files differnew file mode 100644 index 0000000..583c6ed --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P315.wav Binary files differnew file mode 100644 index 0000000..7b1b43b --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P330.wav Binary files differnew file mode 100644 index 0000000..e9ed7ed --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P345.wav Binary files differnew file mode 100644 index 0000000..6ce83ed --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P345.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P000.wav Binary files differnew file mode 100644 index 0000000..b4ea6bf --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P015.wav Binary files differnew file mode 100644 index 0000000..76d5b71 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P030.wav Binary files differnew file mode 100644 index 0000000..04ee003 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P045.wav Binary files differnew file mode 100644 index 0000000..22d7413 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P060.wav Binary files differnew file mode 100644 index 0000000..1b35018 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P075.wav Binary files differnew file mode 100644 index 0000000..2f55df8 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P090.wav Binary files differnew file mode 100644 index 0000000..2f55df8 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P315.wav Binary files differnew file mode 100644 index 0000000..7bcc8a4 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P330.wav Binary files differnew file mode 100644 index 0000000..a3bacf3 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P345.wav Binary files differnew file mode 100644 index 0000000..bdfba2d --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P345.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P000.wav Binary files differnew file mode 100644 index 0000000..719320c --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P015.wav Binary files differnew file mode 100644 index 0000000..5d366fc --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P030.wav Binary files differnew file mode 100644 index 0000000..e10e88b --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P045.wav Binary files differnew file mode 100644 index 0000000..ecb4b50 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P060.wav Binary files differnew file mode 100644 index 0000000..ecb4b50 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P075.wav Binary files differnew file mode 100644 index 0000000..ecb4b50 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P090.wav Binary files differnew file mode 100644 index 0000000..ecb4b50 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P315.wav Binary files differnew file mode 100644 index 0000000..35c44d4 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P330.wav Binary files differnew file mode 100644 index 0000000..8fe859b --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P345.wav Binary files differnew file mode 100644 index 0000000..3e44b83 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P345.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P000.wav Binary files differnew file mode 100644 index 0000000..e878220 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P015.wav Binary files differnew file mode 100644 index 0000000..7628cbc --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P030.wav Binary files differnew file mode 100644 index 0000000..7c4430c --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P045.wav Binary files differnew file mode 100644 index 0000000..55e3c5e --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P060.wav Binary files differnew file mode 100644 index 0000000..563313e --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P075.wav Binary files differnew file mode 100644 index 0000000..563313e --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P090.wav Binary files differnew file mode 100644 index 0000000..563313e --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P315.wav Binary files differnew file mode 100644 index 0000000..3eccc16 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P330.wav Binary files differnew file mode 100644 index 0000000..fd3f5e1 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P345.wav Binary files differnew file mode 100644 index 0000000..5937c59 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P345.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P000.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P000.wav Binary files differnew file mode 100644 index 0000000..99dc851 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P000.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P015.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P015.wav Binary files differnew file mode 100644 index 0000000..28994d5 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P015.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P030.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P030.wav Binary files differnew file mode 100644 index 0000000..beb24a2 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P030.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P045.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P045.wav Binary files differnew file mode 100644 index 0000000..f840c59 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P045.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P060.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P060.wav Binary files differnew file mode 100644 index 0000000..f840c59 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P060.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P075.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P075.wav Binary files differnew file mode 100644 index 0000000..f840c59 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P075.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P090.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P090.wav Binary files differnew file mode 100644 index 0000000..f840c59 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P090.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P315.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P315.wav Binary files differnew file mode 100644 index 0000000..68baa8e --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P315.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P330.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P330.wav Binary files differnew file mode 100644 index 0000000..6cb01b8 --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P330.wav diff --git a/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P345.wav b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P345.wav Binary files differnew file mode 100644 index 0000000..b2ae88c --- /dev/null +++ b/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P345.wav diff --git a/WebCore/platform/brew/ContextMenuBrew.cpp b/WebCore/platform/brew/ContextMenuBrew.cpp index 924e9dd..56ac351 100644 --- a/WebCore/platform/brew/ContextMenuBrew.cpp +++ b/WebCore/platform/brew/ContextMenuBrew.cpp @@ -32,15 +32,13 @@ namespace WebCore { -ContextMenu::ContextMenu(const HitTestResult& result) - : m_hitTestResult(result) +ContextMenu::ContextMenu() { ASSERT_NOT_REACHED(); notImplemented(); } -ContextMenu::ContextMenu(const HitTestResult& result, const PlatformMenuDescription menu) - : m_hitTestResult(result) +ContextMenu::ContextMenu(const PlatformMenuDescription menu) { ASSERT_NOT_REACHED(); notImplemented(); diff --git a/WebCore/platform/chromium/ContextMenuChromium.cpp b/WebCore/platform/chromium/ContextMenuChromium.cpp index 93c0ec4..9bddd28 100644 --- a/WebCore/platform/chromium/ContextMenuChromium.cpp +++ b/WebCore/platform/chromium/ContextMenuChromium.cpp @@ -36,13 +36,11 @@ namespace WebCore { // This is a stub implementation of WebKit's ContextMenu class that does // nothing. -ContextMenu::ContextMenu(const HitTestResult& result) - : m_hitTestResult(result) +ContextMenu::ContextMenu() { } -ContextMenu::ContextMenu(const HitTestResult& result, const PlatformMenuDescription menu) - : m_hitTestResult(result) +ContextMenu::ContextMenu(const PlatformMenuDescription menu) { } diff --git a/WebCore/platform/chromium/MIMETypeRegistryChromium.cpp b/WebCore/platform/chromium/MIMETypeRegistryChromium.cpp index 23f7926..9df8847 100644 --- a/WebCore/platform/chromium/MIMETypeRegistryChromium.cpp +++ b/WebCore/platform/chromium/MIMETypeRegistryChromium.cpp @@ -91,8 +91,7 @@ bool MIMETypeRegistry::isSupportedImageResourceMIMEType(const String& mimeType) bool MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(const String& mimeType) { - // FIXME: Fill this out. See: http://trac.webkit.org/changeset/30888 - return isSupportedImageMIMEType(mimeType); + return mimeType == "image/jpeg" || mimeType == "image/png"; } bool MIMETypeRegistry::isSupportedJavaScriptMIMEType(const String& mimeType) diff --git a/WebCore/platform/efl/ContextMenuEfl.cpp b/WebCore/platform/efl/ContextMenuEfl.cpp index 8d85608..a5c6524 100644 --- a/WebCore/platform/efl/ContextMenuEfl.cpp +++ b/WebCore/platform/efl/ContextMenuEfl.cpp @@ -22,60 +22,34 @@ #include "config.h" #include "ContextMenu.h" -#include "ContextMenuClient.h" -#include "ContextMenuClientEfl.h" -#include "ContextMenuController.h" #include "NotImplemented.h" namespace WebCore { -ContextMenu::ContextMenu(const HitTestResult& result) - : m_hitTestResult(result) +ContextMenu::ContextMenu(void* menu) { - m_contextMenuClient = static_cast<ContextMenuClientEfl*>(controller()->client()); - m_platformDescription = m_contextMenuClient->createPlatformDescription(this); + getContextMenuItems(menu, m_items); } -ContextMenu::ContextMenu(const HitTestResult& result, const PlatformMenuDescription menu) - : m_hitTestResult(result) - , m_platformDescription(menu) +ContextMenu::ContextMenu() { - m_contextMenuClient = static_cast<ContextMenuClientEfl*>(controller()->client()); + notImplemented(); } -ContextMenu::~ContextMenu() +void ContextMenu::getContextMenuItems(void* menu, Vector<ContextMenuItem>& items) { - if (m_platformDescription) - m_contextMenuClient->freePlatformDescription(m_platformDescription); + notImplemented(); } -void ContextMenu::appendItem(ContextMenuItem& item) +void* ContextMenu::createNativeMenuFromItems(const Vector<ContextMenuItem>& items) { - checkOrEnableIfNeeded(item); - m_contextMenuClient->appendItem(m_platformDescription, item); + notImplemented(); + return 0; } -void ContextMenu::setPlatformDescription(PlatformMenuDescription menu) +void* ContextMenu::nativeMenu() const { - ASSERT(!m_platformDescription); - - m_platformDescription = menu; - m_contextMenuClient->show(m_platformDescription); -} - -PlatformMenuDescription ContextMenu::platformDescription() const -{ - return m_platformDescription; -} - -PlatformMenuDescription ContextMenu::releasePlatformDescription() -{ - // Ref count remains the same, just pass it and remove our ref, so it - // will not be decremented when this object goes away. - PlatformMenuDescription description = m_platformDescription; - m_platformDescription = 0; - - return description; + return createNativeMenuFromItems(m_items); } } diff --git a/WebCore/platform/efl/ContextMenuItemEfl.cpp b/WebCore/platform/efl/ContextMenuItemEfl.cpp index efa743f..5ce8fab 100644 --- a/WebCore/platform/efl/ContextMenuItemEfl.cpp +++ b/WebCore/platform/efl/ContextMenuItemEfl.cpp @@ -30,114 +30,73 @@ #include "config.h" #include "ContextMenuItem.h" -#include "ContextMenu.h" #include "NotImplemented.h" namespace WebCore { -ContextMenuItem::ContextMenuItem(PlatformMenuItemDescription) +ContextMenuItem::ContextMenuItem(void* const&) { - // It's inside WebKit that this initialization is done, as WebCore doesn't - // know how PlatformMenuItemDescription is implemented. notImplemented(); } -ContextMenuItem::ContextMenuItem(ContextMenu* submenu) +ContextMenuItem::ContextMenuItem(ContextMenuItemType, ContextMenuAction, const String&, ContextMenu*) { - m_platformDescription.type = SubmenuType; - setSubMenu(submenu); -} - -ContextMenuItem::ContextMenuItem(ContextMenuItemType type, ContextMenuAction action, const String& title, ContextMenu* subMenu) -{ - m_platformDescription.type = type; - m_platformDescription.action = action; - m_platformDescription.title = String(title); - - setSubMenu(subMenu); + notImplemented(); } ContextMenuItem::~ContextMenuItem() { - if (m_platformDescription.subMenu) - delete m_platformDescription.subMenu; + notImplemented(); } -PlatformMenuItemDescription ContextMenuItem::releasePlatformDescription() +void* ContextMenuItem::nativeMenuItem() const { - return m_platformDescription; + notImplemented(); + return 0; } ContextMenuItemType ContextMenuItem::type() const { - return m_platformDescription.type; + notImplemented(); + return ActionType; } -void ContextMenuItem::setType(ContextMenuItemType type) +void ContextMenuItem::setAction(ContextMenuAction) { - m_platformDescription.type = type; + notImplemented(); } ContextMenuAction ContextMenuItem::action() const { - return m_platformDescription.action; -} - -void ContextMenuItem::setAction(ContextMenuAction action) -{ - m_platformDescription.action = action; -} - -String ContextMenuItem::title() const -{ - return m_platformDescription.title; -} - -void ContextMenuItem::setTitle(const String& title) -{ - m_platformDescription.title = String(title); -} - -PlatformMenuDescription ContextMenuItem::platformSubMenu() const -{ - if (!m_platformDescription.subMenu) - return 0; - - return m_platformDescription.subMenu->platformDescription(); - + notImplemented(); + return ContextMenuItemTagNoAction; } -void ContextMenuItem::setSubMenu(ContextMenu* subMenu) +void ContextMenuItem::setChecked(bool) { - delete m_platformDescription.subMenu; - m_platformDescription.subMenu = 0; - - if (!subMenu) - return; - - m_platformDescription.type = SubmenuType; - m_platformDescription.subMenu = new ContextMenu(subMenu->hitTestResult(), - subMenu->releasePlatformDescription()); + notImplemented(); } bool ContextMenuItem::checked() const { - return m_platformDescription.checked; + notImplemented(); + return 0; } -void ContextMenuItem::setChecked(bool shouldCheck) +void ContextMenuItem::setEnabled(bool) { - m_platformDescription.checked = shouldCheck; + notImplemented(); } bool ContextMenuItem::enabled() const { - return m_platformDescription.enabled; + notImplemented(); + return false; } -void ContextMenuItem::setEnabled(bool shouldEnable) +void ContextMenuItem::setSubMenu(ContextMenu*) { - m_platformDescription.enabled = shouldEnable; + notImplemented(); } } diff --git a/WebCore/platform/efl/SharedTimerEfl.cpp b/WebCore/platform/efl/SharedTimerEfl.cpp index 990d0c8..2534c60 100644 --- a/WebCore/platform/efl/SharedTimerEfl.cpp +++ b/WebCore/platform/efl/SharedTimerEfl.cpp @@ -30,25 +30,16 @@ #include "SharedTimer.h" #include <Ecore.h> -#include <pthread.h> -#include <stdio.h> #include <wtf/Assertions.h> #include <wtf/CurrentTime.h> #include <wtf/MainThread.h> namespace WebCore { -static pthread_mutex_t timerMutex = PTHREAD_MUTEX_INITIALIZER; static Ecore_Timer *_sharedTimer = 0; -static Ecore_Pipe *_pipe = 0; static void (*_timerFunction)(); -struct timerOp { - double time; - unsigned char op; // 0 - add a timer; 1 - del a timer; -}; - void setSharedTimerFiredFunction(void (*func)()) { _timerFunction = func; @@ -64,58 +55,20 @@ static Eina_Bool timerEvent(void*) return ECORE_CALLBACK_CANCEL; } -void processTimers(struct timerOp *tOp) +void stopSharedTimer() { if (_sharedTimer) { ecore_timer_del(_sharedTimer); _sharedTimer = 0; } - - if (tOp->op == 1) - return; - - double interval = tOp->time - currentTime(); - - if (interval <= ecore_animator_frametime_get()) { - if (_timerFunction) - _timerFunction(); - return; - } - - _sharedTimer = ecore_timer_add(interval, timerEvent, 0); -} - -void pipeHandlerCb(void *data, void *buffer, unsigned int nbyte) -{ - ASSERT(nbyte == sizeof(struct timerOp)); - - struct timerOp *tOp = (struct timerOp *)buffer; - processTimers(tOp); -} - -void stopSharedTimer() -{ - struct timerOp tOp; - pthread_mutex_lock(&timerMutex); - if (!_pipe) - _pipe = ecore_pipe_add(pipeHandlerCb, 0); - pthread_mutex_unlock(&timerMutex); - - tOp.op = 1; - ecore_pipe_write(_pipe, &tOp, sizeof(tOp)); } void addNewTimer(double fireTime) { - struct timerOp tOp; - pthread_mutex_lock(&timerMutex); - if (!_pipe) - _pipe = ecore_pipe_add(pipeHandlerCb, 0); - pthread_mutex_unlock(&timerMutex); + double interval = fireTime - currentTime(); + stopSharedTimer(); - tOp.time = fireTime; - tOp.op = 0; - ecore_pipe_write(_pipe, &tOp, sizeof(tOp)); + _sharedTimer = ecore_timer_loop_add(interval, timerEvent, 0); } void setSharedTimerFireTime(double fireTime) diff --git a/WebCore/platform/graphics/ContextShadow.cpp b/WebCore/platform/graphics/ContextShadow.cpp index 87a1c5c..b34e546 100644 --- a/WebCore/platform/graphics/ContextShadow.cpp +++ b/WebCore/platform/graphics/ContextShadow.cpp @@ -29,6 +29,8 @@ #include "config.h" #include "ContextShadow.h" +#include "FloatQuad.h" +#include <cmath> #include <wtf/MathExtras.h> #include <wtf/Noncopyable.h> @@ -41,6 +43,7 @@ ContextShadow::ContextShadow() : m_type(NoShadow) , m_blurDistance(0) , m_layerContext(0) + , m_shadowsIgnoreTransforms(false) { } @@ -49,6 +52,7 @@ ContextShadow::ContextShadow(const Color& color, float radius, const FloatSize& , m_blurDistance(round(radius)) , m_offset(offset) , m_layerContext(0) + , m_shadowsIgnoreTransforms(false) { // See comments in http://webkit.org/b/40793, it seems sensible // to follow Skia's limit of 128 pixels of blur radius @@ -77,6 +81,23 @@ void ContextShadow::clear() m_offset = FloatSize(); } +bool ContextShadow::mustUseContextShadow(PlatformContext context) +{ + // We can't avoid ContextShadow, since the shadow has blur. + if (m_type == ContextShadow::BlurShadow) + return true; + // We can avoid ContextShadow and optimize, since we're not drawing on a + // canvas and box shadows are affected by the transformation matrix. + if (!shadowsIgnoreTransforms()) + return false; + // We can avoid ContextShadow, since there are no transformations to apply to the canvas. + const TransformationMatrix transform(getTransformationMatrixFromContext(context)); + if (transform.isIdentity()) + return false; + // Otherwise, no chance avoiding ContextShadow. + return true; +} + // Instead of integer division, we use 17.15 for fixed-point division. static const int BlurSumShift = 15; @@ -149,29 +170,89 @@ void ContextShadow::blurLayerImage(unsigned char* imageData, const IntSize& size } } -void ContextShadow::calculateLayerBoundingRect(const FloatRect& layerArea, const IntRect& clipRect) +void ContextShadow::adjustBlurDistance(const PlatformContext context) +{ + // Adjust blur if we're scaling, since the radius must not be affected by transformations. + const TransformationMatrix transform(getTransformationMatrixFromContext(context)); + + if (transform.isIdentity()) + return; + + // Calculale transformed unit vectors. + const FloatQuad unitQuad(FloatPoint(0, 0), FloatPoint(1, 0), + FloatPoint(0, 1), FloatPoint(1, 1)); + const FloatQuad transformedUnitQuad = transform.mapQuad(unitQuad); + + // Calculate X axis scale factor. + const FloatSize xUnitChange = transformedUnitQuad.p2() - transformedUnitQuad.p1(); + const float xAxisScale = sqrtf(xUnitChange.width() * xUnitChange.width() + + xUnitChange.height() * xUnitChange.height()); + + // Calculate Y axis scale factor. + const FloatSize yUnitChange = transformedUnitQuad.p3() - transformedUnitQuad.p1(); + const float yAxisScale = sqrtf(yUnitChange.width() * yUnitChange.width() + + yUnitChange.height() * yUnitChange.height()); + + // blurLayerImage() does not support per-axis blurring, so calculate a balanced scaling. + const float scale = sqrtf(xAxisScale * yAxisScale); + m_blurDistance = roundf(static_cast<float>(m_blurDistance) / scale); +} + +IntRect ContextShadow::calculateLayerBoundingRect(const PlatformContext context, const FloatRect& layerArea, const IntRect& clipRect) { - // Calculate the destination of the blurred layer. - FloatRect destinationRect(layerArea); - destinationRect.move(m_offset); - m_layerRect = enclosingIntRect(destinationRect); + // Calculate the destination of the blurred and/or transformed layer. + FloatRect layerFloatRect; + float inflation = 0; + + const TransformationMatrix transform(getTransformationMatrixFromContext(context)); + if (m_shadowsIgnoreTransforms && !transform.isIdentity()) { + FloatQuad transformedPolygon = transform.mapQuad(FloatQuad(layerArea)); + transformedPolygon.move(m_offset); + layerFloatRect = transform.inverse().mapQuad(transformedPolygon).boundingBox(); + } else { + layerFloatRect = layerArea; + layerFloatRect.move(m_offset); + } // We expand the area by the blur radius to give extra space for the blur transition. - m_layerRect.inflate(m_type == BlurShadow ? m_blurDistance : 0); + if (m_type == BlurShadow) { + layerFloatRect.inflate(m_blurDistance); + inflation += m_blurDistance; + } + + FloatRect unclippedLayerRect = layerFloatRect; - if (!clipRect.contains(m_layerRect)) { + if (!clipRect.contains(enclosingIntRect(layerFloatRect))) { // No need to have the buffer larger than the clip. - m_layerRect.intersect(clipRect); + layerFloatRect.intersect(clipRect); // If we are totally outside the clip region, we aren't painting at all. - if (m_layerRect.isEmpty()) - return; + if (layerFloatRect.isEmpty()) + return IntRect(0, 0, 0, 0); // We adjust again because the pixels at the borders are still // potentially affected by the pixels outside the buffer. - if (m_type == BlurShadow) - m_layerRect.inflate(m_type == BlurShadow ? m_blurDistance : 0); + if (m_type == BlurShadow) { + layerFloatRect.inflate(m_blurDistance); + unclippedLayerRect.inflate(m_blurDistance); + inflation += m_blurDistance; + } } + + const int frameSize = inflation * 2; + m_sourceRect = IntRect(0, 0, layerArea.width() + frameSize, layerArea.height() + frameSize); + m_layerOrigin = FloatPoint(layerFloatRect.x(), layerFloatRect.y()); + + const FloatPoint m_unclippedLayerOrigin = FloatPoint(unclippedLayerRect.x(), unclippedLayerRect.y()); + const FloatSize clippedOut = m_unclippedLayerOrigin - m_layerOrigin; + + // Set the origin as the top left corner of the scratch image, or, in case there's a clipped + // out region, set the origin accordingly to the full bounding rect's top-left corner. + const float translationX = -layerArea.x() + inflation - fabsf(clippedOut.width()); + const float translationY = -layerArea.y() + inflation - fabsf(clippedOut.height()); + m_layerContextTranslation = FloatPoint(translationX, translationY); + + return enclosingIntRect(layerFloatRect); } } // namespace WebCore diff --git a/WebCore/platform/graphics/ContextShadow.h b/WebCore/platform/graphics/ContextShadow.h index 26f0a36..8f14229 100644 --- a/WebCore/platform/graphics/ContextShadow.h +++ b/WebCore/platform/graphics/ContextShadow.h @@ -79,6 +79,7 @@ public: ContextShadow(); ContextShadow(const Color&, float radius, const FloatSize& offset); + bool mustUseContextShadow(PlatformContext); void clear(); // The pair beginShadowLayer and endShadowLayer creates a temporary image @@ -106,27 +107,29 @@ public: PlatformContext beginShadowLayer(PlatformContext, const FloatRect& layerArea); void endShadowLayer(PlatformContext); static void purgeScratchBuffer(); + static TransformationMatrix getTransformationMatrixFromContext(PlatformContext); + + void setShadowsIgnoreTransforms(bool enable) { m_shadowsIgnoreTransforms = enable; } + bool shadowsIgnoreTransforms() const { return m_shadowsIgnoreTransforms; } #if PLATFORM(CAIRO) void drawRectShadow(GraphicsContext* context, const IntRect& rect, const IntSize& topLeftRadius = IntSize(), const IntSize& topRightRadius = IntSize(), const IntSize& bottomLeftRadius = IntSize(), const IntSize& bottomRightRadius = IntSize()); #endif - #if PLATFORM(QT) - QPointF offset() { return QPointF(m_offset.width(), m_offset.height()); } + QPointF offset() const { return QPointF(m_offset.width(), m_offset.height()); } #endif - private: - IntRect m_layerRect; - PlatformImage m_layerImage; - PlatformContext m_layerContext; - -#if PLATFORM(QT) - // Used for reference when canvas scale(x,y) was called. - FloatRect m_unscaledLayerRect; -#endif - + PlatformImage m_layerImage; // Buffer to where the temporary shadow will be drawn to. + PlatformContext m_layerContext; // Context used to paint the shadow to the layer image. + FloatRect m_sourceRect; // Sub-rect of m_layerImage that contains the shadow pixels. + FloatPoint m_layerOrigin; // Top-left corner of the (possibly clipped) bounding rect to draw the shadow to. + FloatPoint m_layerContextTranslation; // Translation to apply to m_layerContext for the shadow to be correctly clipped. + bool m_shadowsIgnoreTransforms; + + void adjustBlurDistance(const PlatformContext); void blurLayerImage(unsigned char*, const IntSize& imageSize, int stride); - void calculateLayerBoundingRect(const FloatRect& layerArea, const IntRect& clipRect); + IntRect calculateLayerBoundingRect(const PlatformContext, const FloatRect& layerArea, const IntRect& clipRect); + #if PLATFORM(CAIRO) void drawRectShadowWithoutTiling(PlatformContext context, const IntRect& shadowRect, const IntSize& topLeftRadius, const IntSize& topRightRadius, const IntSize& bottomLeftRadius, const IntSize& bottomRightRadius, float alpha); #endif diff --git a/WebCore/platform/graphics/Extensions3D.h b/WebCore/platform/graphics/Extensions3D.h index 74210a5..0363a48 100644 --- a/WebCore/platform/graphics/Extensions3D.h +++ b/WebCore/platform/graphics/Extensions3D.h @@ -50,11 +50,17 @@ public: // GL_ARB_texture_non_power_of_two / GL_OES_texture_npot // GL_EXT_packed_depth_stencil / GL_OES_packed_depth_stencil // GL_ANGLE_framebuffer_blit / GL_ANGLE_framebuffer_multisample + // GL_OES_texture_float // Takes full name of extension; for example, // "GL_EXT_texture_format_BGRA8888". virtual bool supports(const String&) = 0; + // Certain OpenGL and WebGL implementations may support enabling + // extensions lazily. This method may only be called with + // extension names for which supports returns true. + virtual void ensureEnabled(const String&) = 0; + enum ExtensionsEnumType { // GL_EXT_texture_format_BGRA8888 enums BGRA_EXT = 0x80E1, diff --git a/WebCore/platform/graphics/FloatPoint3D.h b/WebCore/platform/graphics/FloatPoint3D.h index b6cbaa8..ba0ee9d 100644 --- a/WebCore/platform/graphics/FloatPoint3D.h +++ b/WebCore/platform/graphics/FloatPoint3D.h @@ -84,6 +84,11 @@ public: m_z *= sz; } + bool isZero() const + { + return !m_x && !m_y && !m_z; + } + void normalize(); float dot(const FloatPoint3D& a) const @@ -115,6 +120,8 @@ public: float lengthSquared() const { return this->dot(*this); } float length() const { return sqrtf(lengthSquared()); } + + float distanceTo(const FloatPoint3D& a) const; private: float m_x; @@ -160,6 +167,21 @@ inline float operator*(const FloatPoint3D& a, const FloatPoint3D& b) return a.dot(b); } +inline FloatPoint3D operator*(float k, const FloatPoint3D& v) +{ + return FloatPoint3D(k * v.x(), k * v.y(), k * v.z()); +} + +inline FloatPoint3D operator*(const FloatPoint3D& v, float k) +{ + return FloatPoint3D(k * v.x(), k * v.y(), k * v.z()); +} + +inline float FloatPoint3D::distanceTo(const FloatPoint3D& a) const +{ + return (*this - a).length(); +} + } // namespace WebCore #endif // FloatPoint3D_h diff --git a/WebCore/platform/graphics/Font.cpp b/WebCore/platform/graphics/Font.cpp index 6bbf3d7..8828a31 100644 --- a/WebCore/platform/graphics/Font.cpp +++ b/WebCore/platform/graphics/Font.cpp @@ -156,6 +156,26 @@ void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoi return drawComplexText(context, run, point, from, to); } +void Font::drawEmphasisMarks(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const +{ + if (m_fontList && m_fontList->loadingCustomFonts()) + return; + + if (to < 0) + to = run.length(); + +#if ENABLE(SVG_FONTS) + // FIXME: Implement for SVG fonts. + if (primaryFont()->isSVGFont()) + return; +#endif + + if (codePath(run) != Complex) + drawEmphasisMarksForSimpleText(context, run, mark, point, from, to); + else + drawEmphasisMarksForComplexText(context, run, mark, point, from, to); +} + float Font::floatWidth(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { #if ENABLE(SVG_FONTS) @@ -354,6 +374,42 @@ bool Font::isCJKIdeograph(UChar32 c) if (c >= 0x2F00 && c <= 0x2FDF) return true; + // CJK Strokes. + if (c >= 0x31C0 && c <= 0x31EF) + return true; + + // CJK Compatibility Ideographs. + if (c >= 0xF900 && c <= 0xFAFF) + return true; + + // CJK Unified Ideographs Extension B. + if (c >= 0x20000 && c <= 0x2A6DF) + return true; + + // CJK Unified Ideographs Extension C. + if (c >= 0x2A700 && c <= 0x2B73F) + return true; + + // CJK Unified Ideographs Extension D. + if (c >= 0x2B740 && c <= 0x2B81F) + return true; + + // CJK Compatibility Ideographs Supplement. + if (c >= 0x2F800 && c <= 0x2FA1F) + return true; + + return false; +} + +bool Font::isCJKIdeographOrSymbol(UChar32 c) +{ + // 0x2C7 Caron, Mandarin Chinese 3rd Tone + // 0x2CA Modifier Letter Acute Accent, Mandarin Chinese 2nd Tone + // 0x2CB Modifier Letter Grave Access, Mandarin Chinese 4th Tone + // 0x2D9 Dot Above, Mandarin Chinese 5th Tone + if ((c == 0x2C7) || (c == 0x2CA) || (c == 0x2CB) || (c == 0x2D9)) + return true; + // Ideographic Description Characters. if (c >= 0x2FF0 && c <= 0x2FFF) return true; @@ -361,11 +417,23 @@ bool Font::isCJKIdeograph(UChar32 c) // CJK Symbols and Punctuation. if (c >= 0x3000 && c <= 0x303F) return true; - - // CJK Strokes. - if (c >= 0x31C0 && c <= 0x31EF) + + // Hiragana + if (c >= 0x3040 && c <= 0x309F) + return true; + + // Katakana + if (c >= 0x30A0 && c <= 0x30FF) + return true; + + // Bopomofo + if (c >= 0x3100 && c <= 0x312F) return true; + // Bopomofo Extended + if (c >= 0x31A0 && c <= 0x31BF) + return true; + // Enclosed CJK Letters and Months. if (c >= 0x3200 && c <= 0x32FF) return true; @@ -374,35 +442,34 @@ bool Font::isCJKIdeograph(UChar32 c) if (c >= 0x3300 && c <= 0x33FF) return true; - // CJK Compatibility Ideographs. - if (c >= 0xF900 && c <= 0xFAFF) - return true; - // CJK Compatibility Forms. if (c >= 0xFE30 && c <= 0xFE4F) return true; + // Halfwidth and Fullwidth Forms + // Usually only used in CJK + if (c >= 0xFF00 && c <= 0xFFEF) + return true; + // Emoji. if (c >= 0x1F200 && c <= 0x1F6F) return true; - // CJK Unified Ideographs Extension B. - if (c >= 0x20000 && c <= 0x2A6DF) - return true; - - // CJK Unified Ideographs Extension C. - if (c >= 0x2A700 && c <= 0x2B73F) - return true; - - // CJK Unified Ideographs Extension D. - if (c >= 0x2B740 && c <= 0x2B81F) - return true; - - // CJK Compatibility Ideographs Supplement. - if (c >= 0x2F800 && c <= 0x2FA1F) - return true; + return isCJKIdeograph(c); +} - return false; +bool Font::canReceiveTextEmphasis(UChar32 c) +{ + CharCategory category = Unicode::category(c); + if (category & (Separator_Space | Separator_Line | Separator_Paragraph | Other_NotAssigned | Other_Control | Other_Format)) + return false; + + // Additional word-separator characters listed in CSS Text Level 3 Editor's Draft 3 November 2010. + if (c == ethiopicWordspace || c == aegeanWordSeparatorLine || c == aegeanWordSeparatorDot + || c == ugariticWordDivider || c == tibetanMarkIntersyllabicTsheg || c == tibetanMarkDelimiterTshegBstar) + return false; + + return true; } } diff --git a/WebCore/platform/graphics/Font.h b/WebCore/platform/graphics/Font.h index cb83ad2..4097f1e 100644 --- a/WebCore/platform/graphics/Font.h +++ b/WebCore/platform/graphics/Font.h @@ -93,6 +93,7 @@ public: void update(PassRefPtr<FontSelector>) const; void drawText(GraphicsContext*, const TextRun&, const FloatPoint&, int from = 0, int to = -1) const; + void drawEmphasisMarks(GraphicsContext*, const TextRun&, const AtomicString& mark, const FloatPoint&, int from = 0, int to = -1) const; int width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* glyphOverflow = 0) const { return lroundf(floatWidth(run, fallbackFonts, glyphOverflow)); } float floatWidth(const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* glyphOverflow = 0) const; @@ -136,14 +137,18 @@ public: unsigned unitsPerEm() const { return primaryFont()->unitsPerEm(); } int spaceWidth() const { return (int)ceilf(primaryFont()->adjustedSpaceWidth() + m_letterSpacing); } float tabWidth(const SimpleFontData& fontData) const { return 8 * ceilf(fontData.adjustedSpaceWidth() + letterSpacing()); } + int emphasisMarkAscent(const AtomicString&) const; + int emphasisMarkDescent(const AtomicString&) const; + int emphasisMarkHeight(const AtomicString&) const; const SimpleFontData* primaryFont() const; const FontData* fontDataAt(unsigned) const; - GlyphData glyphDataForCharacter(UChar32, bool mirror, bool forceSmallCaps = false) const; + GlyphData glyphDataForCharacter(UChar32, bool mirror, FontDataVariant = AutoVariant) 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); #if PLATFORM(QT) QFont font() const; @@ -163,17 +168,29 @@ private: int offsetForPositionForTextUsingSVGFont(const TextRun&, float position, bool includePartialGlyphs) const; #endif + enum ForTextEmphasisOrNot { NotForTextEmphasis, ForTextEmphasis }; + + // Returns the initial in-stream advance. + float getGlyphsAndAdvancesForSimpleText(const TextRun&, int from, int to, GlyphBuffer&, ForTextEmphasisOrNot = NotForTextEmphasis) const; void drawSimpleText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const; + void drawEmphasisMarksForSimpleText(GraphicsContext*, const TextRun&, const AtomicString& mark, const FloatPoint&, int from, int to) const; void drawGlyphs(GraphicsContext*, const SimpleFontData*, const GlyphBuffer&, int from, int to, const FloatPoint&) const; - void drawGlyphBuffer(GraphicsContext*, const GlyphBuffer&, const TextRun&, const FloatPoint&) const; + void drawGlyphBuffer(GraphicsContext*, const GlyphBuffer&, const FloatPoint&) const; + void drawEmphasisMarks(GraphicsContext* context, const GlyphBuffer&, const AtomicString&, const FloatPoint&) const; float floatWidthForSimpleText(const TextRun&, GlyphBuffer*, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const; int offsetForPositionForSimpleText(const TextRun&, float position, bool includePartialGlyphs) const; FloatRect selectionRectForSimpleText(const TextRun&, const FloatPoint&, int h, int from, int to) const; + bool getEmphasisMarkGlyphData(const AtomicString&, GlyphData&) const; + static bool canReturnFallbackFontsForComplexText(); CodePath codePath(const TextRun&) const; + + // Returns the initial in-stream advance. + float getGlyphsAndAdvancesForComplexText(const TextRun&, int from, int to, GlyphBuffer&, ForTextEmphasisOrNot = NotForTextEmphasis) const; void drawComplexText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const; + void drawEmphasisMarksForComplexText(GraphicsContext*, const TextRun&, const AtomicString& mark, const FloatPoint&, int from, int to) const; float floatWidthForComplexText(const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const; int offsetForPositionForComplexText(const TextRun&, float position, bool includePartialGlyphs) const; FloatRect selectionRectForComplexText(const TextRun&, const FloatPoint&, int h, int from, int to) const; @@ -195,6 +212,7 @@ public: FontSelector* fontSelector() const; static bool treatAsSpace(UChar c) { return c == ' ' || c == '\t' || c == '\n' || c == noBreakSpace; } static bool treatAsZeroWidthSpace(UChar c) { return c < 0x20 || (c >= 0x7F && c < 0xA0) || c == softHyphen || (c >= 0x200c && c <= 0x200f) || (c >= 0x202a && c <= 0x202e) || c == objectReplacementCharacter; } + static bool canReceiveTextEmphasis(UChar32 c); static inline UChar normalizeSpaces(UChar character) { diff --git a/WebCore/platform/graphics/FontFastPath.cpp b/WebCore/platform/graphics/FontFastPath.cpp index f0dd33e..73904e0 100644 --- a/WebCore/platform/graphics/FontFastPath.cpp +++ b/WebCore/platform/graphics/FontFastPath.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2003, 2006 Apple Computer, Inc. + * Copyright (C) 2003, 2006, 2010 Apple Inc. All rights reserved. * Copyright (C) 2008 Holger Hans Peter Freyther * Copyright (C) 2009 Torch Mobile, Inc. * @@ -40,17 +40,20 @@ using namespace Unicode; namespace WebCore { -GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCaps) const +GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, FontDataVariant variant) const { ASSERT(isMainThread()); - bool useSmallCapsFont = forceSmallCaps; - if (m_fontDescription.smallCaps()) { - UChar32 upperC = toUpper(c); - if (upperC != c) { - c = upperC; - useSmallCapsFont = true; - } + if (variant == AutoVariant) { + if (m_fontDescription.smallCaps()) { + UChar32 upperC = toUpper(c); + if (upperC != c) { + c = upperC; + variant = SmallCapsVariant; + } else + variant = NormalVariant; + } else + variant = NormalVariant; } if (mirror) @@ -68,14 +71,14 @@ GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCap } GlyphPage* page; - if (!useSmallCapsFont) { - // Fastest loop, for the common case (not small caps). + if (variant == NormalVariant) { + // Fastest loop, for the common case (normal variant). while (true) { page = node->page(); if (page) { GlyphData data = page->glyphDataForCharacter(c); if (data.fontData) { - if (data.fontData->platformData().orientation() == Vertical && data.fontData->orientation() == Horizontal && Font::isCJKIdeograph(c)) { + 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(); @@ -108,23 +111,23 @@ GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCap if (page) { GlyphData data = page->glyphDataForCharacter(c); if (data.fontData) { - // The smallCapsFontData function should not normally return 0. + // The variantFontData function should not normally return 0. // But if it does, we will just render the capital letter big. - const SimpleFontData* smallCapsFontData = data.fontData->smallCapsFontData(m_fontDescription); - if (!smallCapsFontData) + const SimpleFontData* variantFontData = data.fontData->variantFontData(m_fontDescription, variant); + if (!variantFontData) return data; - GlyphPageTreeNode* smallCapsNode = GlyphPageTreeNode::getRootChild(smallCapsFontData, pageNumber); - const GlyphPage* smallCapsPage = smallCapsNode->page(); - if (smallCapsPage) { - GlyphData data = smallCapsPage->glyphDataForCharacter(c); + GlyphPageTreeNode* variantNode = GlyphPageTreeNode::getRootChild(variantFontData, pageNumber); + const GlyphPage* variantPage = variantNode->page(); + if (variantPage) { + GlyphData data = variantPage->glyphDataForCharacter(c); if (data.fontData) return data; } - // Do not attempt system fallback off the smallCapsFontData. This is the very unlikely case that + // Do not attempt system fallback off the variantFontData. This is the very unlikely case that // a font has the lowercase character but the small caps font does not have its uppercase version. - return smallCapsFontData->missingGlyphData(); + return variantFontData->missingGlyphData(); } if (node->isSystemFallback()) @@ -157,14 +160,14 @@ GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCap codeUnitsLength = 2; } const SimpleFontData* characterFontData = fontCache()->getFontDataForCharacters(*this, codeUnits, codeUnitsLength); - if (useSmallCapsFont && characterFontData) - characterFontData = characterFontData->smallCapsFontData(m_fontDescription); + if (variant != NormalVariant && characterFontData) + characterFontData = characterFontData->variantFontData(m_fontDescription, variant); if (characterFontData) { // Got the fallback glyph and font. GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page(); GlyphData data = fallbackPage && fallbackPage->fontDataForCharacter(c) ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData(); // Cache it so we don't have to do system fallback again next time. - if (!useSmallCapsFont) { + if (variant == NormalVariant) { #if OS(WINCE) // missingGlyphData returns a null character, which is not suitable for GDI to display. // Also, sometimes we cannot map a font for the character on WINCE, but GDI can still @@ -182,7 +185,7 @@ GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCap // Even system fallback can fail; use the missing glyph in that case. // FIXME: It would be nicer to use the missing glyph from the last resort font instead. GlyphData data = primaryFont()->missingGlyphData(); - if (!useSmallCapsFont) { + if (variant == NormalVariant) { #if OS(WINCE) // See comment about WINCE GDI handling near setGlyphDataForCharacter above. page->setGlyphDataForCharacter(c, c, data.fontData); @@ -194,42 +197,136 @@ GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCap return data; } -void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const +// FIXME: This function may not work if the emphasis mark uses a complex script, but none of the +// standard emphasis marks do so. +bool Font::getEmphasisMarkGlyphData(const AtomicString& mark, GlyphData& glyphData) const { - // This glyph buffer holds our glyphs+advances+font data for each glyph. - GlyphBuffer glyphBuffer; + if (mark.isEmpty()) + return false; - float startX = point.x(); - WidthIterator it(this, run); +#if ENABLE(SVG_FONTS) + // FIXME: Implement for SVG fonts. + if (primaryFont()->isSVGFont()) + return false; +#endif + + UChar32 character = mark[0]; + + if (U16_IS_SURROGATE(character)) { + if (!U16_IS_SURROGATE_LEAD(character)) + return false; + + if (mark.length() < 2) + return false; + + UChar low = mark[1]; + if (!U16_IS_TRAIL(low)) + return false; + + character = U16_GET_SUPPLEMENTARY(character, low); + } + + glyphData = glyphDataForCharacter(character, false, EmphasisMarkVariant); + return true; +} + +int Font::emphasisMarkAscent(const AtomicString& mark) const +{ + GlyphData markGlyphData; + if (!getEmphasisMarkGlyphData(mark, markGlyphData)) + return 0; + + const SimpleFontData* markFontData = markGlyphData.fontData; + ASSERT(markFontData); + if (!markFontData) + return 0; + + return markFontData->ascent(); +} + +int Font::emphasisMarkDescent(const AtomicString& mark) const +{ + GlyphData markGlyphData; + if (!getEmphasisMarkGlyphData(mark, markGlyphData)) + return 0; + + const SimpleFontData* markFontData = markGlyphData.fontData; + ASSERT(markFontData); + if (!markFontData) + return 0; + + return markFontData->descent(); +} + +int Font::emphasisMarkHeight(const AtomicString& mark) const +{ + GlyphData markGlyphData; + if (!getEmphasisMarkGlyphData(mark, markGlyphData)) + return 0; + + const SimpleFontData* markFontData = markGlyphData.fontData; + ASSERT(markFontData); + if (!markFontData) + return 0; + + return markFontData->height(); +} + +float Font::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const +{ + float initialAdvance; + + WidthIterator it(this, run, 0, false, forTextEmphasis); it.advance(from); float beforeWidth = it.m_runWidthSoFar; it.advance(to, &glyphBuffer); - - // We couldn't generate any glyphs for the run. Give up. + if (glyphBuffer.isEmpty()) - return; - + return 0; + float afterWidth = it.m_runWidthSoFar; if (run.rtl()) { float finalRoundingWidth = it.m_finalRoundingWidth; it.advance(run.length()); - startX += finalRoundingWidth + it.m_runWidthSoFar - afterWidth; + initialAdvance = finalRoundingWidth + it.m_runWidthSoFar - afterWidth; } else - startX += beforeWidth; + initialAdvance = beforeWidth; - // Swap the order of the glyphs if right-to-left. - if (run.rtl()) + if (run.rtl()) { for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end) glyphBuffer.swap(i, end); + } + + return initialAdvance; +} + +void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const +{ + // This glyph buffer holds our glyphs+advances+font data for each glyph. + GlyphBuffer glyphBuffer; + + float startX = point.x() + getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer); + + if (glyphBuffer.isEmpty()) + return; - // Calculate the starting point of the glyphs to be displayed by adding - // all the advances up to the first glyph. FloatPoint startPoint(startX, point.y()); - drawGlyphBuffer(context, glyphBuffer, run, startPoint); + drawGlyphBuffer(context, glyphBuffer, startPoint); +} + +void Font::drawEmphasisMarksForSimpleText(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const +{ + GlyphBuffer glyphBuffer; + float initialAdvance = getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer, ForTextEmphasis); + + if (glyphBuffer.isEmpty()) + return; + + drawEmphasisMarks(context, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y())); } -void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const TextRun&, const FloatPoint& point) const +void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const FloatPoint& point) const { // Draw each contiguous run of glyphs that use the same font data. const SimpleFontData* fontData = glyphBuffer.fontDataAt(0); @@ -256,6 +353,50 @@ void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuf drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); } +inline static float offsetToMiddleOfGlyph(const SimpleFontData* fontData, Glyph glyph) +{ + if (fontData->orientation() == Horizontal) { + FloatRect bounds = fontData->boundsForGlyph(glyph); + return bounds.x() + bounds.width() / 2; + } + // FIXME: Use glyph bounds once they make sense for vertical fonts. + return fontData->widthForGlyph(glyph) / 2; +} + +inline static float offsetToMiddleOfGlyphAtIndex(const GlyphBuffer& glyphBuffer, size_t i) +{ + return offsetToMiddleOfGlyph(glyphBuffer.fontDataAt(i), glyphBuffer.glyphAt(i)); +} + +void Font::drawEmphasisMarks(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoint& point) const +{ + GlyphData markGlyphData; + if (!getEmphasisMarkGlyphData(mark, markGlyphData)) + return; + + const SimpleFontData* markFontData = markGlyphData.fontData; + ASSERT(markFontData); + if (!markFontData) + return; + + Glyph markGlyph = markGlyphData.glyph; + Glyph spaceGlyph = markFontData->spaceGlyph(); + + float middleOfLastGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, 0); + FloatPoint startPoint(point.x() + middleOfLastGlyph - offsetToMiddleOfGlyph(markFontData, markGlyph), point.y()); + + GlyphBuffer markBuffer; + for (int i = 0; i + 1 < glyphBuffer.size(); ++i) { + float middleOfNextGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, i + 1); + float advance = glyphBuffer.advanceAt(i) - middleOfLastGlyph + middleOfNextGlyph; + markBuffer.add(glyphBuffer.glyphAt(i) ? markGlyph : spaceGlyph, markFontData, advance); + middleOfLastGlyph = middleOfNextGlyph; + } + markBuffer.add(glyphBuffer.glyphAt(glyphBuffer.size() - 1) ? markGlyph : spaceGlyph, markFontData, 0); + + drawGlyphBuffer(context, markBuffer, startPoint); +} + float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { WidthIterator it(this, run, fallbackFonts, glyphOverflow); diff --git a/WebCore/platform/graphics/GeneratedImage.cpp b/WebCore/platform/graphics/GeneratedImage.cpp index 5df2608..f2c175b 100644 --- a/WebCore/platform/graphics/GeneratedImage.cpp +++ b/WebCore/platform/graphics/GeneratedImage.cpp @@ -57,7 +57,8 @@ void GeneratedImage::drawPattern(GraphicsContext* context, const FloatRect& srcR // Create a BitmapImage and call drawPattern on it. OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(adjustedSize); - ASSERT(imageBuffer.get()); + if (!imageBuffer) + return; // Fill with the gradient. GraphicsContext* graphicsContext = imageBuffer->context(); diff --git a/WebCore/platform/graphics/GraphicsContext.cpp b/WebCore/platform/graphics/GraphicsContext.cpp index d80b365..49a7a9c 100644 --- a/WebCore/platform/graphics/GraphicsContext.cpp +++ b/WebCore/platform/graphics/GraphicsContext.cpp @@ -29,7 +29,6 @@ #include "BidiResolver.h" #include "Font.h" #include "Generator.h" -#include "GraphicsContextPrivate.h" #include "ImageBuffer.h" using namespace std; @@ -74,14 +73,15 @@ private: int m_offset; }; -GraphicsContextPrivate* GraphicsContext::createGraphicsContextPrivate() +GraphicsContext::GraphicsContext(PlatformGraphicsContext* platformGraphicsContext) + : m_updatingControlTints(false) { - return new GraphicsContextPrivate; + platformInit(platformGraphicsContext); } -void GraphicsContext::destroyGraphicsContextPrivate(GraphicsContextPrivate* deleteMe) +GraphicsContext::~GraphicsContext() { - delete deleteMe; + platformDestroy(); } void GraphicsContext::save() @@ -89,7 +89,7 @@ void GraphicsContext::save() if (paintingDisabled()) return; - m_common->stack.append(m_common->state); + m_stack.append(m_state); savePlatformState(); } @@ -99,120 +99,139 @@ void GraphicsContext::restore() if (paintingDisabled()) return; - if (m_common->stack.isEmpty()) { + if (m_stack.isEmpty()) { LOG_ERROR("ERROR void GraphicsContext::restore() stack is empty"); return; } - m_common->state = m_common->stack.last(); - m_common->stack.removeLast(); + m_state = m_stack.last(); + m_stack.removeLast(); restorePlatformState(); } void GraphicsContext::setStrokeThickness(float thickness) { - m_common->state.strokeThickness = thickness; + m_state.strokeThickness = thickness; setPlatformStrokeThickness(thickness); } void GraphicsContext::setStrokeStyle(const StrokeStyle& style) { - m_common->state.strokeStyle = style; + m_state.strokeStyle = style; setPlatformStrokeStyle(style); } void GraphicsContext::setStrokeColor(const Color& color, ColorSpace colorSpace) { - m_common->state.strokeColor = color; - m_common->state.strokeColorSpace = colorSpace; - m_common->state.strokeGradient.clear(); - m_common->state.strokePattern.clear(); + m_state.strokeColor = color; + m_state.strokeColorSpace = colorSpace; + m_state.strokeGradient.clear(); + m_state.strokePattern.clear(); setPlatformStrokeColor(color, colorSpace); } void GraphicsContext::setShadow(const FloatSize& offset, float blur, const Color& color, ColorSpace colorSpace) { - m_common->state.shadowOffset = offset; - m_common->state.shadowBlur = blur; - m_common->state.shadowColor = color; + m_state.shadowOffset = offset; + m_state.shadowBlur = blur; + m_state.shadowColor = color; + m_state.shadowColorSpace = colorSpace; setPlatformShadow(offset, blur, color, colorSpace); } void GraphicsContext::clearShadow() { - m_common->state.shadowOffset = FloatSize(); - m_common->state.shadowBlur = 0; - m_common->state.shadowColor = Color(); + m_state.shadowOffset = FloatSize(); + m_state.shadowBlur = 0; + m_state.shadowColor = Color(); + m_state.shadowColorSpace = ColorSpaceDeviceRGB; clearPlatformShadow(); } -bool GraphicsContext::getShadow(FloatSize& offset, float& blur, Color& color) const +bool GraphicsContext::getShadow(FloatSize& offset, float& blur, Color& color, ColorSpace& colorSpace) const { - offset = m_common->state.shadowOffset; - blur = m_common->state.shadowBlur; - color = m_common->state.shadowColor; + offset = m_state.shadowOffset; + blur = m_state.shadowBlur; + color = m_state.shadowColor; + colorSpace = m_state.shadowColorSpace; return color.isValid() && color.alpha() && (blur || offset.width() || offset.height()); } float GraphicsContext::strokeThickness() const { - return m_common->state.strokeThickness; + return m_state.strokeThickness; } StrokeStyle GraphicsContext::strokeStyle() const { - return m_common->state.strokeStyle; + return m_state.strokeStyle; } Color GraphicsContext::strokeColor() const { - return m_common->state.strokeColor; + return m_state.strokeColor; } ColorSpace GraphicsContext::strokeColorSpace() const { - return m_common->state.strokeColorSpace; + return m_state.strokeColorSpace; } WindRule GraphicsContext::fillRule() const { - return m_common->state.fillRule; + return m_state.fillRule; } void GraphicsContext::setFillRule(WindRule fillRule) { - m_common->state.fillRule = fillRule; + m_state.fillRule = fillRule; } void GraphicsContext::setFillColor(const Color& color, ColorSpace colorSpace) { - m_common->state.fillColor = color; - m_common->state.fillColorSpace = colorSpace; - m_common->state.fillGradient.clear(); - m_common->state.fillPattern.clear(); + m_state.fillColor = color; + m_state.fillColorSpace = colorSpace; + m_state.fillGradient.clear(); + m_state.fillPattern.clear(); setPlatformFillColor(color, colorSpace); } Color GraphicsContext::fillColor() const { - return m_common->state.fillColor; + return m_state.fillColor; } ColorSpace GraphicsContext::fillColorSpace() const { - return m_common->state.fillColorSpace; + return m_state.fillColorSpace; } void GraphicsContext::setShouldAntialias(bool b) { - m_common->state.shouldAntialias = b; + m_state.shouldAntialias = b; setPlatformShouldAntialias(b); } bool GraphicsContext::shouldAntialias() const { - return m_common->state.shouldAntialias; + return m_state.shouldAntialias; +} + +void GraphicsContext::setShouldSmoothFonts(bool b) +{ + m_state.shouldSmoothFonts = b; + setPlatformShouldSmoothFonts(b); +} + +bool GraphicsContext::shouldSmoothFonts() const +{ + return m_state.shouldSmoothFonts; +} + +const GraphicsContextState& GraphicsContext::state() const +{ + return m_state; } void GraphicsContext::setStrokePattern(PassRefPtr<Pattern> pattern) @@ -222,9 +241,9 @@ void GraphicsContext::setStrokePattern(PassRefPtr<Pattern> pattern) setStrokeColor(Color::black, ColorSpaceDeviceRGB); return; } - m_common->state.strokeGradient.clear(); - m_common->state.strokePattern = pattern; - setPlatformStrokePattern(m_common->state.strokePattern.get()); + m_state.strokeGradient.clear(); + m_state.strokePattern = pattern; + setPlatformStrokePattern(m_state.strokePattern.get()); } void GraphicsContext::setFillPattern(PassRefPtr<Pattern> pattern) @@ -234,9 +253,9 @@ void GraphicsContext::setFillPattern(PassRefPtr<Pattern> pattern) setFillColor(Color::black, ColorSpaceDeviceRGB); return; } - m_common->state.fillGradient.clear(); - m_common->state.fillPattern = pattern; - setPlatformFillPattern(m_common->state.fillPattern.get()); + m_state.fillGradient.clear(); + m_state.fillPattern = pattern; + setPlatformFillPattern(m_state.fillPattern.get()); } void GraphicsContext::setStrokeGradient(PassRefPtr<Gradient> gradient) @@ -246,9 +265,9 @@ void GraphicsContext::setStrokeGradient(PassRefPtr<Gradient> gradient) setStrokeColor(Color::black, ColorSpaceDeviceRGB); return; } - m_common->state.strokeGradient = gradient; - m_common->state.strokePattern.clear(); - setPlatformStrokeGradient(m_common->state.strokeGradient.get()); + m_state.strokeGradient = gradient; + m_state.strokePattern.clear(); + setPlatformStrokeGradient(m_state.strokeGradient.get()); } void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient) @@ -258,34 +277,39 @@ void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient) setFillColor(Color::black, ColorSpaceDeviceRGB); return; } - m_common->state.fillGradient = gradient; - m_common->state.fillPattern.clear(); - setPlatformFillGradient(m_common->state.fillGradient.get()); + m_state.fillGradient = gradient; + m_state.fillPattern.clear(); + setPlatformFillGradient(m_state.fillGradient.get()); } Gradient* GraphicsContext::fillGradient() const { - return m_common->state.fillGradient.get(); + return m_state.fillGradient.get(); } Gradient* GraphicsContext::strokeGradient() const { - return m_common->state.strokeGradient.get(); + return m_state.strokeGradient.get(); } Pattern* GraphicsContext::fillPattern() const { - return m_common->state.fillPattern.get(); + return m_state.fillPattern.get(); } Pattern* GraphicsContext::strokePattern() const { - return m_common->state.strokePattern.get(); + return m_state.strokePattern.get(); } void GraphicsContext::setShadowsIgnoreTransforms(bool ignoreTransforms) { - m_common->state.shadowsIgnoreTransforms = ignoreTransforms; + m_state.shadowsIgnoreTransforms = ignoreTransforms; +} + +bool GraphicsContext::shadowsIgnoreTransforms() const +{ + return m_state.shadowsIgnoreTransforms; } bool GraphicsContext::shadowsIgnoreTransforms() const @@ -295,23 +319,23 @@ bool GraphicsContext::shadowsIgnoreTransforms() const bool GraphicsContext::updatingControlTints() const { - return m_common->m_updatingControlTints; + return m_updatingControlTints; } void GraphicsContext::setUpdatingControlTints(bool b) { setPaintingDisabled(b); - m_common->m_updatingControlTints = b; + m_updatingControlTints = b; } void GraphicsContext::setPaintingDisabled(bool f) { - m_common->state.paintingDisabled = f; + m_state.paintingDisabled = f; } bool GraphicsContext::paintingDisabled() const { - return m_common->state.paintingDisabled; + return m_state.paintingDisabled; } void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntPoint& p, CompositeOperator op) @@ -344,6 +368,14 @@ void GraphicsContext::drawText(const Font& font, const TextRun& run, const IntPo } #endif +void GraphicsContext::drawEmphasisMarks(const Font& font, const TextRun& run, const AtomicString& mark, const IntPoint& point, int from, int to) +{ + if (paintingDisabled()) + return; + + font.drawEmphasisMarks(this, run, mark, point, from, to); +} + void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const FloatPoint& point) { if (paintingDisabled()) @@ -531,14 +563,14 @@ void GraphicsContext::clipToImageBuffer(ImageBuffer* buffer, const FloatRect& re buffer->clip(this, rect); } -int GraphicsContext::textDrawingMode() +TextDrawingModeFlags GraphicsContext::textDrawingMode() const { - return m_common->state.textDrawingMode; + return m_state.textDrawingMode; } -void GraphicsContext::setTextDrawingMode(int mode) +void GraphicsContext::setTextDrawingMode(TextDrawingModeFlags mode) { - m_common->state.textDrawingMode = mode; + m_state.textDrawingMode = mode; if (paintingDisabled()) return; setPlatformTextDrawingMode(mode); @@ -551,7 +583,22 @@ void GraphicsContext::fillRect(const FloatRect& rect, Generator& generator) generator.fill(this, rect); } +<<<<<<< HEAD #if !(PLATFORM(SKIA) && !PLATFORM(ANDROID)) +======= +void GraphicsContext::setCompositeOperation(CompositeOperator compositeOperation) +{ + m_state.compositeOperator = compositeOperation; + setPlatformCompositeOperation(compositeOperation); +} + +CompositeOperator GraphicsContext::compositeOperation() const +{ + return m_state.compositeOperator; +} + +#if !PLATFORM(SKIA) +>>>>>>> webkit.org at r74534 (trunk) void GraphicsContext::setPlatformFillGradient(Gradient*) { } @@ -572,7 +619,7 @@ void GraphicsContext::setPlatformStrokePattern(Pattern*) #if !PLATFORM(CG) && !(PLATFORM(SKIA) && !PLATFORM(ANDROID)) // Implement this if you want to go ahead and push the drawing mode into your native context // immediately. -void GraphicsContext::setPlatformTextDrawingMode(int mode) +void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode) { } #endif @@ -583,6 +630,12 @@ void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle&) } #endif +#if !PLATFORM(CG) +void GraphicsContext::setPlatformShouldSmoothFonts(bool) +{ +} +#endif + #if !PLATFORM(SKIA) void GraphicsContext::setSharedGraphicsContext3D(SharedGraphicsContext3D*, DrawingBuffer*, const IntSize&) { diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h index 0ea717b..22215a0 100644 --- a/WebCore/platform/graphics/GraphicsContext.h +++ b/WebCore/platform/graphics/GraphicsContext.h @@ -30,9 +30,11 @@ #include "ColorSpace.h" #include "DashArray.h" #include "FloatRect.h" +#include "Gradient.h" #include "Image.h" #include "IntRect.h" #include "Path.h" +#include "Pattern.h" #include "TextDirection.h" #include <wtf/Noncopyable.h> #include <wtf/PassOwnPtr.h> @@ -97,11 +99,6 @@ typedef struct HDC__ PlatformGraphicsContext; typedef void PlatformGraphicsContext; #endif -#if PLATFORM(GTK) -typedef struct _GdkDrawable GdkDrawable; -typedef struct _GdkEventExpose GdkEventExpose; -#endif - #if PLATFORM(WIN) typedef struct HDC__* HDC; #if !PLATFORM(CG) @@ -130,21 +127,19 @@ namespace WebCore { class DrawingBuffer; class Font; class Generator; - class Gradient; class GraphicsContextPlatformPrivate; - class GraphicsContextPrivate; class ImageBuffer; class KURL; - class Path; - class Pattern; class SharedGraphicsContext3D; class TextRun; - // These bits can be ORed together for a total of 8 possible text drawing modes. - const int cTextInvisible = 0; - const int cTextFill = 1; - const int cTextStroke = 2; - const int cTextClip = 4; + enum TextDrawingMode { + TextModeInvisible = 0, + TextModeFill = 1 << 0, + TextModeStroke = 1 << 1, + TextModeClip = 1 << 2 + }; + typedef unsigned TextDrawingModeFlags; enum StrokeStyle { NoStroke, @@ -161,6 +156,64 @@ namespace WebCore { InterpolationHigh }; + struct GraphicsContextState { + GraphicsContextState() + : strokeThickness(0) + , shadowBlur(0) +#if PLATFORM(CAIRO) + , globalAlpha(1) +#endif + , textDrawingMode(TextModeFill) + , strokeColor(Color::black) + , fillColor(Color::black) + , strokeStyle(SolidStroke) + , fillRule(RULE_NONZERO) + , strokeColorSpace(ColorSpaceDeviceRGB) + , fillColorSpace(ColorSpaceDeviceRGB) + , shadowColorSpace(ColorSpaceDeviceRGB) + , compositeOperator(CompositeSourceOver) + , shouldAntialias(true) + , shouldSmoothFonts(true) + , paintingDisabled(false) + , shadowsIgnoreTransforms(false) + { + } + + RefPtr<Gradient> strokeGradient; + RefPtr<Pattern> strokePattern; + + RefPtr<Gradient> fillGradient; + RefPtr<Pattern> fillPattern; + + FloatSize shadowOffset; + + float strokeThickness; + float shadowBlur; + +#if PLATFORM(CAIRO) + float globalAlpha; +#endif + TextDrawingModeFlags textDrawingMode; + + Color strokeColor; + Color fillColor; + Color shadowColor; + + StrokeStyle strokeStyle; + WindRule fillRule; + + ColorSpace strokeColorSpace; + ColorSpace fillColorSpace; + ColorSpace shadowColorSpace; + + CompositeOperator compositeOperator; + + bool shouldAntialias : 1; + bool shouldSmoothFonts : 1; + bool paintingDisabled : 1; + bool shadowsIgnoreTransforms : 1; + }; + class GraphicsContext : public Noncopyable { public: GraphicsContext(PlatformGraphicsContext*); @@ -202,9 +255,18 @@ namespace WebCore { void setShouldAntialias(bool); bool shouldAntialias() const; + void setShouldSmoothFonts(bool); + bool shouldSmoothFonts() const; + + const GraphicsContextState& state() const; + #if PLATFORM(CG) void applyStrokePattern(); void applyFillPattern(); + void drawPath(const Path&); + + // Allow font smoothing (LCD antialiasing). Not part of the graphics state. + void setAllowsFontSmoothing(bool); #endif #if PLATFORM(ANDROID) @@ -246,9 +308,8 @@ namespace WebCore { void drawEllipse(const IntRect&); void drawConvexPolygon(size_t numPoints, const FloatPoint*, bool shouldAntialias = false); - void drawPath(); - void fillPath(); - void strokePath(); + void fillPath(const Path&); + void strokePath(const Path&); // Arc drawing (used by border-radius in CSS) just supports stroking at the moment. void strokeArc(const IntRect&, int startAngle, int angleSpan); @@ -289,14 +350,15 @@ namespace WebCore { void addInnerRoundedRectClip(const IntRect&, int thickness); void clipOut(const IntRect&); void clipOutRoundedRect(const IntRect&, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight); - void clipPath(WindRule); + void clipPath(const Path&, WindRule); void clipConvexPolygon(size_t numPoints, const FloatPoint*, bool antialias = true); void clipToImageBuffer(ImageBuffer*, const FloatRect&); - int textDrawingMode(); - void setTextDrawingMode(int); + TextDrawingModeFlags textDrawingMode() const; + void setTextDrawingMode(TextDrawingModeFlags); void drawText(const Font&, const TextRun&, const IntPoint&, int from = 0, int to = -1); + void drawEmphasisMarks(const Font&, const TextRun& , const AtomicString& mark, const IntPoint&, int from = 0, int to = -1); void drawBidiText(const Font&, const TextRun&, const FloatPoint&); void drawHighlightForText(const Font&, const TextRun&, const IntPoint&, int h, const Color& backgroundColor, ColorSpace, int from = 0, int to = -1); @@ -320,7 +382,7 @@ namespace WebCore { void endTransparencyLayer(); void setShadow(const FloatSize&, float blur, const Color&, ColorSpace); - bool getShadow(FloatSize&, float&, Color&) const; + bool getShadow(FloatSize&, float&, Color&, ColorSpace&) const; void clearShadow(); void drawFocusRing(const Vector<IntRect>&, int width, int offset, const Color&); @@ -337,9 +399,12 @@ namespace WebCore { #endif void setCompositeOperation(CompositeOperator); + CompositeOperator compositeOperation() const; +#if PLATFORM(SKIA) void beginPath(); void addPath(const Path&); +#endif void clip(const Path&); @@ -429,7 +494,6 @@ namespace WebCore { #if PLATFORM(QT) bool inTransparencyLayer() const; - PlatformPath* currentPath(); void pushTransparencyLayerInternal(const QRect &rect, qreal opacity, QPixmap& alphaMask); void takeOwnershipOfPlatformContext(); static QPainter::CompositionMode toQtCompositionMode(CompositeOperator op); @@ -441,7 +505,7 @@ namespace WebCore { #if PLATFORM(GTK) void setGdkExposeEvent(GdkEventExpose*); - GdkDrawable* gdkDrawable() const; + GdkWindow* gdkWindow() const; GdkEventExpose* gdkExposeEvent() const; #endif @@ -454,10 +518,17 @@ namespace WebCore { void markDirtyRect(const IntRect&); // Hints that a portion of the backing store is dirty. private: + void platformInit(PlatformGraphicsContext*); + void platformDestroy(); + +#if PLATFORM(WIN) && !OS(WINCE) + void platformInit(HDC, bool hasAlpha = false); +#endif + void savePlatformState(); void restorePlatformState(); - void setPlatformTextDrawingMode(int); + void setPlatformTextDrawingMode(TextDrawingModeFlags); void setPlatformFont(const Font& font); void setPlatformStrokeColor(const Color&, ColorSpace); @@ -470,18 +541,21 @@ namespace WebCore { void setPlatformFillGradient(Gradient*); void setPlatformFillPattern(Pattern*); - void setPlatformShouldAntialias(bool b); + void setPlatformShouldAntialias(bool); + void setPlatformShouldSmoothFonts(bool); void setPlatformShadow(const FloatSize&, float blur, const Color&, ColorSpace); void clearPlatformShadow(); + void setPlatformCompositeOperation(CompositeOperator); + static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, const StrokeStyle&); - static GraphicsContextPrivate* createGraphicsContextPrivate(); - static void destroyGraphicsContextPrivate(GraphicsContextPrivate*); + GraphicsContextPlatformPrivate* m_data; - GraphicsContextPrivate* m_common; - GraphicsContextPlatformPrivate* m_data; // Deprecated; m_commmon can just be downcasted. To be removed. + GraphicsContextState m_state; + Vector<GraphicsContextState> m_stack; + bool m_updatingControlTints; }; } // namespace WebCore diff --git a/WebCore/platform/graphics/GraphicsContext3D.cpp b/WebCore/platform/graphics/GraphicsContext3D.cpp index d0ee639..7fae4a1 100644 --- a/WebCore/platform/graphics/GraphicsContext3D.cpp +++ b/WebCore/platform/graphics/GraphicsContext3D.cpp @@ -31,27 +31,108 @@ #include "GraphicsContext3D.h" #include "ArrayBufferView.h" +#include "CheckedInt.h" #include "DrawingBuffer.h" #include "Image.h" #include "ImageData.h" +#include <wtf/OwnArrayPtr.h> +#include <wtf/PassOwnArrayPtr.h> + namespace WebCore { -static uint8_t convertColor16LittleTo8(uint16_t value) -{ - return value >> 8; -} +namespace { + + unsigned bytesPerComponent(unsigned type) + { + switch (type) { + case GraphicsContext3D::UNSIGNED_BYTE: + return 1; + case GraphicsContext3D::UNSIGNED_SHORT_5_6_5: + case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4: + case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1: + return 2; + case GraphicsContext3D::FLOAT: + return 4; + default: + return 1; + } + } + + unsigned componentsPerPixel(unsigned format, unsigned type) + { + switch (type) { + case GraphicsContext3D::UNSIGNED_SHORT_5_6_5: + case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4: + case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1: + case GraphicsContext3D::FLOAT: + return 1; + default: + break; + } + switch (format) { + case GraphicsContext3D::ALPHA: + case GraphicsContext3D::LUMINANCE: + return 1; + case GraphicsContext3D::LUMINANCE_ALPHA: + return 2; + case GraphicsContext3D::RGB: + return 3; + case GraphicsContext3D::RGBA: + return 4; + default: + return 4; + } + } + + // This function should only be called if width and height is non-zero and + // format/type are valid. Return 0 if overflow happens. + size_t imageSizeInBytes(unsigned width, unsigned height, unsigned format, unsigned type) + { + ASSERT(width && height); + CheckedInt<uint32_t> checkedWidth(width); + CheckedInt<uint32_t> checkedHeight(height); + CheckedInt<uint32_t> checkedBytesPerPixel(bytesPerComponent(type) * componentsPerPixel(format, type)); + CheckedInt<uint32_t> checkedSize = checkedWidth * checkedHeight * checkedBytesPerPixel; + if (checkedSize.valid()) + return checkedSize.value(); + return 0; + } + + uint8_t convertColor16LittleTo8(uint16_t value) + { + return value >> 8; + } + + uint8_t convertColor16BigTo8(uint16_t value) + { + return static_cast<uint8_t>(value & 0x00FF); + } + +} // anonymous namespace -static uint8_t convertColor16BigTo8(uint16_t value) -{ - return static_cast<uint8_t>(value & 0x00FF); -} PassRefPtr<DrawingBuffer> GraphicsContext3D::createDrawingBuffer(const IntSize& size) { return DrawingBuffer::create(this, size); } +bool GraphicsContext3D::texImage2DResourceSafe(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type) +{ + OwnArrayPtr<unsigned char> zero; + if (width && height) { + size_t size = imageSizeInBytes(width, height, format, type); + if (!size) { + synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return false; + } + zero = adoptArrayPtr(new unsigned char[size]); + memset(zero.get(), 0, size); + } + texImage2D(target, level, internalformat, width, height, border, format, type, zero.get()); + return true; +} + bool GraphicsContext3D::computeFormatAndTypeParameters(unsigned int format, unsigned int type, unsigned long* componentsPerPixel, @@ -86,6 +167,9 @@ bool GraphicsContext3D::computeFormatAndTypeParameters(unsigned int format, *componentsPerPixel = 1; *bytesPerComponent = sizeof(unsigned short); break; + case GraphicsContext3D::FLOAT: // OES_texture_float + *bytesPerComponent = sizeof(float); + break; default: return false; } @@ -188,6 +272,27 @@ bool GraphicsContext3D::extractTextureData(unsigned int width, unsigned int heig ASSERT_NOT_REACHED(); } break; + case FLOAT: // OES_texture_float + switch (format) { + case RGBA: + sourceDataFormat = SourceFormatRGBA32F; + break; + case RGB: + sourceDataFormat = SourceFormatRGB32F; + break; + case ALPHA: + sourceDataFormat = SourceFormatA32F; + break; + case LUMINANCE: + sourceDataFormat = SourceFormatR32F; + break; + case LUMINANCE_ALPHA: + sourceDataFormat = SourceFormatRA32F; + break; + default: + ASSERT_NOT_REACHED(); + } + break; case UNSIGNED_SHORT_5_5_5_1: sourceDataFormat = SourceFormatRGBA5551; break; @@ -501,6 +606,38 @@ void unpackA16BigToRGBA8(const uint16_t* source, uint8_t* destination) destination[3] = convertColor16BigTo8(source[0]); } +void unpackRGB32FToRGBA32F(const float* source, float* destination) +{ + destination[0] = source[0]; + destination[1] = source[1]; + destination[2] = source[2]; + destination[3] = 1; +} + +void unpackR32FToRGBA32F(const float* source, float* destination) +{ + destination[0] = source[0]; + destination[1] = source[0]; + destination[2] = source[0]; + destination[3] = 1; +} + +void unpackRA32FToRGBA32F(const float* source, float* destination) +{ + destination[0] = source[0]; + destination[1] = source[0]; + destination[2] = source[0]; + destination[3] = source[1]; +} + +void unpackA32FToRGBA32F(const float* source, float* destination) +{ + destination[0] = 0; + destination[1] = 0; + destination[2] = 0; + destination[3] = source[0]; +} + //---------------------------------------------------------------------- // Pixel packing routines. // @@ -713,14 +850,68 @@ void packRGBA8ToUnsignedShort565Unmultiply(const uint8_t* source, uint16_t* dest | ((sourceB & 0xF8) >> 3)); } +void packRGBA32FToRGB32F(const float* source, float* destination) +{ + destination[0] = source[0]; + destination[1] = source[1]; + destination[2] = source[2]; +} + +void packRGBA32FToRGB32FPremultiply(const float* source, float* destination) +{ + float scaleFactor = source[3]; + destination[0] = source[0] * scaleFactor; + destination[1] = source[1] * scaleFactor; + destination[2] = source[2] * scaleFactor; +} + +void packRGBA32FToRGBA32FPremultiply(const float* source, float* destination) +{ + float scaleFactor = source[3]; + destination[0] = source[0] * scaleFactor; + destination[1] = source[1] * scaleFactor; + destination[2] = source[2] * scaleFactor; + destination[3] = source[3]; +} + +void packRGBA32FToA32F(const float* source, float* destination) +{ + destination[0] = source[3]; +} + +void packRGBA32FToR32F(const float* source, float* destination) +{ + destination[0] = source[0]; +} + +void packRGBA32FToR32FPremultiply(const float* source, float* destination) +{ + float scaleFactor = source[3]; + destination[0] = source[0] * scaleFactor; +} + + +void packRGBA32FToRA32F(const float* source, float* destination) +{ + destination[0] = source[0]; + destination[1] = source[3]; +} + +void packRGBA32FToRA32FPremultiply(const float* source, float* destination) +{ + float scaleFactor = source[3]; + destination[0] = source[0] * scaleFactor; + destination[1] = scaleFactor; +} + } // anonymous namespace // This is used whenever unpacking is necessary; i.e., the source data -// is not in RGBA8 format, or the unpack alignment specifies that rows -// are not tightly packed. -template<typename SourceType, typename DestType, - void unpackingFunc(const SourceType*, uint8_t*), - void packingFunc(const uint8_t*, DestType*)> +// is not in RGBA8/RGBA32F format, or the unpack alignment specifies +// that rows are not tightly packed. +template<typename SourceType, typename IntermediateType, typename DestType, + void unpackingFunc(const SourceType*, IntermediateType*), + void packingFunc(const IntermediateType*, DestType*)> static void doUnpackingAndPacking(const SourceType* sourceData, unsigned int width, unsigned int height, @@ -732,7 +923,7 @@ static void doUnpackingAndPacking(const SourceType* sourceData, if (!sourceElementsPerRow) { unsigned int numElements = width * height * sourceElementsPerPixel; const SourceType* endPointer = sourceData + numElements; - uint8_t temporaryRGBAData[4]; + IntermediateType temporaryRGBAData[4]; while (sourceData < endPointer) { unpackingFunc(sourceData, temporaryRGBAData); packingFunc(temporaryRGBAData, destinationData); @@ -740,7 +931,7 @@ static void doUnpackingAndPacking(const SourceType* sourceData, destinationData += destinationElementsPerPixel; } } else { - uint8_t temporaryRGBAData[4]; + IntermediateType temporaryRGBAData[4]; for (unsigned int y = 0; y < height; ++y) { const SourceType* currentSource = sourceData; for (unsigned int x = 0; x < width; ++x) { @@ -802,176 +993,176 @@ static void doPacking(const void* sourceData, destinationData += destinationElementsPerPixel; } } else { - doUnpackingAndPacking<uint8_t, DestType, unpackRGBA8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackRGBA8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); } break; } case GraphicsContext3D::SourceFormatRGBA16Little: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint16_t, DestType, unpackRGBA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRGBA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatRGBA16Big: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint16_t, DestType, unpackRGBA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRGBA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatRGB8: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint8_t>(width, 3, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint8_t, DestType, unpackRGB8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackRGB8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatRGB16Little: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint16_t>(width, 6, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint16_t, DestType, unpackRGB16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRGB16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatRGB16Big: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint16_t>(width, 6, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint16_t, DestType, unpackRGB16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRGB16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatBGR8: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint8_t>(width, 3, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint8_t, DestType, unpackBGR8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackBGR8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatARGB8: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint8_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint8_t, DestType, unpackARGB8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackARGB8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatARGB16Little: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint16_t, DestType, unpackARGB16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackARGB16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatARGB16Big: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint16_t, DestType, unpackARGB16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackARGB16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatABGR8: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint8_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint8_t, DestType, unpackABGR8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackABGR8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatBGRA8: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint8_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint8_t, DestType, unpackBGRA8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackBGRA8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatBGRA16Little: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint16_t, DestType, unpackBGRA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackBGRA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatBGRA16Big: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint16_t, DestType, unpackBGRA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackBGRA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatRGBA5551: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint16_t, DestType, unpackRGBA5551ToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRGBA5551ToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatRGBA4444: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint16_t, DestType, unpackRGBA4444ToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRGBA4444ToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatRGB565: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint16_t, DestType, unpackRGB565ToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRGB565ToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatR8: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint8_t>(width, 1, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint8_t, DestType, unpackR8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackR8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatR16Little: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint16_t, DestType, unpackR16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackR16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatR16Big: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint16_t, DestType, unpackR16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackR16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatRA8: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint8_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint8_t, DestType, unpackRA8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackRA8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatRA16Little: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint16_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint16_t, DestType, unpackRA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatRA16Big: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint16_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint16_t, DestType, unpackRA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatAR8: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint8_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint8_t, DestType, unpackAR8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackAR8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatAR16Little: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint16_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint16_t, DestType, unpackAR16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackAR16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatAR16Big: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint16_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint16_t, DestType, unpackAR16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackAR16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatA8: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint8_t>(width, 1, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint8_t, DestType, unpackA8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackA8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatA16Little: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint16_t, DestType, unpackA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } case GraphicsContext3D::SourceFormatA16Big: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); - doUnpackingAndPacking<uint16_t, DestType, unpackA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } default: @@ -979,6 +1170,63 @@ static void doPacking(const void* sourceData, } } +// This specialized routine is used only for floating-point texture uploads. It +// does not need to be as general as doPacking, above; because there are +// currently no native floating-point image formats in WebKit, there are only a +// few upload paths. +template<void packingFunc(const float*, float*)> +static void doFloatingPointPacking(const void* sourceData, + GraphicsContext3D::SourceDataFormat sourceDataFormat, + unsigned int width, + unsigned int height, + unsigned int sourceUnpackAlignment, + float* destinationData, + unsigned int destinationElementsPerPixel) +{ + switch (sourceDataFormat) { + case GraphicsContext3D::SourceFormatRGBA8: { + unsigned int sourceElementsPerPixel, sourceElementsPerRow; + computeIncrementParameters<float>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); + ASSERT(!sourceElementsPerRow); // Guaranteed because each color channel is sizeof(float) bytes. + const float* source = static_cast<const float*>(sourceData); + unsigned int numElements = width * height * 4; + const float* endPointer = source + numElements; + while (source < endPointer) { + packingFunc(source, destinationData); + source += sourceElementsPerPixel; + destinationData += destinationElementsPerPixel; + } + break; + } + case GraphicsContext3D::SourceFormatRGB32F: { + unsigned int sourceElementsPerPixel, sourceElementsPerRow; + computeIncrementParameters<float>(width, 3, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); + doUnpackingAndPacking<float, float, float, unpackRGB32FToRGBA32F, packingFunc>(static_cast<const float*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + break; + } + case GraphicsContext3D::SourceFormatR32F: { + unsigned int sourceElementsPerPixel, sourceElementsPerRow; + computeIncrementParameters<float>(width, 1, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); + doUnpackingAndPacking<float, float, float, unpackR32FToRGBA32F, packingFunc>(static_cast<const float*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + break; + } + case GraphicsContext3D::SourceFormatRA32F: { + unsigned int sourceElementsPerPixel, sourceElementsPerRow; + computeIncrementParameters<float>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); + doUnpackingAndPacking<float, float, float, unpackRA32FToRGBA32F, packingFunc>(static_cast<const float*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + break; + } + case GraphicsContext3D::SourceFormatA32F: { + unsigned int sourceElementsPerPixel, sourceElementsPerRow; + computeIncrementParameters<float>(width, 1, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); + doUnpackingAndPacking<float, float, float, unpackA32FToRGBA32F, packingFunc>(static_cast<const float*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + break; + } + default: + ASSERT_NOT_REACHED(); + } +} + bool GraphicsContext3D::packPixels(const uint8_t* sourceData, GraphicsContext3D::SourceDataFormat sourceDataFormat, unsigned int width, @@ -1113,6 +1361,87 @@ bool GraphicsContext3D::packPixels(const uint8_t* sourceData, } break; } + case FLOAT: { + // OpenGL ES, and therefore WebGL, require that the format and + // internalformat be identical, which implies that the source and + // destination formats will both be floating-point in this branch -- at + // least, until WebKit supports floating-point image formats natively. + ASSERT(sourceDataFormat == SourceFormatRGBA32F || sourceDataFormat == SourceFormatRGB32F + || sourceDataFormat == SourceFormatRA32F || sourceDataFormat == SourceFormatR32F + || sourceDataFormat == SourceFormatA32F); + // Because WebKit doesn't use floating-point color channels for anything + // internally, there's no chance we have to do a (lossy) unmultiply + // operation. + ASSERT(alphaOp == AlphaDoNothing || alphaOp == AlphaDoPremultiply); + // For the source formats with an even number of channels (RGBA32F, + // RA32F) it is guaranteed that the pixel data is tightly packed because + // unpack alignment <= sizeof(float) * number of channels. + float* destination = static_cast<float*>(destinationData); + if (alphaOp == AlphaDoNothing + && ((sourceDataFormat == SourceFormatRGBA32F && destinationFormat == RGBA) + || (sourceDataFormat == SourceFormatRA32F && destinationFormat == LUMINANCE_ALPHA))) { + // No conversion necessary. + int numChannels = (sourceDataFormat == SourceFormatRGBA32F ? 4 : 2); + memcpy(destinationData, sourceData, width * height * numChannels * sizeof(float)); + break; + } + switch (destinationFormat) { + case RGB: + switch (alphaOp) { + case AlphaDoNothing: + doFloatingPointPacking<packRGBA32FToRGB32F>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 3); + break; + case AlphaDoPremultiply: + doFloatingPointPacking<packRGBA32FToRGB32FPremultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 3); + break; + default: + ASSERT_NOT_REACHED(); + } + break; + case RGBA: + // AlphaDoNothing is handled above with fast path. + ASSERT(alphaOp == AlphaDoPremultiply); + doFloatingPointPacking<packRGBA32FToRGBA32FPremultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 4); + break; + case ALPHA: + // From the desktop OpenGL conversion rules (OpenGL 2.1 + // specification, Table 3.15), the alpha channel is chosen + // from the RGBA data. + doFloatingPointPacking<packRGBA32FToA32F>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1); + break; + case LUMINANCE: + // From the desktop OpenGL conversion rules (OpenGL 2.1 + // specification, Table 3.15), the red channel is chosen + // from the RGBA data. + switch (alphaOp) { + case AlphaDoNothing: + doFloatingPointPacking<packRGBA32FToR32F>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1); + break; + case AlphaDoPremultiply: + doFloatingPointPacking<packRGBA32FToR32FPremultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1); + break; + default: + ASSERT_NOT_REACHED(); + } + break; + case LUMINANCE_ALPHA: + // From the desktop OpenGL conversion rules (OpenGL 2.1 + // specification, Table 3.15), the red and alpha channels + // are chosen from the RGBA data. + switch (alphaOp) { + case AlphaDoNothing: + doFloatingPointPacking<packRGBA32FToRA32F>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 2); + break; + case AlphaDoPremultiply: + doFloatingPointPacking<packRGBA32FToRA32FPremultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 2); + break; + default: + ASSERT_NOT_REACHED(); + } + break; + } + break; + } } return true; } diff --git a/WebCore/platform/graphics/GraphicsContext3D.h b/WebCore/platform/graphics/GraphicsContext3D.h index c2d5c24..f9540be 100644 --- a/WebCore/platform/graphics/GraphicsContext3D.h +++ b/WebCore/platform/graphics/GraphicsContext3D.h @@ -472,6 +472,10 @@ public: // like GL_FLOAT, GL_INT, etc. int sizeInBytes(int type); + // Helper to texImage2D with pixel==0 case: pixels are initialized to 0. + // Return true if no GL error is synthesized. + bool texImage2DResourceSafe(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type); + bool isGLES2Compliant() const; //---------------------------------------------------------------------- @@ -536,9 +540,11 @@ public: SourceFormatRGBA8 = 0, SourceFormatRGBA16Little, SourceFormatRGBA16Big, + SourceFormatRGBA32F, SourceFormatRGB8, SourceFormatRGB16Little, SourceFormatRGB16Big, + SourceFormatRGB32F, SourceFormatBGR8, SourceFormatBGRA8, SourceFormatBGRA16Little, @@ -553,15 +559,18 @@ public: SourceFormatR8, SourceFormatR16Little, SourceFormatR16Big, + SourceFormatR32F, SourceFormatRA8, SourceFormatRA16Little, SourceFormatRA16Big, + SourceFormatRA32F, SourceFormatAR8, SourceFormatAR16Little, SourceFormatAR16Big, SourceFormatA8, SourceFormatA16Little, SourceFormatA16Big, + SourceFormatA32F, SourceFormatNumFormats }; diff --git a/WebCore/platform/graphics/GraphicsContextPrivate.h b/WebCore/platform/graphics/GraphicsContextPrivate.h deleted file mode 100644 index 985cad9..0000000 --- a/WebCore/platform/graphics/GraphicsContextPrivate.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * 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 GraphicsContextPrivate_h -#define GraphicsContextPrivate_h - -#include "Gradient.h" -#include "GraphicsContext.h" -#include "Pattern.h" -#include "TransformationMatrix.h" - -namespace WebCore { - - struct GraphicsContextState { - GraphicsContextState() - : textDrawingMode(cTextFill) - , strokeStyle(SolidStroke) - , strokeThickness(0) - , strokeColor(Color::black) - , strokeColorSpace(ColorSpaceDeviceRGB) - , fillRule(RULE_NONZERO) - , fillColor(Color::black) - , fillColorSpace(ColorSpaceDeviceRGB) - , shouldAntialias(true) - , paintingDisabled(false) - , shadowBlur(0) - , shadowsIgnoreTransforms(false) -#if PLATFORM(CAIRO) - , globalAlpha(1) -#endif - { - } - - int textDrawingMode; - - StrokeStyle strokeStyle; - float strokeThickness; - Color strokeColor; - ColorSpace strokeColorSpace; - RefPtr<Gradient> strokeGradient; - RefPtr<Pattern> strokePattern; - - WindRule fillRule; - Color fillColor; - ColorSpace fillColorSpace; - RefPtr<Gradient> fillGradient; - RefPtr<Pattern> fillPattern; - - bool shouldAntialias; - - bool paintingDisabled; - - FloatSize shadowOffset; - float shadowBlur; - Color shadowColor; - - bool shadowsIgnoreTransforms; -#if PLATFORM(CAIRO) - float globalAlpha; -#elif PLATFORM(QT) - TransformationMatrix pathTransform; -#endif - }; - - class GraphicsContextPrivate : public Noncopyable { - public: - GraphicsContextPrivate() - : m_updatingControlTints(false) - { - } - - GraphicsContextState state; - Vector<GraphicsContextState> stack; - bool m_updatingControlTints; - }; - -} // namespace WebCore - -#endif // GraphicsContextPrivate_h diff --git a/WebCore/platform/graphics/GraphicsLayer.cpp b/WebCore/platform/graphics/GraphicsLayer.cpp index 08b79ab..84905a9 100644 --- a/WebCore/platform/graphics/GraphicsLayer.cpp +++ b/WebCore/platform/graphics/GraphicsLayer.cpp @@ -73,6 +73,7 @@ GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client) , m_usingTiledLayer(false) , m_masksToBounds(false) , m_drawsContent(false) + , m_acceleratesDrawing(false) , m_paintingPhase(GraphicsLayerPaintAll) , m_contentsOrientation(CompositingCoordinatesTopDown) , m_parent(0) diff --git a/WebCore/platform/graphics/GraphicsLayer.h b/WebCore/platform/graphics/GraphicsLayer.h index 81aa6d0..f31c8f9 100644 --- a/WebCore/platform/graphics/GraphicsLayer.h +++ b/WebCore/platform/graphics/GraphicsLayer.h @@ -49,23 +49,19 @@ @class WebLayer; @class CALayer; typedef CALayer PlatformLayer; -typedef CALayer* NativeLayer; #else typedef void* PlatformLayer; -typedef void* NativeLayer; #endif #elif PLATFORM(WIN) namespace WebCore { class WKCACFLayer; typedef WKCACFLayer PlatformLayer; -typedef void* NativeLayer; } #elif PLATFORM(QT) #if USE(TEXTURE_MAPPER) namespace WebCore { class TextureMapperPlatformLayer; typedef TextureMapperPlatformLayer PlatformLayer; -typedef TextureMapperPlatformLayer* NativeLayer; }; #else QT_BEGIN_NAMESPACE @@ -73,14 +69,12 @@ class QGraphicsObject; QT_END_NAMESPACE namespace WebCore { typedef QGraphicsObject PlatformLayer; -typedef QGraphicsObject* NativeLayer; } #endif #elif PLATFORM(CHROMIUM) namespace WebCore { class LayerChromium; typedef LayerChromium PlatformLayer; -typedef void* NativeLayer; } #elif PLATFORM(ANDROID) namespace WebCore { @@ -90,7 +84,6 @@ typedef void* NativeLayer; } #else typedef void* PlatformLayer; -typedef void* NativeLayer; #endif enum LayerTreeAsTextBehaviorFlags { @@ -206,9 +199,6 @@ public: const String& name() const { return m_name; } virtual void setName(const String& name) { m_name = name; } - // For hosting this GraphicsLayer in a native layer hierarchy. - virtual NativeLayer nativeLayer() const { return 0; } - GraphicsLayer* parent() const { return m_parent; }; void setParent(GraphicsLayer* layer) { m_parent = layer; } // Internal use only. @@ -274,6 +264,9 @@ public: bool drawsContent() const { return m_drawsContent; } virtual void setDrawsContent(bool b) { m_drawsContent = b; } + bool acceleratesDrawing() const { return m_acceleratesDrawing; } + virtual void setAcceleratesDrawing(bool b) { m_acceleratesDrawing = b; } + // The color used to paint the layer backgrounds const Color& backgroundColor() const { return m_backgroundColor; } virtual void setBackgroundColor(const Color&); @@ -329,6 +322,7 @@ public: // Callback from the underlying graphics system when the layer has been displayed virtual void didDisplay(PlatformLayer*) { } + // For hosting this GraphicsLayer in a native layer hierarchy. virtual PlatformLayer* platformLayer() const { return 0; } void dumpLayer(TextStream&, int indent = 0, LayerTreeAsTextBehavior = LayerTreeAsTextBehaviorNormal) const; @@ -409,6 +403,7 @@ protected: bool m_usingTiledLayer : 1; bool m_masksToBounds : 1; bool m_drawsContent : 1; + bool m_acceleratesDrawing : 1; GraphicsLayerPaintingPhase m_paintingPhase; CompositingCoordinatesOrientation m_contentsOrientation; // affects orientation of layer contents diff --git a/WebCore/platform/graphics/Image.cpp b/WebCore/platform/graphics/Image.cpp index 6f2311c..3096680 100644 --- a/WebCore/platform/graphics/Image.cpp +++ b/WebCore/platform/graphics/Image.cpp @@ -81,10 +81,10 @@ void Image::fillWithSolidColor(GraphicsContext* ctxt, const FloatRect& dstRect, if (color.alpha() <= 0) return; - ctxt->save(); + CompositeOperator previousOperator = ctxt->compositeOperation(); ctxt->setCompositeOperation(!color.hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op); ctxt->fillRect(dstRect, color, styleColorSpace); - ctxt->restore(); + ctxt->setCompositeOperation(previousOperator); } static inline FloatSize calculatePatternScale(const FloatRect& dstRect, const FloatRect& srcRect, Image::TileRule hRule, Image::TileRule vRule) diff --git a/WebCore/platform/graphics/ImageBuffer.h b/WebCore/platform/graphics/ImageBuffer.h index 822a0ff..8f9abf3 100644 --- a/WebCore/platform/graphics/ImageBuffer.h +++ b/WebCore/platform/graphics/ImageBuffer.h @@ -39,6 +39,10 @@ #include <wtf/PassOwnPtr.h> #include <wtf/PassRefPtr.h> +#if (PLATFORM(MAC) && PLATFORM(CA) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)) +#define USE_IOSURFACE 1 +#endif + namespace WebCore { class GraphicsContext; @@ -51,13 +55,18 @@ namespace WebCore { Unmultiplied }; + enum RenderingMode { + Unaccelerated, + Accelerated + }; + class ImageBuffer : public Noncopyable { public: // Will return a null pointer on allocation failure. - static PassOwnPtr<ImageBuffer> create(const IntSize& size, ColorSpace colorSpace = ColorSpaceDeviceRGB) + static PassOwnPtr<ImageBuffer> create(const IntSize& size, ColorSpace colorSpace = ColorSpaceDeviceRGB, RenderingMode renderingMode = Unaccelerated) { bool success = false; - OwnPtr<ImageBuffer> buf(new ImageBuffer(size, colorSpace, success)); + OwnPtr<ImageBuffer> buf(new ImageBuffer(size, colorSpace, renderingMode, success)); if (success) return buf.release(); return 0; @@ -104,6 +113,7 @@ namespace WebCore { ImageBufferData m_data; IntSize m_size; + bool m_accelerateRendering; OwnPtr<GraphicsContext> m_context; #if !PLATFORM(CG) @@ -113,7 +123,7 @@ namespace WebCore { // This constructor will place its success into the given out-variable // so that create() knows when it should return failure. - ImageBuffer(const IntSize&, ColorSpace colorSpace, bool& success); + ImageBuffer(const IntSize&, ColorSpace colorSpace, RenderingMode renderingMode, bool& success); }; } // namespace WebCore diff --git a/WebCore/platform/graphics/ImageSource.cpp b/WebCore/platform/graphics/ImageSource.cpp index d1a944a..92553c5 100644 --- a/WebCore/platform/graphics/ImageSource.cpp +++ b/WebCore/platform/graphics/ImageSource.cpp @@ -41,10 +41,10 @@ namespace WebCore { unsigned ImageSource::s_maxPixelsPerDecodedImage = 1024 * 1024; #endif -ImageSource::ImageSource(bool premultiplyAlpha, bool ignoreGammaAndColorProfile) +ImageSource::ImageSource(ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption) : m_decoder(0) - , m_premultiplyAlpha(premultiplyAlpha) - , m_ignoreGammaAndColorProfile(ignoreGammaAndColorProfile) + , m_alphaOption(alphaOption) + , m_gammaAndColorProfileOption(gammaAndColorProfileOption) { } @@ -79,7 +79,7 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived) // If insufficient bytes are available to determine the image type, no decoder plugin will be // made. if (!m_decoder) { - m_decoder = static_cast<NativeImageSourcePtr>(ImageDecoder::create(*data, m_premultiplyAlpha, m_ignoreGammaAndColorProfile)); + m_decoder = static_cast<NativeImageSourcePtr>(ImageDecoder::create(*data, m_alphaOption, m_gammaAndColorProfileOption)); #if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) if (m_decoder && s_maxPixelsPerDecodedImage) m_decoder->setMaxNumPixels(s_maxPixelsPerDecodedImage); @@ -153,13 +153,14 @@ float ImageSource::frameDurationAtIndex(size_t index) if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) return 0; - // Many annoying ads specify a 0 duration to make an image flash as quickly - // as possible. We follow WinIE's behavior and use a duration of 100 ms - // for any frames that specify a duration of <= 50 ms. See - // <http://bugs.webkit.org/show_bug.cgi?id=14413> or Radar 4051389 for - // more. + // Many annoying ads specify a 0 duration to make an image flash as quickly as possible. + // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify + // a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082> + // for more information. const float duration = buffer->duration() / 1000.0f; - return (duration < 0.051f) ? 0.100f : duration; + if (duration < 0.011f) + return 0.100f; + return duration; } bool ImageSource::frameHasAlphaAtIndex(size_t index) diff --git a/WebCore/platform/graphics/ImageSource.h b/WebCore/platform/graphics/ImageSource.h index 3d96698..29c1be3 100644 --- a/WebCore/platform/graphics/ImageSource.h +++ b/WebCore/platform/graphics/ImageSource.h @@ -138,7 +138,17 @@ const int cAnimationNone = -2; class ImageSource : public Noncopyable { public: - ImageSource(bool premultiplyAlpha = true, bool ignoreGammaAndColorProfile = false); + enum AlphaOption { + AlphaPremultiplied, + AlphaNotPremultiplied + }; + + enum GammaAndColorProfileOption { + GammaAndColorProfileApplied, + GammaAndColorProfileIgnored + }; + + ImageSource(AlphaOption alphaOption = AlphaPremultiplied, GammaAndColorProfileOption gammaAndColorProfileOption = GammaAndColorProfileApplied); ~ImageSource(); // Tells the ImageSource that the Image no longer cares about decoded frame @@ -206,8 +216,8 @@ private: protected: #endif NativeImageSourcePtr m_decoder; - bool m_premultiplyAlpha; - bool m_ignoreGammaAndColorProfile; + AlphaOption m_alphaOption; + GammaAndColorProfileOption m_gammaAndColorProfileOption; #if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) static unsigned s_maxPixelsPerDecodedImage; #endif diff --git a/WebCore/platform/graphics/IntRect.h b/WebCore/platform/graphics/IntRect.h index e43e290..638db75 100644 --- a/WebCore/platform/graphics/IntRect.h +++ b/WebCore/platform/graphics/IntRect.h @@ -117,6 +117,29 @@ public: void move(const IntSize& s) { m_location += s; } void move(int dx, int dy) { m_location.move(dx, dy); } + + void shiftLeftEdgeTo(int edge) + { + int delta = edge - x(); + setX(edge); + setWidth(std::max(0, width() - delta)); + } + void shiftRightEdgeTo(int edge) + { + int delta = edge - right(); + setWidth(std::max(0, width() + delta)); + } + void shiftTopEdgeTo(int edge) + { + int delta = edge - y(); + setY(edge); + setHeight(std::max(0, height() - delta)); + } + void shiftBottomEdgeTo(int edge) + { + int delta = edge - bottom(); + setHeight(std::max(0, height() + delta)); + } bool intersects(const IntRect&) const; bool contains(const IntRect&) const; diff --git a/WebCore/platform/graphics/MediaPlayer.cpp b/WebCore/platform/graphics/MediaPlayer.cpp index dc743bf..4a39e9e 100644 --- a/WebCore/platform/graphics/MediaPlayer.cpp +++ b/WebCore/platform/graphics/MediaPlayer.cpp @@ -164,7 +164,8 @@ struct MediaPlayerFactory : Noncopyable { }; static void addMediaEngine(CreateMediaEnginePlayer, MediaEngineSupportedTypes, MediaEngineSupportsType); -static MediaPlayerFactory* chooseBestEngineForTypeAndCodecs(const String& type, const String& codecs); +static MediaPlayerFactory* bestMediaEngineForTypeAndCodecs(const String& type, const String& codecs, MediaPlayerFactory* current = 0); +static MediaPlayerFactory* nextMediaEngine(MediaPlayerFactory* current); static Vector<MediaPlayerFactory*>& installedMediaEngines() { @@ -212,10 +213,12 @@ static const AtomicString& codecs() return codecs; } -static MediaPlayerFactory* chooseBestEngineForTypeAndCodecs(const String& type, const String& codecs) +static MediaPlayerFactory* bestMediaEngineForTypeAndCodecs(const String& type, const String& codecs, MediaPlayerFactory* current) { - Vector<MediaPlayerFactory*>& engines = installedMediaEngines(); + if (type.isEmpty()) + return 0; + Vector<MediaPlayerFactory*>& engines = installedMediaEngines(); if (engines.isEmpty()) return 0; @@ -229,9 +232,13 @@ static MediaPlayerFactory* chooseBestEngineForTypeAndCodecs(const String& type, MediaPlayerFactory* engine = 0; MediaPlayer::SupportsType supported = MediaPlayer::IsNotSupported; - unsigned count = engines.size(); for (unsigned ndx = 0; ndx < count; ndx++) { + if (current) { + if (current == engines[ndx]) + current = 0; + continue; + } MediaPlayer::SupportsType engineSupport = engines[ndx]->supportsTypeAndCodecs(type, codecs); if (engineSupport > supported) { supported = engineSupport; @@ -242,10 +249,27 @@ static MediaPlayerFactory* chooseBestEngineForTypeAndCodecs(const String& type, return engine; } +static MediaPlayerFactory* nextMediaEngine(MediaPlayerFactory* current) +{ + Vector<MediaPlayerFactory*>& engines = installedMediaEngines(); + if (engines.isEmpty()) + return 0; + + if (!current) + return engines.first(); + + size_t currentIndex = engines.find(current); + if (currentIndex == WTF::notFound || currentIndex == engines.size()) + return 0; + + return engines[currentIndex + 1]; +} + // media player MediaPlayer::MediaPlayer(MediaPlayerClient* client) : m_mediaPlayerClient(client) + , m_reloadTimer(this, &MediaPlayer::reloadTimerFired) , m_private(createNullMediaPlayer(this)) , m_currentMediaEngine(0) , m_frameView(0) @@ -268,12 +292,15 @@ MediaPlayer::MediaPlayer(MediaPlayerClient* client) m_currentMediaEngine = engines[0]; m_private.clear(); m_private.set(engines[0]->constructor(this)); + if (m_mediaPlayerClient) + m_mediaPlayerClient->mediaPlayerEngineUpdated(this); } #endif } MediaPlayer::~MediaPlayer() { + m_mediaPlayerClient = 0; } void MediaPlayer::load(const String& url, const ContentType& contentType) @@ -281,26 +308,38 @@ void MediaPlayer::load(const String& url, const ContentType& contentType) String type = contentType.type().lower(); String typeCodecs = contentType.parameter(codecs()); - // If the MIME type is unhelpful, see if the type registry has a match for the file extension. + // If the MIME type is missing or is not meaningful, try to figure it out from the URL. if (type.isEmpty() || type == applicationOctetStream() || type == textPlain()) { - size_t pos = url.reverseFind('.'); - if (pos != notFound) { - String extension = url.substring(pos + 1); - String mediaType = MIMETypeRegistry::getMediaMIMETypeForExtension(extension); - if (!mediaType.isEmpty()) - type = mediaType; + if (protocolIs(url, "data")) + type = mimeTypeFromDataURL(url); + else { + size_t pos = url.reverseFind('.'); + if (pos != notFound) { + String extension = url.substring(pos + 1); + String mediaType = MIMETypeRegistry::getMediaMIMETypeForExtension(extension); + if (!mediaType.isEmpty()) + type = mediaType; + } } } - MediaPlayerFactory* engine = 0; - if (!type.isEmpty()) - engine = chooseBestEngineForTypeAndCodecs(type, typeCodecs); + m_url = url; + m_contentMIMEType = type; + m_contentTypeCodecs = typeCodecs; + loadWithNextMediaEngine(0); +} - // If we didn't find an engine and no MIME type is specified, just use the first engine. - if (!engine && type.isEmpty() && !installedMediaEngines().isEmpty()) - engine = installedMediaEngines()[0]; +void MediaPlayer::loadWithNextMediaEngine(MediaPlayerFactory* current) +{ + MediaPlayerFactory* engine; + + // If no MIME type is specified, just use the next engine. + if (m_contentMIMEType.isEmpty()) + 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 + // Don't delete and recreate the player unless it comes from a different engine. if (!engine) { m_currentMediaEngine = engine; m_private.clear(); @@ -308,6 +347,8 @@ void MediaPlayer::load(const String& url, const ContentType& contentType) m_currentMediaEngine = engine; m_private.clear(); m_private.set(engine->constructor(this)); + if (m_mediaPlayerClient) + m_mediaPlayerClient->mediaPlayerEngineUpdated(this); #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) m_private->setMediaPlayerProxy(m_playerProxy); #endif @@ -316,9 +357,12 @@ void MediaPlayer::load(const String& url, const ContentType& contentType) } if (m_private) - m_private->load(url); - else + m_private->load(m_url); + else { m_private.set(createNullMediaPlayer(this)); + if (m_mediaPlayerClient) + m_mediaPlayerClient->mediaPlayerEngineUpdated(this); + } } bool MediaPlayer::hasAvailableVideoFrame() const @@ -559,7 +603,7 @@ void MediaPlayer::paintCurrentFrameInContext(GraphicsContext* p, const IntRect& m_private->paintCurrentFrameInContext(p, r); } -MediaPlayer::SupportsType MediaPlayer::supportsType(ContentType contentType) +MediaPlayer::SupportsType MediaPlayer::supportsType(const ContentType& contentType) { String type = contentType.type().lower(); String typeCodecs = contentType.parameter(codecs()); @@ -569,7 +613,7 @@ MediaPlayer::SupportsType MediaPlayer::supportsType(ContentType contentType) if (type == applicationOctetStream()) return IsNotSupported; - MediaPlayerFactory* engine = chooseBestEngineForTypeAndCodecs(type, typeCodecs); + MediaPlayerFactory* engine = bestMediaEngineForTypeAndCodecs(type, typeCodecs); if (!engine) return IsNotSupported; @@ -652,9 +696,25 @@ double MediaPlayer::maximumDurationToCacheMediaTime() const return m_private->maximumDurationToCacheMediaTime(); } +void MediaPlayer::reloadTimerFired(Timer<MediaPlayer>*) +{ + m_private->cancelLoad(); + loadWithNextMediaEngine(m_currentMediaEngine); +} + + // Client callbacks. void MediaPlayer::networkStateChanged() { + // If more than one media engine is installed and this one failed before finding metadata, + // let the next engine try. + if (m_private->networkState() >= FormatError + && m_private->readyState() < HaveMetadata + && installedMediaEngines().size() > 1 + && bestMediaEngineForTypeAndCodecs(m_contentMIMEType, m_contentTypeCodecs, m_currentMediaEngine)) { + m_reloadTimer.startOneShot(0); + return; + } if (m_mediaPlayerClient) m_mediaPlayerClient->mediaPlayerNetworkStateChanged(this); } diff --git a/WebCore/platform/graphics/MediaPlayer.h b/WebCore/platform/graphics/MediaPlayer.h index a9499a5..6525ca6 100644 --- a/WebCore/platform/graphics/MediaPlayer.h +++ b/WebCore/platform/graphics/MediaPlayer.h @@ -91,6 +91,7 @@ class GraphicsContext; class IntRect; class IntSize; class MediaPlayer; +struct MediaPlayerFactory; class TimeRanges; class MediaPlayerClient { @@ -136,6 +137,8 @@ public: // the movie size has changed virtual void mediaPlayerSizeChanged(MediaPlayer*) { } + virtual void mediaPlayerEngineUpdated(MediaPlayer*) { } + #if USE(ACCELERATED_COMPOSITING) // whether the rendering system can accelerate the display of this MediaPlayer. virtual bool mediaPlayerRenderingCanBeAccelerated(MediaPlayer*) { return false; } @@ -157,7 +160,7 @@ public: // media engine support enum SupportsType { IsNotSupported, IsSupported, MayBeSupported }; - static MediaPlayer::SupportsType supportsType(ContentType contentType); + static MediaPlayer::SupportsType supportsType(const ContentType&); static void getSupportedTypes(HashSet<String>&); static bool isAvailable(); @@ -184,7 +187,7 @@ public: IntSize size() const { return m_size; } void setSize(const IntSize& size); - void load(const String& url, const ContentType& contentType); + void load(const String& url, const ContentType&); void cancelLoad(); bool visible() const; @@ -285,12 +288,18 @@ public: private: MediaPlayer(MediaPlayerClient*); + void loadWithNextMediaEngine(MediaPlayerFactory*); + void reloadTimerFired(Timer<MediaPlayer>*); static void initializeMediaEngines(); MediaPlayerClient* m_mediaPlayerClient; + Timer<MediaPlayer> m_reloadTimer; OwnPtr<MediaPlayerPrivateInterface*> m_private; - void* m_currentMediaEngine; + MediaPlayerFactory* m_currentMediaEngine; + String m_url; + String m_contentMIMEType; + String m_contentTypeCodecs; FrameView* m_frameView; IntSize m_size; Preload m_preload; diff --git a/WebCore/platform/graphics/Path.h b/WebCore/platform/graphics/Path.h index ba25dc2..423a792 100644 --- a/WebCore/platform/graphics/Path.h +++ b/WebCore/platform/graphics/Path.h @@ -46,7 +46,7 @@ class wxGraphicsPath; typedef wxGraphicsPath PlatformPath; #elif PLATFORM(CAIRO) namespace WebCore { - struct CairoPath; +class CairoPath; } typedef WebCore::CairoPath PlatformPath; #elif PLATFORM(SKIA) diff --git a/WebCore/platform/graphics/SimpleFontData.cpp b/WebCore/platform/graphics/SimpleFontData.cpp index 391873a..e773880 100644 --- a/WebCore/platform/graphics/SimpleFontData.cpp +++ b/WebCore/platform/graphics/SimpleFontData.cpp @@ -57,8 +57,6 @@ SimpleFontData::SimpleFontData(const FontPlatformData& platformData, bool isCust , m_isCustomFont(isCustomFont) , m_isLoading(isLoading) , m_isBrokenIdeographFont(false) - , m_smallCapsFontData(0) - , m_brokenIdeographFontData(0) { platformInit(); platformGlyphInit(); @@ -74,8 +72,6 @@ SimpleFontData::SimpleFontData(PassOwnPtr<SVGFontData> svgFontData, int size, bo , m_isCustomFont(true) , m_isLoading(false) , m_isBrokenIdeographFont(false) - , m_smallCapsFontData(0) - , m_brokenIdeographFontData(0) { SVGFontFaceElement* svgFontFaceElement = m_svgFontData->svgFontFaceElement(); m_unitsPerEm = svgFontFaceElement->unitsPerEm(); @@ -186,16 +182,6 @@ SimpleFontData::~SimpleFontData() if (!isCustomFont()) GlyphPageTreeNode::pruneTreeFontData(this); - else { - if (m_smallCapsFontData) - GlyphPageTreeNode::pruneTreeCustomFontData(m_smallCapsFontData); - - if (m_brokenIdeographFontData) - GlyphPageTreeNode::pruneTreeCustomFontData(m_brokenIdeographFontData); - } - - delete m_smallCapsFontData; - delete m_brokenIdeographFontData; } const SimpleFontData* SimpleFontData::fontDataForCharacter(UChar32) const @@ -210,12 +196,14 @@ bool SimpleFontData::isSegmented() const SimpleFontData* SimpleFontData::brokenIdeographFontData() const { - if (!m_brokenIdeographFontData) { - m_brokenIdeographFontData = new SimpleFontData(m_platformData, isCustomFont(), false); - m_brokenIdeographFontData->m_orientation = Vertical; - m_brokenIdeographFontData->m_isBrokenIdeographFont = true; + 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; } - return m_brokenIdeographFontData; + return m_derivedFontData->brokenIdeograph.get(); } #ifndef NDEBUG @@ -230,4 +218,22 @@ String SimpleFontData::description() const } #endif +PassOwnPtr<SimpleFontData::DerivedFontData> SimpleFontData::DerivedFontData::create(bool forCustomFont) +{ + return adoptPtr(new DerivedFontData(forCustomFont)); +} + +SimpleFontData::DerivedFontData::~DerivedFontData() +{ + if (!forCustomFont) + return; + + if (smallCaps) + GlyphPageTreeNode::pruneTreeCustomFontData(smallCaps.get()); + if (emphasisMark) + GlyphPageTreeNode::pruneTreeCustomFontData(emphasisMark.get()); + if (brokenIdeograph) + GlyphPageTreeNode::pruneTreeCustomFontData(brokenIdeograph.get()); +} + } // namespace WebCore diff --git a/WebCore/platform/graphics/SimpleFontData.h b/WebCore/platform/graphics/SimpleFontData.h index ea053cd..90713af 100644 --- a/WebCore/platform/graphics/SimpleFontData.h +++ b/WebCore/platform/graphics/SimpleFontData.h @@ -65,6 +65,7 @@ class FontDescription; class SharedBuffer; class SVGFontData; +enum FontDataVariant { AutoVariant, NormalVariant, SmallCapsVariant, EmphasisMarkVariant }; enum Pitch { UnknownPitch, FixedPitch, VariablePitch }; class SimpleFontData : public FontData { @@ -76,7 +77,24 @@ public: virtual ~SimpleFontData(); const FontPlatformData& platformData() const { return m_platformData; } - SimpleFontData* smallCapsFontData(const FontDescription& fontDescription) const; + + SimpleFontData* smallCapsFontData(const FontDescription&) const; + SimpleFontData* emphasisMarkFontData(const FontDescription&) const; + + SimpleFontData* variantFontData(const FontDescription& description, FontDataVariant variant) const + { + switch (variant) { + case SmallCapsVariant: + return smallCapsFontData(description); + case EmphasisMarkVariant: + return emphasisMarkFontData(description); + case AutoVariant: + case NormalVariant: + break; + } + ASSERT_NOT_REACHED(); + return const_cast<SimpleFontData*>(this); + } SimpleFontData* brokenIdeographFontData() const; @@ -183,6 +201,8 @@ private: void commonInit(); + SimpleFontData* scaledFontData(const FontDescription&, float scaleFactor) const; + #if (PLATFORM(WIN) && !OS(WINCE)) \ || (OS(WINDOWS) && PLATFORM(WX)) void initGDIFont(); @@ -226,9 +246,23 @@ private: GlyphData m_missingGlyphData; - mutable SimpleFontData* m_smallCapsFontData; + struct DerivedFontData { + static PassOwnPtr<DerivedFontData> create(bool forCustomFont); + ~DerivedFontData(); + + bool forCustomFont; + OwnPtr<SimpleFontData> smallCaps; + OwnPtr<SimpleFontData> emphasisMark; + OwnPtr<SimpleFontData> brokenIdeograph; + + private: + DerivedFontData(bool custom) + : forCustomFont(custom) + { + } + }; - mutable SimpleFontData* m_brokenIdeographFontData; + mutable OwnPtr<DerivedFontData> m_derivedFontData; #if PLATFORM(CG) || PLATFORM(CAIRO) || PLATFORM(WX) float m_syntheticBoldOffset; diff --git a/WebCore/platform/graphics/TextRun.h b/WebCore/platform/graphics/TextRun.h index 79b6cb3..dce5535 100644 --- a/WebCore/platform/graphics/TextRun.h +++ b/WebCore/platform/graphics/TextRun.h @@ -117,7 +117,10 @@ private: const UChar* m_characters; int m_len; - int m_xpos; + // m_xpos is the x position relative to the left start of the text line, not relative to the left + // start of the containing block. In the case of right alignment or center alignment, left start of + // the text line is not the same as left start of the containing block. + int m_xpos; int m_padding; #if ENABLE(SVG) float m_horizontalGlyphStretch; diff --git a/WebCore/platform/graphics/WidthIterator.cpp b/WebCore/platform/graphics/WidthIterator.cpp index ae58918..2a951e8 100644 --- a/WebCore/platform/graphics/WidthIterator.cpp +++ b/WebCore/platform/graphics/WidthIterator.cpp @@ -40,7 +40,7 @@ namespace WebCore { // According to http://www.unicode.org/Public/UNIDATA/UCD.html#Canonical_Combining_Class_Values static const uint8_t hiraganaKatakanaVoicingMarksCombiningClass = 8; -WidthIterator::WidthIterator(const Font* font, const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, bool accountForGlyphBounds) +WidthIterator::WidthIterator(const Font* font, const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, bool accountForGlyphBounds, bool forTextEmphasis) : m_font(font) , m_run(run) , m_end(run.length()) @@ -53,6 +53,7 @@ WidthIterator::WidthIterator(const Font* font, const TextRun& run, HashSet<const , m_minGlyphBoundingBoxY(numeric_limits<float>::max()) , m_firstGlyphOverflow(0) , m_lastGlyphOverflow(0) + , m_forTextEmphasis(forTextEmphasis) { // If the padding is non-zero, count the number of spaces in the run // and divide that by the padding for per space addition. @@ -199,6 +200,9 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer) m_firstGlyphOverflow = max<float>(0, -bounds.x()); } + if (m_forTextEmphasis && !Font::canReceiveTextEmphasis(c)) + glyph = 0; + // Advance past the character we just dealt with. cp += clusterLength; currentCharacter += clusterLength; diff --git a/WebCore/platform/graphics/WidthIterator.h b/WebCore/platform/graphics/WidthIterator.h index d42a0c5..8b3c067 100644 --- a/WebCore/platform/graphics/WidthIterator.h +++ b/WebCore/platform/graphics/WidthIterator.h @@ -33,7 +33,7 @@ class SimpleFontData; class TextRun; struct WidthIterator { - WidthIterator(const Font*, const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0, bool accountForGlyphBounds = false); + WidthIterator(const Font*, const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0, bool accountForGlyphBounds = false, bool forTextEmphasis = false); void advance(int to, GlyphBuffer* = 0); bool advanceOneCharacter(float& width, GlyphBuffer* = 0); @@ -63,6 +63,7 @@ private: float m_minGlyphBoundingBoxY; float m_firstGlyphOverflow; float m_lastGlyphOverflow; + bool m_forTextEmphasis; }; } diff --git a/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp b/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp new file mode 100644 index 0000000..8bde9fd --- /dev/null +++ b/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp @@ -0,0 +1,2300 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) + +#include "GraphicsLayerCA.h" + +#include "Animation.h" +#include "FloatConversion.h" +#include "FloatRect.h" +#include "PlatformCALayer.h" +#include "PlatformString.h" +#include "RotateTransformOperation.h" +#include "ScaleTransformOperation.h" +#include "SystemTime.h" +#include "TranslateTransformOperation.h" +#include <QuartzCore/QuartzCore.h> +#include <limits.h> +#include <wtf/CurrentTime.h> +#include <wtf/text/StringConcatenate.h> + +using namespace std; + +#define HAVE_MODERN_QUARTZCORE (!defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)) + +namespace WebCore { + +// The threshold width or height above which a tiled layer will be used. This should be +// large enough to avoid tiled layers for most GraphicsLayers, but less than the OpenGL +// texture size limit on all supported hardware. +static const int cMaxPixelDimension = 2000; + +// If we send a duration of 0 to CA, then it will use the default duration +// of 250ms. So send a very small value instead. +static const float cAnimationAlmostZeroDuration = 1e-3f; + +// CACurrentMediaTime() is a time since boot. These methods convert between that and +// WebCore time, which is system time (UTC). +static CFTimeInterval currentTimeToMediaTime(double t) +{ + return CACurrentMediaTime() + t - WTF::currentTime(); +} + +static bool isTransformTypeTransformationMatrix(TransformOperation::OperationType transformType) +{ + switch (transformType) { + case TransformOperation::SKEW_X: + case TransformOperation::SKEW_Y: + case TransformOperation::SKEW: + case TransformOperation::MATRIX: + case TransformOperation::ROTATE_3D: + case TransformOperation::MATRIX_3D: + case TransformOperation::PERSPECTIVE: + case TransformOperation::IDENTITY: + case TransformOperation::NONE: + return true; + default: + return false; + } +} + +static bool isTransformTypeFloatPoint3D(TransformOperation::OperationType transformType) +{ + switch (transformType) { + case TransformOperation::SCALE: + case TransformOperation::SCALE_3D: + case TransformOperation::TRANSLATE: + case TransformOperation::TRANSLATE_3D: + return true; + default: + return false; + } +} + +static bool isTransformTypeNumber(TransformOperation::OperationType transformType) +{ + return !isTransformTypeTransformationMatrix(transformType) && !isTransformTypeFloatPoint3D(transformType); +} + +static void getTransformFunctionValue(const TransformOperation* transformOp, TransformOperation::OperationType transformType, const IntSize& size, float& value) +{ + switch (transformType) { + case TransformOperation::ROTATE: + case TransformOperation::ROTATE_X: + case TransformOperation::ROTATE_Y: + value = transformOp ? narrowPrecisionToFloat(deg2rad(static_cast<const RotateTransformOperation*>(transformOp)->angle())) : 0; + break; + case TransformOperation::SCALE_X: + value = transformOp ? narrowPrecisionToFloat(static_cast<const ScaleTransformOperation*>(transformOp)->x()) : 1; + break; + case TransformOperation::SCALE_Y: + value = transformOp ? narrowPrecisionToFloat(static_cast<const ScaleTransformOperation*>(transformOp)->y()) : 1; + break; + case TransformOperation::SCALE_Z: + value = transformOp ? narrowPrecisionToFloat(static_cast<const ScaleTransformOperation*>(transformOp)->z()) : 1; + break; + case TransformOperation::TRANSLATE_X: + value = transformOp ? narrowPrecisionToFloat(static_cast<const TranslateTransformOperation*>(transformOp)->x(size)) : 0; + break; + case TransformOperation::TRANSLATE_Y: + value = transformOp ? narrowPrecisionToFloat(static_cast<const TranslateTransformOperation*>(transformOp)->y(size)) : 0; + break; + case TransformOperation::TRANSLATE_Z: + value = transformOp ? narrowPrecisionToFloat(static_cast<const TranslateTransformOperation*>(transformOp)->z(size)) : 0; + break; + default: + break; + } +} + +static void getTransformFunctionValue(const TransformOperation* transformOp, TransformOperation::OperationType transformType, const IntSize& size, FloatPoint3D& value) +{ + switch (transformType) { + case TransformOperation::SCALE: + case TransformOperation::SCALE_3D: + value.setX(transformOp ? narrowPrecisionToFloat(static_cast<const ScaleTransformOperation*>(transformOp)->x()) : 1); + value.setY(transformOp ? narrowPrecisionToFloat(static_cast<const ScaleTransformOperation*>(transformOp)->y()) : 1); + value.setZ(transformOp ? narrowPrecisionToFloat(static_cast<const ScaleTransformOperation*>(transformOp)->z()) : 1); + break; + case TransformOperation::TRANSLATE: + case TransformOperation::TRANSLATE_3D: + value.setX(transformOp ? narrowPrecisionToFloat(static_cast<const TranslateTransformOperation*>(transformOp)->x(size)) : 0); + value.setY(transformOp ? narrowPrecisionToFloat(static_cast<const TranslateTransformOperation*>(transformOp)->y(size)) : 0); + value.setZ(transformOp ? narrowPrecisionToFloat(static_cast<const TranslateTransformOperation*>(transformOp)->z(size)) : 0); + break; + default: + break; + } +} + +static void getTransformFunctionValue(const TransformOperation* transformOp, TransformOperation::OperationType transformType, const IntSize& size, TransformationMatrix& value) +{ + switch (transformType) { + case TransformOperation::SKEW_X: + case TransformOperation::SKEW_Y: + case TransformOperation::SKEW: + case TransformOperation::MATRIX: + case TransformOperation::ROTATE_3D: + case TransformOperation::MATRIX_3D: + case TransformOperation::PERSPECTIVE: + case TransformOperation::IDENTITY: + case TransformOperation::NONE: + if (transformOp) + transformOp->apply(value, size); + else + value.makeIdentity(); + break; + default: + break; + } +} + +#if HAVE_MODERN_QUARTZCORE +static PlatformCAAnimation::ValueFunctionType getValueFunctionNameForTransformOperation(TransformOperation::OperationType transformType) +{ + // Use literal strings to avoid link-time dependency on those symbols. + switch (transformType) { + case TransformOperation::ROTATE_X: + return PlatformCAAnimation::RotateX; + case TransformOperation::ROTATE_Y: + return PlatformCAAnimation::RotateY; + case TransformOperation::ROTATE: + return PlatformCAAnimation::RotateZ; + case TransformOperation::SCALE_X: + return PlatformCAAnimation::ScaleX; + case TransformOperation::SCALE_Y: + return PlatformCAAnimation::ScaleY; + case TransformOperation::SCALE_Z: + return PlatformCAAnimation::ScaleZ; + case TransformOperation::TRANSLATE_X: + return PlatformCAAnimation::TranslateX; + case TransformOperation::TRANSLATE_Y: + return PlatformCAAnimation::TranslateY; + case TransformOperation::TRANSLATE_Z: + return PlatformCAAnimation::TranslateZ; + case TransformOperation::SCALE: + case TransformOperation::SCALE_3D: + return PlatformCAAnimation::Scale; + case TransformOperation::TRANSLATE: + case TransformOperation::TRANSLATE_3D: + return PlatformCAAnimation::Translate; + default: + return PlatformCAAnimation::NoValueFunction; + } +} +#endif + +static String propertyIdToString(AnimatedPropertyID property) +{ + switch (property) { + case AnimatedPropertyWebkitTransform: + return "transform"; + case AnimatedPropertyOpacity: + return "opacity"; + case AnimatedPropertyBackgroundColor: + return "backgroundColor"; + case AnimatedPropertyInvalid: + ASSERT_NOT_REACHED(); + } + ASSERT_NOT_REACHED(); + return ""; +} + +static String animationIdentifier(const String& animationName, AnimatedPropertyID property, int index) +{ + return makeString(animationName, '_', String::number(property), '_', String::number(index)); +} + +static bool animationHasStepsTimingFunction(const KeyframeValueList& valueList, const Animation* anim) +{ + if (anim->timingFunction()->isStepsTimingFunction()) + return true; + + for (unsigned i = 0; i < valueList.size(); ++i) { + const TimingFunction* timingFunction = valueList.at(i)->timingFunction(); + if (timingFunction && timingFunction->isStepsTimingFunction()) + return true; + } + + return false; +} + +PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client) +{ + return new GraphicsLayerCA(client); +} + +GraphicsLayerCA::GraphicsLayerCA(GraphicsLayerClient* client) + : GraphicsLayer(client) + , m_contentsLayerPurpose(NoContentsLayer) + , m_contentsLayerHasBackgroundColor(false) + , m_uncommittedChanges(NoChange) +{ + m_layer = PlatformCALayer::create(PlatformCALayer::LayerTypeWebLayer, this); + +#if !HAVE_MODERN_QUARTZCORE + setContentsOrientation(defaultContentsOrientation()); +#endif + + updateDebugIndicators(); +} + +GraphicsLayerCA::~GraphicsLayerCA() +{ + // We release our references to the PlatformCALayers here, but do not actively unparent them, + // since that will cause a commit and break our batched commit model. The layers will + // get released when the rootmost modified GraphicsLayerCA rebuilds its child layers. + + // Clean up the layer. + if (m_layer) + m_layer->setOwner(0); + + if (m_contentsLayer) + m_contentsLayer->setOwner(0); + + if (m_structuralLayer) + m_structuralLayer->setOwner(0); + + removeCloneLayers(); +} + +void GraphicsLayerCA::setName(const String& name) +{ + String longName = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + name; + GraphicsLayer::setName(longName); + noteLayerPropertyChanged(NameChanged); +} + +PlatformLayer* GraphicsLayerCA::platformLayer() const +{ + return primaryLayer()->platformLayer(); +} + +bool GraphicsLayerCA::setChildren(const Vector<GraphicsLayer*>& children) +{ + bool childrenChanged = GraphicsLayer::setChildren(children); + if (childrenChanged) + noteSublayersChanged(); + + return childrenChanged; +} + +void GraphicsLayerCA::addChild(GraphicsLayer* childLayer) +{ + GraphicsLayer::addChild(childLayer); + noteSublayersChanged(); +} + +void GraphicsLayerCA::addChildAtIndex(GraphicsLayer* childLayer, int index) +{ + GraphicsLayer::addChildAtIndex(childLayer, index); + noteSublayersChanged(); +} + +void GraphicsLayerCA::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling) +{ + GraphicsLayer::addChildBelow(childLayer, sibling); + noteSublayersChanged(); +} + +void GraphicsLayerCA::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling) +{ + GraphicsLayer::addChildAbove(childLayer, sibling); + noteSublayersChanged(); +} + +bool GraphicsLayerCA::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild) +{ + if (GraphicsLayer::replaceChild(oldChild, newChild)) { + noteSublayersChanged(); + return true; + } + return false; +} + +void GraphicsLayerCA::removeFromParent() +{ + if (m_parent) + static_cast<GraphicsLayerCA*>(m_parent)->noteSublayersChanged(); + GraphicsLayer::removeFromParent(); +} + +void GraphicsLayerCA::setMaskLayer(GraphicsLayer* layer) +{ + if (layer == m_maskLayer) + return; + + GraphicsLayer::setMaskLayer(layer); + noteLayerPropertyChanged(MaskLayerChanged); + + propagateLayerChangeToReplicas(); + + if (m_replicatedLayer) + static_cast<GraphicsLayerCA*>(m_replicatedLayer)->propagateLayerChangeToReplicas(); +} + +void GraphicsLayerCA::setReplicatedLayer(GraphicsLayer* layer) +{ + if (layer == m_replicatedLayer) + return; + + GraphicsLayer::setReplicatedLayer(layer); + noteLayerPropertyChanged(ReplicatedLayerChanged); +} + +void GraphicsLayerCA::setReplicatedByLayer(GraphicsLayer* layer) +{ + if (layer == m_replicaLayer) + return; + + GraphicsLayer::setReplicatedByLayer(layer); + noteSublayersChanged(); + noteLayerPropertyChanged(ReplicatedLayerChanged); +} + +void GraphicsLayerCA::setPosition(const FloatPoint& point) +{ + if (point == m_position) + return; + + GraphicsLayer::setPosition(point); + noteLayerPropertyChanged(PositionChanged); +} + +void GraphicsLayerCA::setAnchorPoint(const FloatPoint3D& point) +{ + if (point == m_anchorPoint) + return; + + GraphicsLayer::setAnchorPoint(point); + noteLayerPropertyChanged(AnchorPointChanged); +} + +void GraphicsLayerCA::setSize(const FloatSize& size) +{ + if (size == m_size) + return; + + GraphicsLayer::setSize(size); + noteLayerPropertyChanged(SizeChanged); +} + +void GraphicsLayerCA::setTransform(const TransformationMatrix& t) +{ + if (t == m_transform) + return; + + GraphicsLayer::setTransform(t); + noteLayerPropertyChanged(TransformChanged); +} + +void GraphicsLayerCA::setChildrenTransform(const TransformationMatrix& t) +{ + if (t == m_childrenTransform) + return; + + GraphicsLayer::setChildrenTransform(t); + noteLayerPropertyChanged(ChildrenTransformChanged); +} + +void GraphicsLayerCA::moveOrCopyLayerAnimation(MoveOrCopy operation, const String& animationIdentifier, PlatformCALayer *fromLayer, PlatformCALayer *toLayer) +{ + RefPtr<PlatformCAAnimation> anim = fromLayer->animationForKey(animationIdentifier); + if (!anim) + return; + + switch (operation) { + case Move: + fromLayer->removeAnimationForKey(animationIdentifier); + toLayer->addAnimationForKey(animationIdentifier, anim.get()); + break; + + case Copy: + toLayer->addAnimationForKey(animationIdentifier, anim.get()); + break; + } +} + +void GraphicsLayerCA::moveOrCopyAnimationsForProperty(MoveOrCopy operation, AnimatedPropertyID property, PlatformCALayer *fromLayer, PlatformCALayer *toLayer) +{ + // Look for running animations affecting this property. + AnimationsMap::const_iterator end = m_runningAnimations.end(); + for (AnimationsMap::const_iterator it = m_runningAnimations.begin(); it != end; ++it) { + const Vector<LayerPropertyAnimation>& propertyAnimations = it->second; + size_t numAnimations = propertyAnimations.size(); + for (size_t i = 0; i < numAnimations; ++i) { + const LayerPropertyAnimation& currAnimation = propertyAnimations[i]; + if (currAnimation.m_property == property) + moveOrCopyLayerAnimation(operation, animationIdentifier(currAnimation.m_name, currAnimation.m_property, currAnimation.m_index), fromLayer, toLayer); + } + } +} + +void GraphicsLayerCA::setPreserves3D(bool preserves3D) +{ + if (preserves3D == m_preserves3D) + return; + + GraphicsLayer::setPreserves3D(preserves3D); + noteLayerPropertyChanged(Preserves3DChanged); +} + +void GraphicsLayerCA::setMasksToBounds(bool masksToBounds) +{ + if (masksToBounds == m_masksToBounds) + return; + + GraphicsLayer::setMasksToBounds(masksToBounds); + noteLayerPropertyChanged(MasksToBoundsChanged); +} + +void GraphicsLayerCA::setDrawsContent(bool drawsContent) +{ + if (drawsContent == m_drawsContent) + return; + + GraphicsLayer::setDrawsContent(drawsContent); + noteLayerPropertyChanged(DrawsContentChanged); +} + +void GraphicsLayerCA::setAcceleratesDrawing(bool acceleratesDrawing) +{ + if (acceleratesDrawing == m_acceleratesDrawing) + return; + + GraphicsLayer::setAcceleratesDrawing(acceleratesDrawing); + noteLayerPropertyChanged(DrawsContentChanged); +} + +void GraphicsLayerCA::setBackgroundColor(const Color& color) +{ + if (m_backgroundColorSet && m_backgroundColor == color) + return; + + GraphicsLayer::setBackgroundColor(color); + + m_contentsLayerHasBackgroundColor = true; + noteLayerPropertyChanged(BackgroundColorChanged); +} + +void GraphicsLayerCA::clearBackgroundColor() +{ + if (!m_backgroundColorSet) + return; + + GraphicsLayer::clearBackgroundColor(); + m_contentsLayerHasBackgroundColor = false; + noteLayerPropertyChanged(BackgroundColorChanged); +} + +void GraphicsLayerCA::setContentsOpaque(bool opaque) +{ + if (m_contentsOpaque == opaque) + return; + + GraphicsLayer::setContentsOpaque(opaque); + noteLayerPropertyChanged(ContentsOpaqueChanged); +} + +void GraphicsLayerCA::setBackfaceVisibility(bool visible) +{ + if (m_backfaceVisibility == visible) + return; + + GraphicsLayer::setBackfaceVisibility(visible); + noteLayerPropertyChanged(BackfaceVisibilityChanged); +} + +void GraphicsLayerCA::setOpacity(float opacity) +{ + float clampedOpacity = max(0.0f, min(opacity, 1.0f)); + + if (clampedOpacity == m_opacity) + return; + + GraphicsLayer::setOpacity(clampedOpacity); + noteLayerPropertyChanged(OpacityChanged); +} + +void GraphicsLayerCA::setNeedsDisplay() +{ + FloatRect hugeRect(-numeric_limits<float>::max() / 2, -numeric_limits<float>::max() / 2, + numeric_limits<float>::max(), numeric_limits<float>::max()); + + setNeedsDisplayInRect(hugeRect); +} + +void GraphicsLayerCA::setNeedsDisplayInRect(const FloatRect& rect) +{ + if (!drawsContent()) + return; + + const size_t maxDirtyRects = 32; + + for (size_t i = 0; i < m_dirtyRects.size(); ++i) { + if (m_dirtyRects[i].contains(rect)) + return; + } + + if (m_dirtyRects.size() < maxDirtyRects) + m_dirtyRects.append(rect); + else + m_dirtyRects[0].unite(rect); + + noteLayerPropertyChanged(DirtyRectsChanged); +} + +void GraphicsLayerCA::setContentsNeedsDisplay() +{ + noteLayerPropertyChanged(ContentsNeedsDisplay); +} + +void GraphicsLayerCA::setContentsRect(const IntRect& rect) +{ + if (rect == m_contentsRect) + return; + + GraphicsLayer::setContentsRect(rect); + noteLayerPropertyChanged(ContentsRectChanged); +} + +bool GraphicsLayerCA::addAnimation(const KeyframeValueList& valueList, const IntSize& boxSize, const Animation* anim, const String& animationName, double timeOffset) +{ + ASSERT(!animationName.isEmpty()); + + if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2) + return false; + +#if !HAVE_MODERN_QUARTZCORE + // Older versions of QuartzCore do not handle opacity in transform layers properly, so we will + // always do software animation in that case. + if (valueList.property() == AnimatedPropertyOpacity) + return false; +#endif + + // CoreAnimation does not handle the steps() timing function. Fall back + // to software animation in that case. + if (animationHasStepsTimingFunction(valueList, anim)) + return false; + + bool createdAnimations = false; + if (valueList.property() == AnimatedPropertyWebkitTransform) + createdAnimations = createTransformAnimationsFromKeyframes(valueList, anim, animationName, timeOffset, boxSize); + else + createdAnimations = createAnimationFromKeyframes(valueList, anim, animationName, timeOffset); + + if (createdAnimations) + noteLayerPropertyChanged(AnimationChanged); + + return createdAnimations; +} + +void GraphicsLayerCA::pauseAnimation(const String& animationName, double timeOffset) +{ + if (!animationIsRunning(animationName)) + return; + + AnimationsToProcessMap::iterator it = m_animationsToProcess.find(animationName); + if (it != m_animationsToProcess.end()) { + AnimationProcessingAction& processingInfo = it->second; + // If an animation is scheduled to be removed, don't change the remove to a pause. + if (processingInfo.action != Remove) + processingInfo.action = Pause; + } else + m_animationsToProcess.add(animationName, AnimationProcessingAction(Pause, timeOffset)); + + noteLayerPropertyChanged(AnimationChanged); +} + +void GraphicsLayerCA::removeAnimation(const String& animationName) +{ + if (!animationIsRunning(animationName)) + return; + + m_animationsToProcess.add(animationName, AnimationProcessingAction(Remove)); + noteLayerPropertyChanged(AnimationChanged); +} + +void GraphicsLayerCA::animationStarted(CFTimeInterval startTime) +{ + if (m_client) + m_client->notifyAnimationStarted(this, startTime); +} + +void GraphicsLayerCA::setContentsToImage(Image* image) +{ + if (image) { + CGImageRef newImage = image->nativeImageForCurrentFrame(); + if (!newImage) + return; + + // Check to see if the image changed; we have to do this because the call to + // CGImageCreateCopyWithColorSpace() below can create a new image every time. + if (m_uncorrectedContentsImage && m_uncorrectedContentsImage.get() == newImage) + return; + + m_uncorrectedContentsImage = newImage; + m_pendingContentsImage = newImage; + CGColorSpaceRef colorSpace = CGImageGetColorSpace(m_pendingContentsImage.get()); + + static CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB(); + if (colorSpace && CFEqual(colorSpace, deviceRGB)) { + // CoreGraphics renders images tagged with DeviceRGB using the color space of the main display. When we hand such + // images to CA we need to tag them similarly so CA rendering matches CG rendering. + static CGColorSpaceRef genericRGB = CGDisplayCopyColorSpace(kCGDirectMainDisplay); + m_pendingContentsImage.adoptCF(CGImageCreateCopyWithColorSpace(m_pendingContentsImage.get(), genericRGB)); + } + m_contentsLayerPurpose = ContentsLayerForImage; + if (!m_contentsLayer) + noteSublayersChanged(); + } else { + m_uncorrectedContentsImage = 0; + m_pendingContentsImage = 0; + m_contentsLayerPurpose = NoContentsLayer; + if (m_contentsLayer) + noteSublayersChanged(); + } + + noteLayerPropertyChanged(ContentsImageChanged); +} + +void GraphicsLayerCA::setContentsToMedia(PlatformLayer* mediaLayer) +{ + if (m_contentsLayer && mediaLayer == m_contentsLayer->platformLayer()) + return; + + // Create the PlatformCALayer to wrap the incoming layer + m_contentsLayer = mediaLayer ? PlatformCALayer::create(mediaLayer, this) : 0; + + m_contentsLayerPurpose = mediaLayer ? ContentsLayerForMedia : NoContentsLayer; + + noteSublayersChanged(); + noteLayerPropertyChanged(ContentsMediaLayerChanged); +} + +void GraphicsLayerCA::setContentsToCanvas(PlatformLayer* canvasLayer) +{ + if (m_contentsLayer && canvasLayer == m_contentsLayer->platformLayer()) + return; + + // Create the PlatformCALayer to wrap the incoming layer + m_contentsLayer = canvasLayer ? PlatformCALayer::create(canvasLayer, this) : 0; + + m_contentsLayerPurpose = canvasLayer ? ContentsLayerForCanvas : NoContentsLayer; + + noteSublayersChanged(); + noteLayerPropertyChanged(ContentsCanvasLayerChanged); +} + +void GraphicsLayerCA::didDisplay(PlatformLayer* layer) +{ + PlatformCALayer* currentLayer = PlatformCALayer::platformCALayer(layer); + PlatformCALayer* sourceLayer; + LayerMap* layerCloneMap; + + if (currentLayer == m_layer) { + sourceLayer = m_layer.get(); + layerCloneMap = m_layerClones.get(); + } else if (currentLayer == m_contentsLayer) { + sourceLayer = m_contentsLayer.get(); + layerCloneMap = m_contentsLayerClones.get(); + } else + return; + + if (layerCloneMap) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + PlatformCALayer* currClone = it->second.get(); + if (!currClone) + continue; + + if (currClone->contents() != sourceLayer->contents()) + currClone->setContents(sourceLayer->contents()); + else + currClone->setContentsChanged(); + } + } +} + +void GraphicsLayerCA::syncCompositingState() +{ + recursiveCommitChanges(); +} + +void GraphicsLayerCA::syncCompositingStateForThisLayerOnly() +{ + commitLayerChangesBeforeSublayers(); + commitLayerChangesAfterSublayers(); +} + +void GraphicsLayerCA::recursiveCommitChanges() +{ + commitLayerChangesBeforeSublayers(); + + if (m_maskLayer) + static_cast<GraphicsLayerCA*>(m_maskLayer)->commitLayerChangesBeforeSublayers(); + + const Vector<GraphicsLayer*>& childLayers = children(); + size_t numChildren = childLayers.size(); + for (size_t i = 0; i < numChildren; ++i) { + GraphicsLayerCA* curChild = static_cast<GraphicsLayerCA*>(childLayers[i]); + curChild->recursiveCommitChanges(); + } + + if (m_replicaLayer) + static_cast<GraphicsLayerCA*>(m_replicaLayer)->recursiveCommitChanges(); + + if (m_maskLayer) + static_cast<GraphicsLayerCA*>(m_maskLayer)->commitLayerChangesAfterSublayers(); + + commitLayerChangesAfterSublayers(); +} + +void GraphicsLayerCA::commitLayerChangesBeforeSublayers() +{ + if (!m_uncommittedChanges) + return; + + // Need to handle Preserves3DChanged first, because it affects which layers subsequent properties are applied to + if (m_uncommittedChanges & (Preserves3DChanged | ReplicatedLayerChanged)) + updateStructuralLayer(); + + if (m_uncommittedChanges & NameChanged) + updateLayerNames(); + + if (m_uncommittedChanges & ContentsImageChanged) // Needs to happen before ChildrenChanged + updateContentsImage(); + + if (m_uncommittedChanges & ContentsMediaLayerChanged) // Needs to happen before ChildrenChanged + updateContentsMediaLayer(); + + if (m_uncommittedChanges & ContentsCanvasLayerChanged) // Needs to happen before ChildrenChanged + updateContentsCanvasLayer(); + + if (m_uncommittedChanges & BackgroundColorChanged) // Needs to happen before ChildrenChanged, and after updating image or video + updateLayerBackgroundColor(); + + if (m_uncommittedChanges & ChildrenChanged) + updateSublayerList(); + + if (m_uncommittedChanges & PositionChanged) + updateLayerPosition(); + + if (m_uncommittedChanges & AnchorPointChanged) + updateAnchorPoint(); + + if (m_uncommittedChanges & SizeChanged) + updateLayerSize(); + + if (m_uncommittedChanges & TransformChanged) + updateTransform(); + + if (m_uncommittedChanges & ChildrenTransformChanged) + updateChildrenTransform(); + + if (m_uncommittedChanges & MasksToBoundsChanged) + updateMasksToBounds(); + + if (m_uncommittedChanges & DrawsContentChanged) + updateLayerDrawsContent(); + + if (m_uncommittedChanges & ContentsOpaqueChanged) + updateContentsOpaque(); + + if (m_uncommittedChanges & BackfaceVisibilityChanged) + updateBackfaceVisibility(); + + if (m_uncommittedChanges & OpacityChanged) + updateOpacityOnLayer(); + + if (m_uncommittedChanges & AnimationChanged) + updateLayerAnimations(); + + if (m_uncommittedChanges & DirtyRectsChanged) + repaintLayerDirtyRects(); + + if (m_uncommittedChanges & ContentsRectChanged) + updateContentsRect(); + + if (m_uncommittedChanges & MaskLayerChanged) + updateMaskLayer(); + + if (m_uncommittedChanges & ContentsNeedsDisplay) + updateContentsNeedsDisplay(); + + if (m_uncommittedChanges & AcceleratesDrawingChanged) + updateAcceleratesDrawing(); +} + +void GraphicsLayerCA::commitLayerChangesAfterSublayers() +{ + if (!m_uncommittedChanges) + return; + + if (m_uncommittedChanges & ReplicatedLayerChanged) + updateReplicatedLayers(); + + m_uncommittedChanges = NoChange; +} + +void GraphicsLayerCA::updateLayerNames() +{ + switch (structuralLayerPurpose()) { + case StructuralLayerForPreserves3D: + m_structuralLayer->setName("Transform layer " + name()); + break; + case StructuralLayerForReplicaFlattening: + m_structuralLayer->setName("Replica flattening layer " + name()); + break; + case NoStructuralLayer: + break; + } + m_layer->setName(name()); +} + +void GraphicsLayerCA::updateSublayerList() +{ + PlatformCALayerList newSublayers; + const Vector<GraphicsLayer*>& childLayers = children(); + + if (m_structuralLayer || m_contentsLayer || childLayers.size() > 0) { + if (m_structuralLayer) { + // Add the replica layer first. + if (m_replicaLayer) + newSublayers.append(static_cast<GraphicsLayerCA*>(m_replicaLayer)->primaryLayer()); + // Add the primary layer. Even if we have negative z-order children, the primary layer always comes behind. + newSublayers.append(m_layer); + } else if (m_contentsLayer) { + // FIXME: add the contents layer in the correct order with negative z-order children. + // This does not cause visible rendering issues because currently contents layers are only used + // for replaced elements that don't have children. + newSublayers.append(m_contentsLayer); + } + + size_t numChildren = childLayers.size(); + for (size_t i = 0; i < numChildren; ++i) { + GraphicsLayerCA* curChild = static_cast<GraphicsLayerCA*>(childLayers[i]); + PlatformCALayer* childLayer = curChild->layerForSuperlayer(); + newSublayers.append(childLayer); + } + + for (size_t i = 0; i < newSublayers.size(); ++i) + newSublayers[i]->removeFromSuperlayer(); + } + + if (m_structuralLayer) { + m_structuralLayer->setSublayers(newSublayers); + + if (m_contentsLayer) { + // If we have a transform layer, then the contents layer is parented in the + // primary layer (which is itself a child of the transform layer). + m_layer->removeAllSublayers(); + m_layer->appendSublayer(m_contentsLayer.get()); + } + } else + m_layer->setSublayers(newSublayers); +} + +void GraphicsLayerCA::updateLayerPosition() +{ + FloatSize usedSize = m_usingTiledLayer ? constrainedSize() : m_size; + + // Position is offset on the layer by the layer anchor point. + FloatPoint posPoint(m_position.x() + m_anchorPoint.x() * usedSize.width(), + m_position.y() + m_anchorPoint.y() * usedSize.height()); + + primaryLayer()->setPosition(posPoint); + + if (LayerMap* layerCloneMap = primaryLayerClones()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + FloatPoint clonePosition = posPoint; + if (m_replicaLayer && isReplicatedRootClone(it->first)) { + // Maintain the special-case position for the root of a clone subtree, + // which we set up in replicatedLayerRoot(). + clonePosition = positionForCloneRootLayer(); + } + it->second->setPosition(clonePosition); + } + } +} + +void GraphicsLayerCA::updateLayerSize() +{ + FloatRect rect(0, 0, m_size.width(), m_size.height()); + if (m_structuralLayer) { + m_structuralLayer->setBounds(rect); + + if (LayerMap* layerCloneMap = m_structuralLayerClones.get()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) + it->second->setBounds(rect); + } + + // The anchor of the contents layer is always at 0.5, 0.5, so the position is center-relative. + CGPoint centerPoint = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f); + m_layer->setPosition(centerPoint); + + if (LayerMap* layerCloneMap = m_layerClones.get()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) + it->second->setPosition(centerPoint); + } + } + + bool needTiledLayer = requiresTiledLayer(m_size); + if (needTiledLayer != m_usingTiledLayer) + swapFromOrToTiledLayer(needTiledLayer); + + if (m_usingTiledLayer) { + FloatSize sizeToUse = constrainedSize(); + rect = CGRectMake(0, 0, sizeToUse.width(), sizeToUse.height()); + } + + m_layer->setBounds(rect); + if (LayerMap* layerCloneMap = m_layerClones.get()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) + it->second->setBounds(rect); + } + + // Contents transform may depend on height. + updateContentsTransform(); + + // Note that we don't resize m_contentsLayer. It's up the caller to do that. + + // if we've changed the bounds, we need to recalculate the position + // of the layer, taking anchor point into account. + updateLayerPosition(); +} + +void GraphicsLayerCA::updateAnchorPoint() +{ + primaryLayer()->setAnchorPoint(m_anchorPoint); + + if (LayerMap* layerCloneMap = primaryLayerClones()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + PlatformCALayer* currLayer = it->second.get(); + currLayer->setAnchorPoint(m_anchorPoint); + } + } + + updateLayerPosition(); +} + +void GraphicsLayerCA::updateTransform() +{ + primaryLayer()->setTransform(m_transform); + + if (LayerMap* layerCloneMap = primaryLayerClones()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + PlatformCALayer* currLayer = it->second.get(); + if (m_replicaLayer && isReplicatedRootClone(it->first)) { + // Maintain the special-case transform for the root of a clone subtree, + // which we set up in replicatedLayerRoot(). + currLayer->setTransform(TransformationMatrix()); + } else + currLayer->setTransform(m_transform); + } + } +} + +void GraphicsLayerCA::updateChildrenTransform() +{ + primaryLayer()->setSublayerTransform(m_childrenTransform); + + if (LayerMap* layerCloneMap = primaryLayerClones()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) + it->second->setSublayerTransform(m_childrenTransform); + } +} + +void GraphicsLayerCA::updateMasksToBounds() +{ + m_layer->setMasksToBounds(m_masksToBounds); + + if (LayerMap* layerCloneMap = m_layerClones.get()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) + it->second->setMasksToBounds(m_masksToBounds); + } + + updateDebugIndicators(); +} + +void GraphicsLayerCA::updateContentsOpaque() +{ + m_layer.get()->setOpaque(m_contentsOpaque); + + if (LayerMap* layerCloneMap = m_layerClones.get()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) + it->second->setOpaque(m_contentsOpaque); + } +} + +void GraphicsLayerCA::updateBackfaceVisibility() +{ + if (m_structuralLayer && structuralLayerPurpose() == StructuralLayerForReplicaFlattening) { + m_structuralLayer->setDoubleSided(m_backfaceVisibility); + + if (LayerMap* layerCloneMap = m_structuralLayerClones.get()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) + it->second->setDoubleSided(m_backfaceVisibility); + } + } + + m_layer->setDoubleSided(m_backfaceVisibility); + + if (LayerMap* layerCloneMap = m_layerClones.get()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) + it->second->setDoubleSided(m_backfaceVisibility); + } +} + +void GraphicsLayerCA::updateStructuralLayer() +{ + ensureStructuralLayer(structuralLayerPurpose()); +} + +void GraphicsLayerCA::ensureStructuralLayer(StructuralLayerPurpose purpose) +{ + if (purpose == NoStructuralLayer) { + if (m_structuralLayer) { + // Replace the transformLayer in the parent with this layer. + m_layer->removeFromSuperlayer(); + m_structuralLayer->superlayer()->replaceSublayer(m_structuralLayer.get(), m_layer.get()); + + moveOrCopyAnimationsForProperty(Move, AnimatedPropertyWebkitTransform, m_structuralLayer.get(), m_layer.get()); + moveOrCopyAnimationsForProperty(Move, AnimatedPropertyOpacity, m_structuralLayer.get(), m_layer.get()); + + // Release the structural layer. + m_structuralLayer = 0; + + // Update the properties of m_layer now that we no longer have a structural layer. + updateLayerPosition(); + updateLayerSize(); + updateAnchorPoint(); + updateTransform(); + updateChildrenTransform(); + + updateSublayerList(); + updateOpacityOnLayer(); + } + return; + } + + bool structuralLayerChanged = false; + + if (purpose == StructuralLayerForPreserves3D) { + if (m_structuralLayer && m_structuralLayer->layerType() != PlatformCALayer::LayerTypeTransformLayer) + m_structuralLayer = 0; + + if (!m_structuralLayer) { + m_structuralLayer = PlatformCALayer::create(PlatformCALayer::LayerTypeTransformLayer, this); + structuralLayerChanged = true; + } + } else { + if (m_structuralLayer && m_structuralLayer->layerType() != PlatformCALayer::LayerTypeLayer) + m_structuralLayer = 0; + + if (!m_structuralLayer) { + m_structuralLayer = PlatformCALayer::create(PlatformCALayer::LayerTypeLayer, this); + structuralLayerChanged = true; + } + } + + if (!structuralLayerChanged) + return; + + updateLayerNames(); + + // Update the properties of the structural layer. + updateLayerPosition(); + updateLayerSize(); + updateAnchorPoint(); + updateTransform(); + updateChildrenTransform(); + updateBackfaceVisibility(); + + // Set properties of m_layer to their default values, since these are expressed on on the structural layer. + FloatPoint point(m_size.width() / 2.0f, m_size.height() / 2.0f); + FloatPoint3D anchorPoint(0.5f, 0.5f, 0); + m_layer->setPosition(point); + m_layer->setAnchorPoint(anchorPoint); + m_layer->setTransform(TransformationMatrix()); + m_layer->setOpacity(1); + if (m_layerClones) { + LayerMap::const_iterator end = m_layerClones->end(); + for (LayerMap::const_iterator it = m_layerClones->begin(); it != end; ++it) { + PlatformCALayer* currLayer = it->second.get(); + currLayer->setPosition(point); + currLayer->setAnchorPoint(anchorPoint); + currLayer->setTransform(TransformationMatrix()); + currLayer->setOpacity(1); + } + } + + // Move this layer to be a child of the transform layer. + m_layer->superlayer()->replaceSublayer(m_layer.get(), m_structuralLayer.get()); + m_structuralLayer->appendSublayer(m_layer.get()); + + moveOrCopyAnimationsForProperty(Move, AnimatedPropertyWebkitTransform, m_layer.get(), m_structuralLayer.get()); + moveOrCopyAnimationsForProperty(Move, AnimatedPropertyOpacity, m_layer.get(), m_structuralLayer.get()); + + updateSublayerList(); + updateOpacityOnLayer(); +} + +GraphicsLayerCA::StructuralLayerPurpose GraphicsLayerCA::structuralLayerPurpose() const +{ + if (preserves3D()) + return StructuralLayerForPreserves3D; + + if (isReplicated()) + return StructuralLayerForReplicaFlattening; + + return NoStructuralLayer; +} + +void GraphicsLayerCA::updateLayerDrawsContent() +{ + bool needTiledLayer = requiresTiledLayer(m_size); + if (needTiledLayer != m_usingTiledLayer) + swapFromOrToTiledLayer(needTiledLayer); + + if (m_drawsContent) + m_layer->setNeedsDisplay(); + else + m_layer->setContents(0); + + updateDebugIndicators(); +} + +void GraphicsLayerCA::updateAcceleratesDrawing() +{ + m_layer->setAcceleratesDrawing(m_acceleratesDrawing); +} + +void GraphicsLayerCA::updateLayerBackgroundColor() +{ + if (!m_contentsLayer) + return; + + // We never create the contents layer just for background color yet. + if (m_backgroundColorSet) + m_contentsLayer->setBackgroundColor(m_backgroundColor); + else + m_contentsLayer->setBackgroundColor(Color::transparent); +} + +void GraphicsLayerCA::updateContentsImage() +{ + if (m_pendingContentsImage) { + if (!m_contentsLayer.get()) { + m_contentsLayer = PlatformCALayer::create(PlatformCALayer::LayerTypeLayer, this); +#ifndef NDEBUG + m_contentsLayer->setName("Image Layer"); +#endif + setupContentsLayer(m_contentsLayer.get()); + // m_contentsLayer will be parented by updateSublayerList + } + + // FIXME: maybe only do trilinear if the image is being scaled down, + // but then what if the layer size changes? +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + m_contentsLayer->setMinificationFilter(PlatformCALayer::Trilinear); +#endif + m_contentsLayer->setContents(m_pendingContentsImage.get()); + m_pendingContentsImage = 0; + + if (m_contentsLayerClones) { + LayerMap::const_iterator end = m_contentsLayerClones->end(); + for (LayerMap::const_iterator it = m_contentsLayerClones->begin(); it != end; ++it) + it->second->setContents(m_contentsLayer->contents()); + } + + updateContentsRect(); + } else { + // No image. + // m_contentsLayer will be removed via updateSublayerList. + m_contentsLayer = 0; + } +} + +void GraphicsLayerCA::updateContentsMediaLayer() +{ + // Video layer was set as m_contentsLayer, and will get parented in updateSublayerList(). + if (m_contentsLayer) { + setupContentsLayer(m_contentsLayer.get()); + updateContentsRect(); + } +} + +void GraphicsLayerCA::updateContentsCanvasLayer() +{ + // CanvasLayer was set as m_contentsLayer, and will get parented in updateSublayerList(). + if (m_contentsLayer) { + setupContentsLayer(m_contentsLayer.get()); + m_contentsLayer->setNeedsDisplay(); + updateContentsRect(); + } +} + +void GraphicsLayerCA::updateContentsRect() +{ + if (!m_contentsLayer) + return; + + FloatPoint point(m_contentsRect.x(), m_contentsRect.y()); + FloatRect rect(0, 0, m_contentsRect.width(), m_contentsRect.height()); + + m_contentsLayer->setPosition(point); + m_contentsLayer->setBounds(rect); + + if (m_contentsLayerClones) { + LayerMap::const_iterator end = m_contentsLayerClones->end(); + for (LayerMap::const_iterator it = m_contentsLayerClones->begin(); it != end; ++it) { + it->second->setPosition(point); + it->second->setBounds(rect); + } + } +} + +void GraphicsLayerCA::updateMaskLayer() +{ + PlatformCALayer* maskCALayer = m_maskLayer ? static_cast<GraphicsLayerCA*>(m_maskLayer)->primaryLayer() : 0; + m_layer->setMask(maskCALayer); + + LayerMap* maskLayerCloneMap = m_maskLayer ? static_cast<GraphicsLayerCA*>(m_maskLayer)->primaryLayerClones() : 0; + + if (LayerMap* layerCloneMap = m_layerClones.get()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + PlatformCALayer* maskClone = maskLayerCloneMap ? maskLayerCloneMap->get(it->first).get() : 0; + it->second->setMask(maskClone); + } + } +} + +void GraphicsLayerCA::updateReplicatedLayers() +{ + // Clone the descendants of the replicated layer, and parent under us. + ReplicaState replicaState(ReplicaState::ReplicaBranch); + + RefPtr<PlatformCALayer>replicaRoot = replicatedLayerRoot(replicaState); + if (!replicaRoot) + return; + + if (m_structuralLayer) + m_structuralLayer->insertSublayer(replicaRoot.get(), 0); + else + m_layer->insertSublayer(replicaRoot.get(), 0); +} + +// For now, this assumes that layers only ever have one replica, so replicaIndices contains only 0 and 1. +GraphicsLayerCA::CloneID GraphicsLayerCA::ReplicaState::cloneID() const +{ + size_t depth = m_replicaBranches.size(); + + const size_t bitsPerUChar = sizeof(UChar) * 8; + size_t vectorSize = (depth + bitsPerUChar - 1) / bitsPerUChar; + + Vector<UChar> result(vectorSize); + result.fill(0); + + // Create a string from the bit sequence which we can use to identify the clone. + // Note that the string may contain embedded nulls, but that's OK. + for (size_t i = 0; i < depth; ++i) { + UChar& currChar = result[i / bitsPerUChar]; + currChar = (currChar << 1) | m_replicaBranches[i]; + } + + return String::adopt(result); +} + +PassRefPtr<PlatformCALayer> GraphicsLayerCA::replicatedLayerRoot(ReplicaState& replicaState) +{ + // Limit replica nesting, to avoid 2^N explosion of replica layers. + if (!m_replicatedLayer || replicaState.replicaDepth() == ReplicaState::maxReplicaDepth) + return 0; + + GraphicsLayerCA* replicatedLayer = static_cast<GraphicsLayerCA*>(m_replicatedLayer); + + RefPtr<PlatformCALayer> clonedLayerRoot = replicatedLayer->fetchCloneLayers(this, replicaState, RootCloneLevel); + FloatPoint cloneRootPosition = replicatedLayer->positionForCloneRootLayer(); + + // Replica root has no offset or transform + clonedLayerRoot->setPosition(cloneRootPosition); + clonedLayerRoot->setTransform(TransformationMatrix()); + + return clonedLayerRoot; +} + +void GraphicsLayerCA::updateLayerAnimations() +{ + if (m_animationsToProcess.size()) { + AnimationsToProcessMap::const_iterator end = m_animationsToProcess.end(); + for (AnimationsToProcessMap::const_iterator it = m_animationsToProcess.begin(); it != end; ++it) { + const String& currAnimationName = it->first; + AnimationsMap::iterator animationIt = m_runningAnimations.find(currAnimationName); + if (animationIt == m_runningAnimations.end()) + continue; + + const AnimationProcessingAction& processingInfo = it->second; + const Vector<LayerPropertyAnimation>& animations = animationIt->second; + for (size_t i = 0; i < animations.size(); ++i) { + const LayerPropertyAnimation& currAnimation = animations[i]; + switch (processingInfo.action) { + case Remove: + removeCAAnimationFromLayer(currAnimation.m_property, currAnimationName, currAnimation.m_index); + break; + case Pause: + pauseCAAnimationOnLayer(currAnimation.m_property, currAnimationName, currAnimation.m_index, processingInfo.timeOffset); + break; + } + } + + if (processingInfo.action == Remove) + m_runningAnimations.remove(currAnimationName); + } + + m_animationsToProcess.clear(); + } + + size_t numAnimations; + if ((numAnimations = m_uncomittedAnimations.size())) { + for (size_t i = 0; i < numAnimations; ++i) { + const LayerPropertyAnimation& pendingAnimation = m_uncomittedAnimations[i]; + setAnimationOnLayer(pendingAnimation.m_animation.get(), pendingAnimation.m_property, pendingAnimation.m_name, pendingAnimation.m_index, pendingAnimation.m_timeOffset); + + AnimationsMap::iterator it = m_runningAnimations.find(pendingAnimation.m_name); + if (it == m_runningAnimations.end()) { + Vector<LayerPropertyAnimation> animations; + animations.append(pendingAnimation); + m_runningAnimations.add(pendingAnimation.m_name, animations); + } else { + Vector<LayerPropertyAnimation>& animations = it->second; + animations.append(pendingAnimation); + } + } + + m_uncomittedAnimations.clear(); + } +} + +void GraphicsLayerCA::setAnimationOnLayer(PlatformCAAnimation* caAnim, AnimatedPropertyID property, const String& animationName, int index, double timeOffset) +{ + PlatformCALayer* layer = animatedLayer(property); + + if (timeOffset) + caAnim->setBeginTime(CACurrentMediaTime() - timeOffset); + + String animationID = animationIdentifier(animationName, property, index); + + layer->removeAnimationForKey(animationID); + layer->addAnimationForKey(animationID, caAnim); + + if (LayerMap* layerCloneMap = animatedLayerClones(property)) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + // Skip immediate replicas, since they move with the original. + if (m_replicaLayer && isReplicatedRootClone(it->first)) + continue; + + it->second->removeAnimationForKey(animationID); + it->second->addAnimationForKey(animationID, caAnim); + } + } +} + +// Workaround for <rdar://problem/7311367> +static void bug7311367Workaround(PlatformCALayer* transformLayer, const TransformationMatrix& transform) +{ + if (!transformLayer) + return; + + TransformationMatrix caTransform = transform; + caTransform.setM41(caTransform.m41() + 1); + transformLayer->setTransform(caTransform); + + caTransform.setM41(caTransform.m41() - 1); + transformLayer->setTransform(caTransform); +} + +bool GraphicsLayerCA::removeCAAnimationFromLayer(AnimatedPropertyID property, const String& animationName, int index) +{ + PlatformCALayer* layer = animatedLayer(property); + + String animationID = animationIdentifier(animationName, property, index); + + if (!layer->animationForKey(animationID)) + return false; + + layer->removeAnimationForKey(animationID); + bug7311367Workaround(m_structuralLayer.get(), m_transform); + + if (LayerMap* layerCloneMap = animatedLayerClones(property)) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + // Skip immediate replicas, since they move with the original. + if (m_replicaLayer && isReplicatedRootClone(it->first)) + continue; + + it->second ->removeAnimationForKey(animationID); + } + } + return true; +} + +void GraphicsLayerCA::pauseCAAnimationOnLayer(AnimatedPropertyID property, const String& animationName, int index, double timeOffset) +{ + PlatformCALayer* layer = animatedLayer(property); + + String animationID = animationIdentifier(animationName, property, index); + + RefPtr<PlatformCAAnimation> curAnim = layer->animationForKey(animationID); + if (!curAnim) + return; + + // Animations on the layer are immutable, so we have to clone and modify. + RefPtr<PlatformCAAnimation> newAnim = PlatformCAAnimation::create(curAnim.get()); + + newAnim->setSpeed(0); + newAnim->setTimeOffset(timeOffset); + + layer->addAnimationForKey(animationID, newAnim.get()); // This will replace the running animation. + + // Pause the animations on the clones too. + if (LayerMap* layerCloneMap = animatedLayerClones(property)) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + // Skip immediate replicas, since they move with the original. + if (m_replicaLayer && isReplicatedRootClone(it->first)) + continue; + it->second->addAnimationForKey(animationID, newAnim.get()); + } + } +} + +void GraphicsLayerCA::repaintLayerDirtyRects() +{ + if (!m_dirtyRects.size()) + return; + + for (size_t i = 0; i < m_dirtyRects.size(); ++i) + m_layer->setNeedsDisplay(&(m_dirtyRects[i])); + + m_dirtyRects.clear(); +} + +void GraphicsLayerCA::updateContentsNeedsDisplay() +{ + if (m_contentsLayer) + m_contentsLayer->setNeedsDisplay(); +} + +bool GraphicsLayerCA::createAnimationFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, double timeOffset) +{ + ASSERT(valueList.property() != AnimatedPropertyWebkitTransform); + + bool isKeyframe = valueList.size() > 2; + bool valuesOK; + + bool additive = false; + int animationIndex = 0; + + RefPtr<PlatformCAAnimation> caAnimation; + + if (isKeyframe) { + caAnimation = createKeyframeAnimation(animation, valueList.property(), additive); + valuesOK = setAnimationKeyframes(valueList, animation, caAnimation.get()); + } else { + caAnimation = createBasicAnimation(animation, valueList.property(), additive); + valuesOK = setAnimationEndpoints(valueList, animation, caAnimation.get()); + } + + if (!valuesOK) + return false; + + m_uncomittedAnimations.append(LayerPropertyAnimation(caAnimation, animationName, valueList.property(), animationIndex, timeOffset)); + + return true; +} + +bool GraphicsLayerCA::createTransformAnimationsFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, double timeOffset, const IntSize& boxSize) +{ + ASSERT(valueList.property() == AnimatedPropertyWebkitTransform); + + TransformOperationList functionList; + bool listsMatch, hasBigRotation; + fetchTransformOperationList(valueList, functionList, listsMatch, hasBigRotation); + + // We need to fall back to software animation if we don't have setValueFunction:, and + // we would need to animate each incoming transform function separately. This is the + // case if we have a rotation >= 180 or we have more than one transform function. + if ((hasBigRotation || functionList.size() > 1) && !PlatformCAAnimation::supportsValueFunction()) + return false; + + bool validMatrices = true; + + // If functionLists don't match we do a matrix animation, otherwise we do a component hardware animation. + // Also, we can't do component animation unless we have valueFunction, so we need to do matrix animation + // if that's not true as well. + bool isMatrixAnimation = !listsMatch || !PlatformCAAnimation::supportsValueFunction(); + + size_t numAnimations = isMatrixAnimation ? 1 : functionList.size(); + bool isKeyframe = valueList.size() > 2; + + // Iterate through the transform functions, sending an animation for each one. + for (size_t animationIndex = 0; animationIndex < numAnimations; ++animationIndex) { + TransformOperation::OperationType transformOp = isMatrixAnimation ? TransformOperation::MATRIX_3D : functionList[animationIndex]; + RefPtr<PlatformCAAnimation> caAnimation; + +#if defined(BUILDING_ON_LEOPARD) || defined(BUILDING_ON_SNOW_LEOPARD) + // CA applies animations in reverse order (<rdar://problem/7095638>) so we need the last one we add (per property) + // to be non-additive. + bool additive = animationIndex < (numAnimations - 1); +#else + bool additive = animationIndex > 0; +#endif + if (isKeyframe) { + caAnimation = createKeyframeAnimation(animation, valueList.property(), additive); + validMatrices = setTransformAnimationKeyframes(valueList, animation, caAnimation.get(), animationIndex, transformOp, isMatrixAnimation, boxSize); + } else { + caAnimation = createBasicAnimation(animation, valueList.property(), additive); + validMatrices = setTransformAnimationEndpoints(valueList, animation, caAnimation.get(), animationIndex, transformOp, isMatrixAnimation, boxSize); + } + + if (!validMatrices) + break; + + m_uncomittedAnimations.append(LayerPropertyAnimation(caAnimation, animationName, valueList.property(), animationIndex, timeOffset)); + } + + return validMatrices; +} + +PassRefPtr<PlatformCAAnimation> GraphicsLayerCA::createBasicAnimation(const Animation* anim, AnimatedPropertyID property, bool additive) +{ + RefPtr<PlatformCAAnimation> basicAnim = PlatformCAAnimation::create(PlatformCAAnimation::Basic, propertyIdToString(property)); + setupAnimation(basicAnim.get(), anim, additive); + return basicAnim; +} + +PassRefPtr<PlatformCAAnimation>GraphicsLayerCA::createKeyframeAnimation(const Animation* anim, AnimatedPropertyID property, bool additive) +{ + RefPtr<PlatformCAAnimation> keyframeAnim = PlatformCAAnimation::create(PlatformCAAnimation::Keyframe, propertyIdToString(property)); + setupAnimation(keyframeAnim.get(), anim, additive); + return keyframeAnim; +} + +void GraphicsLayerCA::setupAnimation(PlatformCAAnimation* propertyAnim, const Animation* anim, bool additive) +{ + double duration = anim->duration(); + if (duration <= 0) + duration = cAnimationAlmostZeroDuration; + + float repeatCount = anim->iterationCount(); + if (repeatCount == Animation::IterationCountInfinite) + repeatCount = FLT_MAX; + else if (anim->direction() == Animation::AnimationDirectionAlternate) + repeatCount /= 2; + + PlatformCAAnimation::FillModeType fillMode = PlatformCAAnimation::NoFillMode; + switch (anim->fillMode()) { + case AnimationFillModeNone: + fillMode = PlatformCAAnimation::Forwards; // Use "forwards" rather than "removed" because the style system will remove the animation when it is finished. This avoids a flash. + break; + case AnimationFillModeBackwards: + fillMode = PlatformCAAnimation::Both; // Use "both" rather than "backwards" because the style system will remove the animation when it is finished. This avoids a flash. + break; + case AnimationFillModeForwards: + fillMode = PlatformCAAnimation::Forwards; + break; + case AnimationFillModeBoth: + fillMode = PlatformCAAnimation::Both; + break; + } + + propertyAnim->setDuration(duration); + propertyAnim->setRepeatCount(repeatCount); + propertyAnim->setAutoreverses(anim->direction()); + propertyAnim->setRemovedOnCompletion(false); + propertyAnim->setAdditive(additive); + propertyAnim->setFillMode(fillMode); +} + +const TimingFunction* GraphicsLayerCA::timingFunctionForAnimationValue(const AnimationValue* animValue, const Animation* anim) +{ + if (animValue->timingFunction()) + return animValue->timingFunction(); + if (anim->isTimingFunctionSet()) + return anim->timingFunction().get(); + + return 0; +} + +bool GraphicsLayerCA::setAnimationEndpoints(const KeyframeValueList& valueList, const Animation* anim, PlatformCAAnimation* basicAnim) +{ + switch (valueList.property()) { + case AnimatedPropertyOpacity: { + basicAnim->setFromValue(static_cast<const FloatAnimationValue*>(valueList.at(0))->value()); + basicAnim->setToValue(static_cast<const FloatAnimationValue*>(valueList.at(1))->value()); + break; + } + default: + ASSERT_NOT_REACHED(); // we don't animate color yet + break; + } + + // This codepath is used for 2-keyframe animations, so we still need to look in the start + // for a timing function. + const TimingFunction* timingFunction = timingFunctionForAnimationValue(valueList.at(0), anim); + if (timingFunction) + basicAnim->setTimingFunction(timingFunction); + + return true; +} + +bool GraphicsLayerCA::setAnimationKeyframes(const KeyframeValueList& valueList, const Animation* anim, PlatformCAAnimation* keyframeAnim) +{ + Vector<float> keyTimes; + Vector<float> values; + Vector<const TimingFunction*> timingFunctions; + + for (unsigned i = 0; i < valueList.size(); ++i) { + const AnimationValue* curValue = valueList.at(i); + keyTimes.append(curValue->keyTime()); + + switch (valueList.property()) { + case AnimatedPropertyOpacity: { + const FloatAnimationValue* floatValue = static_cast<const FloatAnimationValue*>(curValue); + values.append(floatValue->value()); + break; + } + default: + ASSERT_NOT_REACHED(); // we don't animate color yet + break; + } + + timingFunctions.append(timingFunctionForAnimationValue(curValue, anim)); + } + + // We toss the last tfArray value because it has to one shorter than the others. + timingFunctions.removeLast(); + + keyframeAnim->setKeyTimes(keyTimes); + keyframeAnim->setValues(values); + keyframeAnim->setTimingFunctions(timingFunctions); + + return true; +} + +bool GraphicsLayerCA::setTransformAnimationEndpoints(const KeyframeValueList& valueList, const Animation* anim, PlatformCAAnimation* basicAnim, int functionIndex, TransformOperation::OperationType transformOpType, bool isMatrixAnimation, const IntSize& boxSize) +{ + ASSERT(valueList.size() == 2); + const TransformAnimationValue* startValue = static_cast<const TransformAnimationValue*>(valueList.at(0)); + const TransformAnimationValue* endValue = static_cast<const TransformAnimationValue*>(valueList.at(1)); + + if (isMatrixAnimation) { + TransformationMatrix fromTransform, toTransform; + startValue->value()->apply(boxSize, fromTransform); + endValue->value()->apply(boxSize, toTransform); + + // If any matrix is singular, CA won't animate it correctly. So fall back to software animation + if (!fromTransform.isInvertible() || !toTransform.isInvertible()) + return false; + + basicAnim->setFromValue(fromTransform); + basicAnim->setToValue(toTransform); + } else { + if (isTransformTypeNumber(transformOpType)) { + float value; + getTransformFunctionValue(startValue->value()->at(functionIndex), transformOpType, boxSize, value); + basicAnim->setFromValue(value); + getTransformFunctionValue(endValue->value()->at(functionIndex), transformOpType, boxSize, value); + basicAnim->setToValue(value); + } else if (isTransformTypeFloatPoint3D(transformOpType)) { + FloatPoint3D value; + getTransformFunctionValue(startValue->value()->at(functionIndex), transformOpType, boxSize, value); + basicAnim->setFromValue(value); + getTransformFunctionValue(endValue->value()->at(functionIndex), transformOpType, boxSize, value); + basicAnim->setToValue(value); + } else { + TransformationMatrix value; + getTransformFunctionValue(startValue->value()->at(functionIndex), transformOpType, boxSize, value); + basicAnim->setFromValue(value); + getTransformFunctionValue(endValue->value()->at(functionIndex), transformOpType, boxSize, value); + basicAnim->setToValue(value); + } + } + + // This codepath is used for 2-keyframe animations, so we still need to look in the start + // for a timing function. + const TimingFunction* timingFunction = timingFunctionForAnimationValue(valueList.at(0), anim); + basicAnim->setTimingFunction(timingFunction); + +#if HAVE_MODERN_QUARTZCORE + PlatformCAAnimation::ValueFunctionType valueFunction = getValueFunctionNameForTransformOperation(transformOpType); + if (valueFunction != PlatformCAAnimation::NoValueFunction) + basicAnim->setValueFunction(valueFunction); +#endif + + return true; +} + +bool GraphicsLayerCA::setTransformAnimationKeyframes(const KeyframeValueList& valueList, const Animation* animation, PlatformCAAnimation* keyframeAnim, int functionIndex, TransformOperation::OperationType transformOpType, bool isMatrixAnimation, const IntSize& boxSize) +{ + Vector<float> keyTimes; + Vector<float> floatValues; + Vector<FloatPoint3D> floatPoint3DValues; + Vector<TransformationMatrix> transformationMatrixValues; + Vector<const TimingFunction*> timingFunctions; + + for (unsigned i = 0; i < valueList.size(); ++i) { + const TransformAnimationValue* curValue = static_cast<const TransformAnimationValue*>(valueList.at(i)); + keyTimes.append(curValue->keyTime()); + + if (isMatrixAnimation) { + TransformationMatrix transform; + curValue->value()->apply(boxSize, transform); + + // If any matrix is singular, CA won't animate it correctly. So fall back to software animation + if (!transform.isInvertible()) + return false; + + transformationMatrixValues.append(transform); + } else { + const TransformOperation* transformOp = curValue->value()->at(functionIndex); + if (isTransformTypeNumber(transformOpType)) { + float value; + getTransformFunctionValue(transformOp, transformOpType, boxSize, value); + floatValues.append(value); + } else if (isTransformTypeFloatPoint3D(transformOpType)) { + FloatPoint3D value; + getTransformFunctionValue(transformOp, transformOpType, boxSize, value); + floatPoint3DValues.append(value); + } else { + TransformationMatrix value; + getTransformFunctionValue(transformOp, transformOpType, boxSize, value); + transformationMatrixValues.append(value); + } + } + + const TimingFunction* timingFunction = timingFunctionForAnimationValue(curValue, animation); + timingFunctions.append(timingFunction); + } + + // We toss the last tfArray value because it has to one shorter than the others. + timingFunctions.removeLast(); + + keyframeAnim->setKeyTimes(keyTimes); + + if (isTransformTypeNumber(transformOpType)) + keyframeAnim->setValues(floatValues); + else if (isTransformTypeFloatPoint3D(transformOpType)) + keyframeAnim->setValues(floatPoint3DValues); + else + keyframeAnim->setValues(transformationMatrixValues); + + keyframeAnim->setTimingFunctions(timingFunctions); + +#if HAVE_MODERN_QUARTZCORE + PlatformCAAnimation::ValueFunctionType valueFunction = getValueFunctionNameForTransformOperation(transformOpType); + if (valueFunction != PlatformCAAnimation::NoValueFunction) + keyframeAnim->setValueFunction(valueFunction); +#endif + return true; +} + +void GraphicsLayerCA::suspendAnimations(double time) +{ + double t = currentTimeToMediaTime(time ? time : currentTime()); + primaryLayer()->setSpeed(0); + primaryLayer()->setTimeOffset(t); + + // Suspend the animations on the clones too. + if (LayerMap* layerCloneMap = primaryLayerClones()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + it->second->setSpeed(0); + it->second->setTimeOffset(t); + } + } +} + +void GraphicsLayerCA::resumeAnimations() +{ + primaryLayer()->setSpeed(1); + primaryLayer()->setTimeOffset(0); + + // Resume the animations on the clones too. + if (LayerMap* layerCloneMap = primaryLayerClones()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + it->second->setSpeed(1); + it->second->setTimeOffset(0); + } + } +} + +PlatformCALayer* GraphicsLayerCA::hostLayerForSublayers() const +{ + return m_structuralLayer.get() ? m_structuralLayer.get() : m_layer.get(); +} + +PlatformCALayer* GraphicsLayerCA::layerForSuperlayer() const +{ + return m_structuralLayer ? m_structuralLayer.get() : m_layer.get(); +} + +PlatformCALayer* GraphicsLayerCA::animatedLayer(AnimatedPropertyID property) const +{ + return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayer.get() : primaryLayer(); +} + +GraphicsLayerCA::LayerMap* GraphicsLayerCA::animatedLayerClones(AnimatedPropertyID property) const +{ + return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayerClones.get() : primaryLayerClones(); +} + +void GraphicsLayerCA::setDebugBackgroundColor(const Color& color) +{ + if (color.isValid()) + m_layer->setBackgroundColor(color); + else + m_layer->setBackgroundColor(Color::transparent); +} + +void GraphicsLayerCA::setDebugBorder(const Color& color, float borderWidth) +{ + if (color.isValid()) { + m_layer->setBorderColor(color); + m_layer->setBorderWidth(borderWidth); + } else { + m_layer->setBorderColor(Color::transparent); + m_layer->setBorderWidth(0); + } +} + +FloatSize GraphicsLayerCA::constrainedSize() const +{ + float tileColumns = ceilf(m_size.width() / kTiledLayerTileSize); + float tileRows = ceilf(m_size.height() / kTiledLayerTileSize); + double numTiles = tileColumns * tileRows; + + FloatSize constrainedSize = m_size; + const unsigned cMaxTileCount = 512; + while (numTiles > cMaxTileCount) { + // Constrain the wider dimension. + if (constrainedSize.width() >= constrainedSize.height()) { + tileColumns = max(floorf(cMaxTileCount / tileRows), 1.0f); + constrainedSize.setWidth(tileColumns * kTiledLayerTileSize); + } else { + tileRows = max(floorf(cMaxTileCount / tileColumns), 1.0f); + constrainedSize.setHeight(tileRows * kTiledLayerTileSize); + } + numTiles = tileColumns * tileRows; + } + + return constrainedSize; +} + +bool GraphicsLayerCA::requiresTiledLayer(const FloatSize& size) const +{ + if (!m_drawsContent) + return false; + + // FIXME: catch zero-size height or width here (or earlier)? + return size.width() > cMaxPixelDimension || size.height() > cMaxPixelDimension; +} + +void GraphicsLayerCA::swapFromOrToTiledLayer(bool useTiledLayer) +{ + if (useTiledLayer == m_usingTiledLayer) + return; + + RefPtr<PlatformCALayer> oldLayer = m_layer; + + m_layer = PlatformCALayer::create(useTiledLayer ? PlatformCALayer::LayerTypeWebTiledLayer : PlatformCALayer::LayerTypeWebLayer, this); + + m_usingTiledLayer = useTiledLayer; + + if (useTiledLayer) { +#if !HAVE_MODERN_QUARTZCORE + // Tiled layer has issues with flipped coordinates. + setContentsOrientation(CompositingCoordinatesTopDown); +#endif + } else { +#if !HAVE_MODERN_QUARTZCORE + setContentsOrientation(GraphicsLayerCA::defaultContentsOrientation()); +#endif + } + + m_layer->adoptSublayers(oldLayer.get()); + + oldLayer->superlayer()->replaceSublayer(oldLayer.get(), m_layer.get()); + + updateContentsTransform(); + + updateLayerPosition(); + updateLayerSize(); + updateAnchorPoint(); + updateTransform(); + updateChildrenTransform(); + updateMasksToBounds(); + updateContentsOpaque(); + updateBackfaceVisibility(); + updateLayerBackgroundColor(); + + updateOpacityOnLayer(); + +#ifndef NDEBUG + String name = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + m_name; + m_layer->setName(name); +#endif + + // move over animations + moveOrCopyAnimationsForProperty(Move, AnimatedPropertyWebkitTransform, oldLayer.get(), m_layer.get()); + moveOrCopyAnimationsForProperty(Move, AnimatedPropertyOpacity, oldLayer.get(), m_layer.get()); + moveOrCopyAnimationsForProperty(Move, AnimatedPropertyBackgroundColor, oldLayer.get(), m_layer.get()); + + // need to tell new layer to draw itself + setNeedsDisplay(); + + updateDebugIndicators(); +} + +GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayerCA::defaultContentsOrientation() const +{ +#if !HAVE_MODERN_QUARTZCORE + // Older QuartzCore does not support -geometryFlipped, so we manually flip the root + // layer geometry, and then flip the contents of each layer back so that the CTM for CG + // is unflipped, allowing it to do the correct font auto-hinting. + return CompositingCoordinatesBottomUp; +#else + return CompositingCoordinatesTopDown; +#endif +} + +void GraphicsLayerCA::updateContentsTransform() +{ +#if !HAVE_MODERN_QUARTZCORE + if (contentsOrientation() == CompositingCoordinatesBottomUp) { + CGAffineTransform contentsTransform = CGAffineTransformMakeScale(1, -1); + contentsTransform = CGAffineTransformTranslate(contentsTransform, 0, -m_layer->bounds().size().height()); + m_layer->setContentsTransform(TransformationMatrix(contentsTransform)); + } +#endif +} + +void GraphicsLayerCA::setupContentsLayer(PlatformCALayer* contentsLayer) +{ + // Turn off implicit animations on the inner layer. + contentsLayer->setMasksToBounds(true); + + if (defaultContentsOrientation() == CompositingCoordinatesBottomUp) { + TransformationMatrix flipper( + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); + contentsLayer->setTransform(flipper); + contentsLayer->setAnchorPoint(FloatPoint3D(0, 1, 0)); + } else + contentsLayer->setAnchorPoint(FloatPoint3D()); + + if (showDebugBorders()) { + contentsLayer->setBorderColor(Color(0, 0, 128, 180)); + contentsLayer->setBorderWidth(1.0f); + } +} + +PassRefPtr<PlatformCALayer> GraphicsLayerCA::findOrMakeClone(CloneID cloneID, PlatformCALayer *sourceLayer, LayerMap* clones, CloneLevel cloneLevel) +{ + if (!sourceLayer) + return 0; + + RefPtr<PlatformCALayer> resultLayer; + + // Add with a dummy value to get an iterator for the insertion position, and a boolean that tells + // us whether there's an item there. This technique avoids two hash lookups. + RefPtr<PlatformCALayer> dummy; + pair<LayerMap::iterator, bool> addResult = clones->add(cloneID, dummy); + if (!addResult.second) { + // Value was not added, so it exists already. + resultLayer = addResult.first->second.get(); + } else { + resultLayer = cloneLayer(sourceLayer, cloneLevel); +#ifndef NDEBUG + resultLayer->setName(String::format("Clone %d of layer %p", cloneID[0U], sourceLayer)); +#endif + addResult.first->second = resultLayer; + } + + return resultLayer; +} + +void GraphicsLayerCA::ensureCloneLayers(CloneID cloneID, RefPtr<PlatformCALayer>& primaryLayer, RefPtr<PlatformCALayer>& structuralLayer, RefPtr<PlatformCALayer>& contentsLayer, CloneLevel cloneLevel) +{ + structuralLayer = 0; + contentsLayer = 0; + + if (!m_layerClones) + m_layerClones = new LayerMap; + + if (!m_structuralLayerClones && m_structuralLayer) + m_structuralLayerClones = new LayerMap; + + if (!m_contentsLayerClones && m_contentsLayer) + m_contentsLayerClones = new LayerMap; + + primaryLayer = findOrMakeClone(cloneID, m_layer.get(), m_layerClones.get(), cloneLevel); + structuralLayer = findOrMakeClone(cloneID, m_structuralLayer.get(), m_structuralLayerClones.get(), cloneLevel); + contentsLayer = findOrMakeClone(cloneID, m_contentsLayer.get(), m_contentsLayerClones.get(), cloneLevel); +} + +void GraphicsLayerCA::removeCloneLayers() +{ + m_layerClones = 0; + m_structuralLayerClones = 0; + m_contentsLayerClones = 0; +} + +FloatPoint GraphicsLayerCA::positionForCloneRootLayer() const +{ + // This can get called during a sync when we've just removed the m_replicaLayer. + if (!m_replicaLayer) + return FloatPoint(); + + FloatPoint replicaPosition = m_replicaLayer->replicatedLayerPosition(); + return FloatPoint(replicaPosition.x() + m_anchorPoint.x() * m_size.width(), + replicaPosition.y() + m_anchorPoint.y() * m_size.height()); +} + +void GraphicsLayerCA::propagateLayerChangeToReplicas() +{ + for (GraphicsLayer* currLayer = this; currLayer; currLayer = currLayer->parent()) { + GraphicsLayerCA* currLayerCA = static_cast<GraphicsLayerCA*>(currLayer); + if (!currLayerCA->hasCloneLayers()) + break; + + if (currLayerCA->replicaLayer()) + static_cast<GraphicsLayerCA*>(currLayerCA->replicaLayer())->noteLayerPropertyChanged(ReplicatedLayerChanged); + } +} + +PassRefPtr<PlatformCALayer> GraphicsLayerCA::fetchCloneLayers(GraphicsLayer* replicaRoot, ReplicaState& replicaState, CloneLevel cloneLevel) +{ + RefPtr<PlatformCALayer> primaryLayer; + RefPtr<PlatformCALayer> structuralLayer; + RefPtr<PlatformCALayer> contentsLayer; + ensureCloneLayers(replicaState.cloneID(), primaryLayer, structuralLayer, contentsLayer, cloneLevel); + + if (m_maskLayer) { + RefPtr<PlatformCALayer> maskClone = static_cast<GraphicsLayerCA*>(m_maskLayer)->fetchCloneLayers(replicaRoot, replicaState, IntermediateCloneLevel); + primaryLayer->setMask(maskClone.get()); + } + + if (m_replicatedLayer) { + // We are a replica being asked for clones of our layers. + RefPtr<PlatformCALayer> replicaRoot = replicatedLayerRoot(replicaState); + if (!replicaRoot) + return 0; + + if (structuralLayer) { + structuralLayer->insertSublayer(replicaRoot.get(), 0); + return structuralLayer; + } + + primaryLayer->insertSublayer(replicaRoot.get(), 0); + return primaryLayer; + } + + const Vector<GraphicsLayer*>& childLayers = children(); + Vector<RefPtr<PlatformCALayer> > clonalSublayers; + + RefPtr<PlatformCALayer> replicaLayer; + + if (m_replicaLayer && m_replicaLayer != replicaRoot) { + // We have nested replicas. Ask the replica layer for a clone of its contents. + replicaState.setBranchType(ReplicaState::ReplicaBranch); + replicaLayer = static_cast<GraphicsLayerCA*>(m_replicaLayer)->fetchCloneLayers(replicaRoot, replicaState, RootCloneLevel); + replicaState.setBranchType(ReplicaState::ChildBranch); + } + + if (replicaLayer || structuralLayer || contentsLayer || childLayers.size() > 0) { + if (structuralLayer) { + // Replicas render behind the actual layer content. + if (replicaLayer) + clonalSublayers.append(replicaLayer); + + // Add the primary layer next. Even if we have negative z-order children, the primary layer always comes behind. + clonalSublayers.append(primaryLayer); + } else if (contentsLayer) { + // FIXME: add the contents layer in the correct order with negative z-order children. + // This does not cause visible rendering issues because currently contents layers are only used + // for replaced elements that don't have children. + clonalSublayers.append(contentsLayer); + } + + replicaState.push(ReplicaState::ChildBranch); + + size_t numChildren = childLayers.size(); + for (size_t i = 0; i < numChildren; ++i) { + GraphicsLayerCA* curChild = static_cast<GraphicsLayerCA*>(childLayers[i]); + + RefPtr<PlatformCALayer> childLayer = curChild->fetchCloneLayers(replicaRoot, replicaState, IntermediateCloneLevel); + if (childLayer) + clonalSublayers.append(childLayer); + } + + replicaState.pop(); + + for (size_t i = 0; i < clonalSublayers.size(); ++i) + clonalSublayers[i]->removeFromSuperlayer(); + } + + RefPtr<PlatformCALayer> result; + if (structuralLayer) { + structuralLayer->setSublayers(clonalSublayers); + + if (contentsLayer) { + // If we have a transform layer, then the contents layer is parented in the + // primary layer (which is itself a child of the transform layer). + primaryLayer->removeAllSublayers(); + primaryLayer->appendSublayer(contentsLayer.get()); + } + + result = structuralLayer; + } else { + primaryLayer->setSublayers(clonalSublayers); + result = primaryLayer; + } + + return result; +} + +PassRefPtr<PlatformCALayer> GraphicsLayerCA::cloneLayer(PlatformCALayer *layer, CloneLevel cloneLevel) +{ + PlatformCALayer::LayerType layerType = (layer->layerType() == PlatformCALayer::LayerTypeTransformLayer) ? + PlatformCALayer::LayerTypeTransformLayer : PlatformCALayer::LayerTypeLayer; + RefPtr<PlatformCALayer> newLayer = PlatformCALayer::create(layerType, this); + + newLayer->setPosition(layer->position()); + newLayer->setBounds(layer->bounds()); + newLayer->setAnchorPoint(layer->anchorPoint()); + newLayer->setTransform(layer->transform()); + newLayer->setSublayerTransform(layer->sublayerTransform()); + newLayer->setContents(layer->contents()); + newLayer->setMasksToBounds(layer->masksToBounds()); + newLayer->setDoubleSided(layer->isDoubleSided()); + newLayer->setOpaque(layer->isOpaque()); + newLayer->setBackgroundColor(layer->backgroundColor()); + + if (cloneLevel == IntermediateCloneLevel) { + newLayer->setOpacity(layer->opacity()); + moveOrCopyAnimationsForProperty(Copy, AnimatedPropertyWebkitTransform, layer, newLayer.get()); + moveOrCopyAnimationsForProperty(Copy, AnimatedPropertyOpacity, layer, newLayer.get()); + } + + if (showDebugBorders()) { + newLayer->setBorderColor(Color(255, 122, 251)); + newLayer->setBorderWidth(2); + } + + return newLayer; +} + +void GraphicsLayerCA::setOpacityInternal(float accumulatedOpacity) +{ + LayerMap* layerCloneMap = 0; + + if (preserves3D()) { + m_layer->setOpacity(accumulatedOpacity); + layerCloneMap = m_layerClones.get(); + } else { + primaryLayer()->setOpacity(accumulatedOpacity); + layerCloneMap = primaryLayerClones(); + } + + if (layerCloneMap) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + if (m_replicaLayer && isReplicatedRootClone(it->first)) + continue; + it->second->setOpacity(m_opacity); + } + } +} + +void GraphicsLayerCA::updateOpacityOnLayer() +{ +#if !HAVE_MODERN_QUARTZCORE + // Distribute opacity either to our own layer or to our children. We pass in the + // contribution from our parent(s). + distributeOpacity(parent() ? parent()->accumulatedOpacity() : 1); +#else + primaryLayer()->setOpacity(m_opacity); + + if (LayerMap* layerCloneMap = primaryLayerClones()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + if (m_replicaLayer && isReplicatedRootClone(it->first)) + continue; + + it->second->setOpacity(m_opacity); + } + + } +#endif +} + +void GraphicsLayerCA::noteSublayersChanged() +{ + noteLayerPropertyChanged(ChildrenChanged); + propagateLayerChangeToReplicas(); +} + +void GraphicsLayerCA::noteLayerPropertyChanged(LayerChangeFlags flags) +{ + if (!m_uncommittedChanges && m_client) + m_client->notifySyncRequired(this); + + m_uncommittedChanges |= flags; +} + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/mac/GraphicsLayerMac.h b/WebCore/platform/graphics/ca/GraphicsLayerCA.h index 5d4dfe2..22921c1 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerMac.h +++ b/WebCore/platform/graphics/ca/GraphicsLayerCA.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Apple Inc. All rights reserved. + * 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 @@ -23,36 +23,38 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef GraphicsLayerMac_h -#define GraphicsLayerMac_h +#ifndef GraphicsLayerCA_h +#define GraphicsLayerCA_h #if USE(ACCELERATED_COMPOSITING) #include "GraphicsLayer.h" -#include "WebLayer.h" +#include "Image.h" +#include "PlatformCAAnimation.h" #include <wtf/HashMap.h> #include <wtf/HashSet.h> #include <wtf/RetainPtr.h> #include <wtf/text/StringHash.h> -@class CABasicAnimation; -@class CAKeyframeAnimation; -@class CAMediaTimingFunction; -@class CAPropertyAnimation; -@class WebAnimationDelegate; - namespace WebCore { -class GraphicsLayerMac : public GraphicsLayer { +class PlatformCALayer; + +class GraphicsLayerCA : public GraphicsLayer { public: + // The width and height of a single tile in a tiled layer. Should be large enough to + // avoid lots of small tiles (and therefore lots of drawing callbacks), but small enough + // to keep the overall tile cost low. + static const int kTiledLayerTileSize = 512; - GraphicsLayerMac(GraphicsLayerClient*); - virtual ~GraphicsLayerMac(); + GraphicsLayerCA(GraphicsLayerClient*); + virtual ~GraphicsLayerCA(); + + virtual void animationStarted(CFTimeInterval beginTime); virtual void setName(const String&); - // for hosting this GraphicsLayer in a native layer hierarchy - virtual NativeLayer nativeLayer() const; + virtual PlatformLayer* platformLayer() const; virtual bool setChildren(const Vector<GraphicsLayer*>&); virtual void addChild(GraphicsLayer*); @@ -77,6 +79,7 @@ public: virtual void setPreserves3D(bool); virtual void setMasksToBounds(bool); virtual void setDrawsContent(bool); + virtual void setAcceleratesDrawing(bool); virtual void setBackgroundColor(const Color&); virtual void clearBackgroundColor(); @@ -106,8 +109,6 @@ public: virtual bool hasContentsLayer() const { return m_contentsLayer; } - virtual PlatformLayer* platformLayer() const; - virtual void setDebugBackgroundColor(const Color&); virtual void setDebugBorder(const Color&, float borderWidth); @@ -118,24 +119,21 @@ public: virtual void syncCompositingState(); virtual void syncCompositingStateForThisLayerOnly(); - // Should only be called by animationDidStart: callback - void animationDidStart(CAAnimation*); - protected: virtual void setOpacityInternal(float); private: void updateOpacityOnLayer(); - CALayer* primaryLayer() const { return m_structuralLayer.get() ? m_structuralLayer.get() : m_layer.get(); } - CALayer* hostLayerForSublayers() const; - CALayer* layerForSuperlayer() const; - CALayer* animatedLayer(AnimatedPropertyID) const; + PlatformCALayer* primaryLayer() const { return m_structuralLayer.get() ? m_structuralLayer.get() : m_layer.get(); } + PlatformCALayer* hostLayerForSublayers() const; + PlatformCALayer* layerForSuperlayer() const; + PlatformCALayer* animatedLayer(AnimatedPropertyID) const; typedef String CloneID; // Identifier for a given clone, based on original/replica branching down the tree. static bool isReplicatedRootClone(const CloneID& cloneID) { return cloneID[0U] & 1; } - typedef HashMap<CloneID, RetainPtr<CALayer> > LayerMap; + typedef HashMap<CloneID, RefPtr<PlatformCALayer> > LayerMap; LayerMap* primaryLayerClones() const { return m_structuralLayer.get() ? m_structuralLayerClones.get() : m_layerClones.get(); } LayerMap* animatedLayerClones(AnimatedPropertyID) const; @@ -143,17 +141,17 @@ private: bool createTransformAnimationsFromKeyframes(const KeyframeValueList&, const Animation*, const String& animationName, double timeOffset, const IntSize& boxSize); // Return autoreleased animation (use RetainPtr?) - CABasicAnimation* createBasicAnimation(const Animation*, AnimatedPropertyID, bool additive); - CAKeyframeAnimation* createKeyframeAnimation(const Animation*, AnimatedPropertyID, bool additive); - void setupAnimation(CAPropertyAnimation*, const Animation*, bool additive); + PassRefPtr<PlatformCAAnimation> createBasicAnimation(const Animation*, AnimatedPropertyID, bool additive); + PassRefPtr<PlatformCAAnimation> createKeyframeAnimation(const Animation*, AnimatedPropertyID, bool additive); + void setupAnimation(PlatformCAAnimation*, const Animation*, bool additive); - CAMediaTimingFunction* timingFunctionForAnimationValue(const AnimationValue*, const Animation*); + const TimingFunction* timingFunctionForAnimationValue(const AnimationValue*, const Animation*); - bool setAnimationEndpoints(const KeyframeValueList&, const Animation*, CABasicAnimation*); - bool setAnimationKeyframes(const KeyframeValueList&, const Animation*, CAKeyframeAnimation*); + bool setAnimationEndpoints(const KeyframeValueList&, const Animation*, PlatformCAAnimation*); + bool setAnimationKeyframes(const KeyframeValueList&, const Animation*, PlatformCAAnimation*); - bool setTransformAnimationEndpoints(const KeyframeValueList&, const Animation*, CABasicAnimation*, int functionIndex, TransformOperation::OperationType, bool isMatrixAnimation, const IntSize& boxSize); - bool setTransformAnimationKeyframes(const KeyframeValueList&, const Animation*, CAKeyframeAnimation*, int functionIndex, TransformOperation::OperationType, bool isMatrixAnimation, const IntSize& boxSize); + bool setTransformAnimationEndpoints(const KeyframeValueList&, const Animation*, PlatformCAAnimation*, int functionIndex, TransformOperation::OperationType, bool isMatrixAnimation, const IntSize& boxSize); + bool setTransformAnimationKeyframes(const KeyframeValueList&, const Animation*, PlatformCAAnimation*, int functionIndex, TransformOperation::OperationType, bool isMatrixAnimation, const IntSize& boxSize); bool animationIsRunning(const String& animationName) const { @@ -171,8 +169,8 @@ private: CompositingCoordinatesOrientation defaultContentsOrientation() const; void updateContentsTransform(); - void setupContentsLayer(CALayer*); - CALayer* contentsLayer() const { return m_contentsLayer.get(); } + void setupContentsLayer(PlatformCALayer*); + PlatformCALayer* contentsLayer() const { return m_contentsLayer.get(); } virtual void setReplicatedByLayer(GraphicsLayer*); @@ -224,15 +222,15 @@ private: Vector<ReplicaBranchType> m_replicaBranches; size_t m_replicaDepth; }; - CALayer *replicatedLayerRoot(ReplicaState&); + PassRefPtr<PlatformCALayer>replicatedLayerRoot(ReplicaState&); enum CloneLevel { RootCloneLevel, IntermediateCloneLevel }; - CALayer *fetchCloneLayers(GraphicsLayer* replicaRoot, ReplicaState&, CloneLevel); + PassRefPtr<PlatformCALayer> fetchCloneLayers(GraphicsLayer* replicaRoot, ReplicaState&, CloneLevel); - CALayer *cloneLayer(CALayer *, CloneLevel); - CALayer *findOrMakeClone(CloneID, CALayer *, LayerMap*, CloneLevel); + PassRefPtr<PlatformCALayer> cloneLayer(PlatformCALayer *, CloneLevel); + PassRefPtr<PlatformCALayer> findOrMakeClone(CloneID, PlatformCALayer *, LayerMap*, CloneLevel); - void ensureCloneLayers(CloneID index, CALayer *& primaryLayer, CALayer *& structuralLayer, CALayer *& contentsLayer, CloneLevel); + void ensureCloneLayers(CloneID cloneID, RefPtr<PlatformCALayer>& primaryLayer, RefPtr<PlatformCALayer>& structuralLayer, RefPtr<PlatformCALayer>& contentsLayer, CloneLevel cloneLevel); bool hasCloneLayers() const { return m_layerClones; } void removeCloneLayers(); @@ -264,6 +262,7 @@ private: void updateLayerAnimations(); void updateContentsNeedsDisplay(); + void updateAcceleratesDrawing(); enum StructuralLayerPurpose { NoStructuralLayer = 0, @@ -273,18 +272,18 @@ private: void ensureStructuralLayer(StructuralLayerPurpose); StructuralLayerPurpose structuralLayerPurpose() const; - void setCAAnimationOnLayer(CAPropertyAnimation*, AnimatedPropertyID, const String& animationName, int index, double timeOffset); + void setAnimationOnLayer(PlatformCAAnimation*, AnimatedPropertyID, const String& animationName, int index, double timeOffset); bool removeCAAnimationFromLayer(AnimatedPropertyID, const String& animationName, int index); void pauseCAAnimationOnLayer(AnimatedPropertyID, const String& animationName, int index, double timeOffset); enum MoveOrCopy { Move, Copy }; - static void moveOrCopyLayerAnimation(MoveOrCopy, const String& animationIdentifier, CALayer *fromLayer, CALayer *toLayer); - void moveOrCopyAnimationsForProperty(MoveOrCopy, AnimatedPropertyID, CALayer * fromLayer, CALayer * toLayer); + static void moveOrCopyLayerAnimation(MoveOrCopy, const String& animationIdentifier, PlatformCALayer *fromLayer, PlatformCALayer *toLayer); + void moveOrCopyAnimationsForProperty(MoveOrCopy, AnimatedPropertyID, PlatformCALayer * fromLayer, PlatformCALayer * toLayer); enum LayerChange { NoChange = 0, NameChanged = 1 << 1, - ChildrenChanged = 1 << 2, // also used for content layer, and preserves-3d, and size if tiling changes? + ChildrenChanged = 1 << 2, // also used for content layer, and preserves-3d, and size if tiling changes? PositionChanged = 1 << 3, AnchorPointChanged = 1 << 4, SizeChanged = 1 << 5, @@ -292,7 +291,7 @@ private: ChildrenTransformChanged = 1 << 7, Preserves3DChanged = 1 << 8, MasksToBoundsChanged = 1 << 9, - DrawsContentChanged = 1 << 10, // need this? + DrawsContentChanged = 1 << 10, // need this? BackgroundColorChanged = 1 << 11, ContentsOpaqueChanged = 1 << 12, BackfaceVisibilityChanged = 1 << 13, @@ -305,7 +304,8 @@ private: ContentsRectChanged = 1 << 20, MaskLayerChanged = 1 << 21, ReplicatedLayerChanged = 1 << 22, - ContentsNeedsDisplay = 1 << 23 + ContentsNeedsDisplay = 1 << 23, + AcceleratesDrawingChanged = 1 << 24 }; typedef unsigned LayerChangeFlags; void noteLayerPropertyChanged(LayerChangeFlags flags); @@ -313,9 +313,9 @@ private: void repaintLayerDirtyRects(); - RetainPtr<WebLayer> m_layer; // The main layer - RetainPtr<CALayer> m_structuralLayer; // A layer used for structural reasons, like preserves-3d or replica-flattening. Is the parent of m_layer. - RetainPtr<CALayer> m_contentsLayer; // A layer used for inner content, like image and video + RefPtr<PlatformCALayer> m_layer; // The main layer + RefPtr<PlatformCALayer> m_structuralLayer; // A layer used for structural reasons, like preserves-3d or replica-flattening. Is the parent of m_layer. + RefPtr<PlatformCALayer> m_contentsLayer; // A layer used for inner content, like image and video // References to clones of our layers, for replicated layers. OwnPtr<LayerMap> m_layerClones; @@ -332,15 +332,13 @@ private: ContentsLayerPurpose m_contentsLayerPurpose; bool m_contentsLayerHasBackgroundColor : 1; - RetainPtr<WebAnimationDelegate> m_animationDelegate; - RetainPtr<CGImageRef> m_uncorrectedContentsImage; RetainPtr<CGImageRef> m_pendingContentsImage; // This represents the animation of a single property. There may be multiple transform animations for // a single transition or keyframe animation, so index is used to distinguish these. struct LayerPropertyAnimation { - LayerPropertyAnimation(CAPropertyAnimation* caAnimation, const String& animationName, AnimatedPropertyID property, int index, double timeOffset) + LayerPropertyAnimation(PassRefPtr<PlatformCAAnimation> caAnimation, const String& animationName, AnimatedPropertyID property, int index, double timeOffset) : m_animation(caAnimation) , m_name(animationName) , m_property(property) @@ -348,7 +346,7 @@ private: , m_timeOffset(timeOffset) { } - RetainPtr<CAPropertyAnimation*> m_animation; + RefPtr<PlatformCAAnimation> m_animation; String m_name; AnimatedPropertyID m_property; int m_index; @@ -385,4 +383,4 @@ private: #endif // USE(ACCELERATED_COMPOSITING) -#endif // GraphicsLayerMac_h +#endif // GraphicsLayerCA_h diff --git a/WebCore/platform/graphics/ca/PlatformCAAnimation.h b/WebCore/platform/graphics/ca/PlatformCAAnimation.h new file mode 100644 index 0000000..d802700 --- /dev/null +++ b/WebCore/platform/graphics/ca/PlatformCAAnimation.h @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PlatformCAAnimation_h +#define PlatformCAAnimation_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "Color.h" +#include "FloatPoint3D.h" +#include "TransformationMatrix.h" +#include <wtf/RefCounted.h> +#include <wtf/RetainPtr.h> +#include <wtf/Vector.h> + +#if PLATFORM(MAC) +#ifdef __OBJC__ +@class CAPropertyAnimation; +typedef CAPropertyAnimation* PlatformAnimationRef; +#else +typedef void* CAPropertyAnimation; // So the m_animation declaration works +typedef void* PlatformAnimationRef; +#endif +#elif PLATFORM(WIN) +namespace WebCore { +class WKCACFAnimation; +typedef WKCACFAnimation* PlatformAnimationRef; +} +#endif + +namespace WebCore { + +class FloatRect; +class PlatformCAAnimation; +class TimingFunction; + +class PlatformCAAnimation : public RefCounted<PlatformCAAnimation> { +public: + friend class PlatformCALayer; + + enum AnimationType { Basic, Keyframe }; + enum FillModeType { NoFillMode, Forwards, Backwards, Both }; + enum ValueFunctionType { NoValueFunction, RotateX, RotateY, RotateZ, ScaleX, ScaleY, ScaleZ, Scale, TranslateX, TranslateY, TranslateZ, Translate }; + + static PassRefPtr<PlatformCAAnimation> create(AnimationType, const String& keyPath); + static PassRefPtr<PlatformCAAnimation> create(PlatformAnimationRef animation); + static PassRefPtr<PlatformCAAnimation> create(const PlatformCAAnimation* animation); + + ~PlatformCAAnimation(); + + static bool supportsValueFunction(); + + PlatformAnimationRef platformAnimation() const; + + AnimationType animationType() const { return m_type; } + String keyPath() const; + + CFTimeInterval beginTime() const; + void setBeginTime(CFTimeInterval); + + CFTimeInterval duration() const; + void setDuration(CFTimeInterval); + + float speed() const; + void setSpeed(float); + + CFTimeInterval timeOffset() const; + void setTimeOffset(CFTimeInterval); + + float repeatCount() const; + void setRepeatCount(float); + + bool autoreverses() const; + void setAutoreverses(bool); + + FillModeType fillMode() const; + void setFillMode(FillModeType); + + void setTimingFunction(const TimingFunction*); + void copyTimingFunctionFrom(const PlatformCAAnimation*); + + bool isRemovedOnCompletion() const; + void setRemovedOnCompletion(bool); + + bool isAdditive() const; + void setAdditive(bool); + + ValueFunctionType valueFunction() const; + void setValueFunction(ValueFunctionType); + + // Basic-animation properties. + void setFromValue(float); + void setFromValue(const WebCore::TransformationMatrix&); + void setFromValue(const FloatPoint3D&); + void setFromValue(const WebCore::Color&); + void copyFromValueFrom(const PlatformCAAnimation*); + + void setToValue(float); + void setToValue(const WebCore::TransformationMatrix&); + void setToValue(const FloatPoint3D&); + void setToValue(const WebCore::Color&); + void copyToValueFrom(const PlatformCAAnimation*); + + // Keyframe-animation properties. + void setValues(const Vector<float>&); + void setValues(const Vector<WebCore::TransformationMatrix>&); + void setValues(const Vector<FloatPoint3D>&); + void setValues(const Vector<WebCore::Color>&); + void copyValuesFrom(const PlatformCAAnimation*); + + void setKeyTimes(const Vector<float>&); + void copyKeyTimesFrom(const PlatformCAAnimation*); + + void setTimingFunctions(const Vector<const TimingFunction*>&); + void copyTimingFunctionsFrom(const PlatformCAAnimation*); + +protected: + PlatformCAAnimation(AnimationType, const String& keyPath); + PlatformCAAnimation(PlatformAnimationRef animation); + PlatformCAAnimation(const PlatformCAAnimation* animation); + +private: + AnimationType m_type; + +#if PLATFORM(MAC) + RetainPtr<CAPropertyAnimation> m_animation; +#elif PLATFORM(WIN) + RetainPtr<CACFAnimationRef> m_animation; +#endif +}; + +} + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // PlatformCAAnimation_h diff --git a/WebCore/platform/graphics/ca/PlatformCALayer.h b/WebCore/platform/graphics/ca/PlatformCALayer.h new file mode 100644 index 0000000..9cf0ccb --- /dev/null +++ b/WebCore/platform/graphics/ca/PlatformCALayer.h @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PlatformCALayer_h +#define PlatformCALayer_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "GraphicsContext.h" +#include "GraphicsLayerCA.h" +#include "PlatformCAAnimation.h" +#include "PlatformString.h" +#include <wtf/HashMap.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RetainPtr.h> +#include <wtf/Vector.h> +#include <wtf/text/StringHash.h> + +namespace WebCore { + +class PlatformCALayer; + +typedef Vector<RefPtr<PlatformCALayer> > PlatformCALayerList; + +class PlatformCALayer : public RefCounted<PlatformCALayer> { +public: + // TiledLayer used in GraphicsLayer has constant settings: + // cTiledLayerTileSize = 512 + // setTileSize:(cTiledLayerTileSize, cTiledLayerTileSize) + // setLevelsOfDetail:1 + // setLevelsOfDetailBias:0 + // setContentsGravity:@"bottomLeft" + // + // TiledLayer also has drawing functions like WebLayer + // + // WebLayer is a CALayer with drawing functions specific to WebKit + // + // Layer and TransformLayer are used as is + + enum LayerType { LayerTypeLayer, LayerTypeWebLayer, LayerTypeTransformLayer, LayerTypeWebTiledLayer, LayerTypeCustom }; + enum FilterType { Linear, Nearest, Trilinear }; + + static PassRefPtr<PlatformCALayer> create(LayerType, GraphicsLayerCA*); + + // This function passes the layer as a void* rather than a PlatformLayer because PlatformLayer + // is defined differently for Obj C and C++. This allows callers from both languages. + static PassRefPtr<PlatformCALayer> create(void* platformLayer, GraphicsLayerCA*); + + ~PlatformCALayer(); + + // This function passes the layer as a void* rather than a PlatformLayer because PlatformLayer + // is defined differently for Obj C and C++. This allows callers from both languages. + static PlatformCALayer* platformCALayer(void* platformLayer); + + PlatformLayer* platformLayer() const; + + static bool isValueFunctionSupported(); + + GraphicsLayerCA* owner() const { return m_owner; } + void setOwner(GraphicsLayerCA* owner); + + void animationStarted(CFTimeInterval beginTime) + { + if (m_owner) + m_owner->animationStarted(beginTime); + } + + void setNeedsDisplay(const FloatRect* dirtyRect = 0); + + void setContentsChanged(); + + LayerType layerType() const { return m_layerType; } + + PlatformCALayer* superlayer() const; + void removeFromSuperlayer(); + void setSublayers(const PlatformCALayerList&); + void removeAllSublayers(); + void appendSublayer(PlatformCALayer*); + void insertSublayer(PlatformCALayer*, size_t index); + void replaceSublayer(PlatformCALayer* reference, PlatformCALayer*); + size_t sublayerCount() const; + + // This method removes the sublayers from the source and reparents them to the current layer. + void adoptSublayers(PlatformCALayer* source); + + void addAnimationForKey(const String& key, PlatformCAAnimation* animation); + void removeAnimationForKey(const String& key); + PassRefPtr<PlatformCAAnimation> animationForKey(const String& key); + + PlatformCALayer* mask() const; + void setMask(PlatformCALayer*); + + bool isOpaque() const; + void setOpaque(bool); + + FloatRect bounds() const; + void setBounds(const FloatRect&); + + FloatPoint3D position() const; + void setPosition(const FloatPoint3D&); + void setPosition(const FloatPoint& pos) { setPosition(FloatPoint3D(pos.x(), pos.y(), 0)); } + + FloatPoint3D anchorPoint() const; + void setAnchorPoint(const FloatPoint3D&); + + TransformationMatrix transform() const; + void setTransform(const TransformationMatrix&); + + TransformationMatrix sublayerTransform() const; + void setSublayerTransform(const TransformationMatrix&); + + TransformationMatrix contentsTransform() const; + void setContentsTransform(const TransformationMatrix&); + + bool isHidden() const; + void setHidden(bool); + + bool isGeometryFlipped() const; + void setGeometryFlipped(bool); + + bool isDoubleSided() const; + void setDoubleSided(bool); + + bool masksToBounds() const; + void setMasksToBounds(bool); + + bool acceleratesDrawing() const; + void setAcceleratesDrawing(bool); + + void* contents() const; + void setContents(void*); + + FloatRect contentsRect() const; + void setContentsRect(const FloatRect&); + + void setMinificationFilter(FilterType); + void setMagnificationFilter(FilterType); + + Color backgroundColor() const; + void setBackgroundColor(const Color&); + + float borderWidth() const; + void setBorderWidth(float); + + Color borderColor() const; + void setBorderColor(const Color&); + + float opacity() const; + void setOpacity(float); + + String name() const; + void setName(const String&); + + FloatRect frame() const; + void setFrame(const FloatRect&); + + float speed() const; + void setSpeed(float); + + CFTimeInterval timeOffset() const; + void setTimeOffset(CFTimeInterval); + +protected: + PlatformCALayer(LayerType, PlatformLayer*, GraphicsLayerCA*); + +private: + + GraphicsLayerCA* m_owner; + LayerType m_layerType; + +#if PLATFORM(MAC) || PLATFORM(WIN) + RetainPtr<PlatformLayer> m_layer; +#endif + +#if PLATFORM(MAC) +#ifdef __OBJC__ + RetainPtr<NSObject> m_delegate; +#else + RetainPtr<void> m_delegate; +#endif +#endif +}; + +} + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // PlatformCALayer_h diff --git a/WebCore/platform/graphics/ca/TransformationMatrixCA.cpp b/WebCore/platform/graphics/ca/TransformationMatrixCA.cpp new file mode 100644 index 0000000..27805e6 --- /dev/null +++ b/WebCore/platform/graphics/ca/TransformationMatrixCA.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if PLATFORM(CA) + +#include "TransformationMatrix.h" + +#include "FloatConversion.h" + +namespace WebCore { + +TransformationMatrix::TransformationMatrix(const CATransform3D& t) +{ + setMatrix( + t.m11, t.m12, t.m13, t.m14, + t.m21, t.m22, t.m23, t.m24, + t.m31, t.m32, t.m33, t.m34, + t.m41, t.m42, t.m43, t.m44); +} + +TransformationMatrix::operator CATransform3D() const +{ + CATransform3D toT3D; + toT3D.m11 = narrowPrecisionToFloat(m11()); + toT3D.m12 = narrowPrecisionToFloat(m12()); + toT3D.m13 = narrowPrecisionToFloat(m13()); + toT3D.m14 = narrowPrecisionToFloat(m14()); + toT3D.m21 = narrowPrecisionToFloat(m21()); + toT3D.m22 = narrowPrecisionToFloat(m22()); + toT3D.m23 = narrowPrecisionToFloat(m23()); + toT3D.m24 = narrowPrecisionToFloat(m24()); + toT3D.m31 = narrowPrecisionToFloat(m31()); + toT3D.m32 = narrowPrecisionToFloat(m32()); + toT3D.m33 = narrowPrecisionToFloat(m33()); + toT3D.m34 = narrowPrecisionToFloat(m34()); + toT3D.m41 = narrowPrecisionToFloat(m41()); + toT3D.m42 = narrowPrecisionToFloat(m42()); + toT3D.m43 = narrowPrecisionToFloat(m43()); + toT3D.m44 = narrowPrecisionToFloat(m44()); + return toT3D; +} + +} + +#endif // PLATFORM(CA) diff --git a/WebCore/platform/graphics/ca/mac/PlatformCAAnimationMac.mm b/WebCore/platform/graphics/ca/mac/PlatformCAAnimationMac.mm new file mode 100644 index 0000000..2a00857 --- /dev/null +++ b/WebCore/platform/graphics/ca/mac/PlatformCAAnimationMac.mm @@ -0,0 +1,574 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) + +#import "PlatformCAAnimation.h" + +#import "FloatConversion.h" +#import "PlatformString.h" +#import "TimingFunction.h" +#import <QuartzCore/QuartzCore.h> +#import <wtf/UnusedParam.h> + +#define HAVE_MODERN_QUARTZCORE (!defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)) + +using namespace WebCore; + +// This value must be the same as in PlatformCALayerMac.mm +static NSString * const WKNonZeroBeginTimeFlag = @"WKPlatformCAAnimationNonZeroBeginTimeFlag"; + +static bool hasNonZeroBeginTimeFlag(const PlatformCAAnimation* animation) +{ + return [[animation->platformAnimation() valueForKey:WKNonZeroBeginTimeFlag] boolValue]; +} + +static void setNonZeroBeginTimeFlag(PlatformCAAnimation* animation, bool value) +{ + [animation->platformAnimation() setValue:[NSNumber numberWithBool:value] forKey:WKNonZeroBeginTimeFlag]; +} + +static NSString* toCAFillModeType(PlatformCAAnimation::FillModeType type) +{ + switch (type) { + case PlatformCAAnimation::NoFillMode: + case PlatformCAAnimation::Forwards: return kCAFillModeForwards; + case PlatformCAAnimation::Backwards: return kCAFillModeBackwards; + case PlatformCAAnimation::Both: return kCAFillModeBoth; + } + return @""; +} + +static PlatformCAAnimation::FillModeType fromCAFillModeType(NSString* string) +{ + if ([string isEqualToString:kCAFillModeBackwards]) + return PlatformCAAnimation::Backwards; + + if ([string isEqualToString:kCAFillModeBoth]) + return PlatformCAAnimation::Both; + + return PlatformCAAnimation::Forwards; +} + +#if HAVE_MODERN_QUARTZCORE +static NSString* toCAValueFunctionType(PlatformCAAnimation::ValueFunctionType type) +{ + switch (type) { + case PlatformCAAnimation::NoValueFunction: return @""; + case PlatformCAAnimation::RotateX: return kCAValueFunctionRotateX; + case PlatformCAAnimation::RotateY: return kCAValueFunctionRotateY; + case PlatformCAAnimation::RotateZ: return kCAValueFunctionRotateZ; + case PlatformCAAnimation::ScaleX: return kCAValueFunctionScaleX; + case PlatformCAAnimation::ScaleY: return kCAValueFunctionScaleY; + case PlatformCAAnimation::ScaleZ: return kCAValueFunctionScaleZ; + case PlatformCAAnimation::Scale: return kCAValueFunctionScale; + case PlatformCAAnimation::TranslateX: return kCAValueFunctionTranslateX; + case PlatformCAAnimation::TranslateY: return kCAValueFunctionTranslateY; + case PlatformCAAnimation::TranslateZ: return kCAValueFunctionTranslateZ; + case PlatformCAAnimation::Translate: return kCAValueFunctionTranslate; + } + return @""; +} + +static PlatformCAAnimation::ValueFunctionType fromCAValueFunctionType(NSString* string) +{ + if ([string isEqualToString:kCAValueFunctionRotateX]) + return PlatformCAAnimation::RotateX; + + if ([string isEqualToString:kCAValueFunctionRotateY]) + return PlatformCAAnimation::RotateY; + + if ([string isEqualToString:kCAValueFunctionRotateZ]) + return PlatformCAAnimation::RotateZ; + + if ([string isEqualToString:kCAValueFunctionScaleX]) + return PlatformCAAnimation::ScaleX; + + if ([string isEqualToString:kCAValueFunctionScaleY]) + return PlatformCAAnimation::ScaleY; + + if ([string isEqualToString:kCAValueFunctionScaleZ]) + return PlatformCAAnimation::ScaleZ; + + if ([string isEqualToString:kCAValueFunctionScale]) + return PlatformCAAnimation::Scale; + + if ([string isEqualToString:kCAValueFunctionTranslateX]) + return PlatformCAAnimation::TranslateX; + + if ([string isEqualToString:kCAValueFunctionTranslateY]) + return PlatformCAAnimation::TranslateY; + + if ([string isEqualToString:kCAValueFunctionTranslateZ]) + return PlatformCAAnimation::TranslateZ; + + if ([string isEqualToString:kCAValueFunctionTranslate]) + return PlatformCAAnimation::Translate; + + return PlatformCAAnimation::NoValueFunction; +} +#endif + +static CAMediaTimingFunction* toCAMediaTimingFunction(const TimingFunction* timingFunction) +{ + if (!timingFunction) + return [CAMediaTimingFunction functionWithControlPoints:0.25f :0.1f :0.25f :0.1f]; + + if (timingFunction->isCubicBezierTimingFunction()) { + const CubicBezierTimingFunction* ctf = static_cast<const CubicBezierTimingFunction*>(timingFunction); + return [CAMediaTimingFunction functionWithControlPoints:static_cast<float>(ctf->x1()) :static_cast<float>(ctf->y1()) + :static_cast<float>(ctf->x2()) :static_cast<float>(ctf->y2())]; + } + + return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; + + return 0; +} + +PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::create(AnimationType type, const String& keyPath) +{ + return adoptRef(new PlatformCAAnimation(type, keyPath)); +} + +PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::create(PlatformAnimationRef animation) +{ + return adoptRef(new PlatformCAAnimation(animation)); +} + +PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::create(const PlatformCAAnimation* animation) +{ + return adoptRef(new PlatformCAAnimation(animation)); +} + +PlatformCAAnimation::PlatformCAAnimation(AnimationType type, const String& keyPath) + : m_type(type) +{ + if (type == Basic) + m_animation.adoptNS([[CABasicAnimation animationWithKeyPath:keyPath] retain]); + else + m_animation.adoptNS([[CAKeyframeAnimation animationWithKeyPath:keyPath] retain]); +} + +PlatformCAAnimation::PlatformCAAnimation(PlatformAnimationRef animation) +{ + if ([static_cast<CAAnimation*>(animation) isKindOfClass:[CABasicAnimation class]]) + m_type = Basic; + else if ([static_cast<CAAnimation*>(animation) isKindOfClass:[CAKeyframeAnimation class]]) + m_type = Keyframe; + else { + ASSERT(0); + return; + } + + m_animation = static_cast<CAPropertyAnimation*>(animation); +} + +PlatformCAAnimation::PlatformCAAnimation(const PlatformCAAnimation* animation) +{ + PlatformCAAnimation* newAnimation = new PlatformCAAnimation(animation->animationType(), animation->keyPath()); + + newAnimation->setBeginTime(animation->beginTime()); + newAnimation->setDuration(animation->duration()); + newAnimation->setSpeed(animation->speed()); + newAnimation->setTimeOffset(animation->timeOffset()); + newAnimation->setRepeatCount(animation->repeatCount()); + newAnimation->setAutoreverses(animation->autoreverses()); + newAnimation->setFillMode(animation->fillMode()); + newAnimation->setRemovedOnCompletion(animation->isRemovedOnCompletion()); + newAnimation->setAdditive(animation->isAdditive()); + newAnimation->copyTimingFunctionFrom(animation); + +#if HAVE_MODERN_QUARTZCORE + newAnimation->setValueFunction(animation->valueFunction()); +#endif + + setNonZeroBeginTimeFlag(newAnimation, hasNonZeroBeginTimeFlag(animation)); + + // Copy the specific Basic or Keyframe values + if (animation->animationType() == Keyframe) { + newAnimation->copyValuesFrom(animation); + newAnimation->copyKeyTimesFrom(animation); + newAnimation->copyTimingFunctionsFrom(animation); + } else { + newAnimation->copyFromValueFrom(animation); + newAnimation->copyToValueFrom(animation); + } +} + +PlatformCAAnimation::~PlatformCAAnimation() +{ +} + +bool PlatformCAAnimation::supportsValueFunction() +{ + static bool sHaveValueFunction = [CAPropertyAnimation instancesRespondToSelector:@selector(setValueFunction:)]; + return sHaveValueFunction; +} + +PlatformAnimationRef PlatformCAAnimation::platformAnimation() const +{ + return m_animation.get(); +} + +String PlatformCAAnimation::keyPath() const +{ + return [m_animation.get() keyPath]; +} + +CFTimeInterval PlatformCAAnimation::beginTime() const +{ + return [m_animation.get() beginTime]; +} + +void PlatformCAAnimation::setBeginTime(CFTimeInterval value) +{ + [m_animation.get() setBeginTime:value]; + + // Also set a flag to tell us if we've passed in a 0 value. + // The flag is needed because later beginTime will get changed + // to the time at which it fired and we need to know whether + // or not it was 0 to begin with. + if (value) + setNonZeroBeginTimeFlag(this, true); +} + +CFTimeInterval PlatformCAAnimation::duration() const +{ + return [m_animation.get() duration]; +} + +void PlatformCAAnimation::setDuration(CFTimeInterval value) +{ + [m_animation.get() setDuration:value]; +} + +float PlatformCAAnimation::speed() const +{ + return [m_animation.get() speed]; +} + +void PlatformCAAnimation::setSpeed(float value) +{ + [m_animation.get() setSpeed:value]; +} + +CFTimeInterval PlatformCAAnimation::timeOffset() const +{ + return [m_animation.get() timeOffset]; +} + +void PlatformCAAnimation::setTimeOffset(CFTimeInterval value) +{ + [m_animation.get() setTimeOffset:value]; +} + +float PlatformCAAnimation::repeatCount() const +{ + return [m_animation.get() repeatCount]; +} + +void PlatformCAAnimation::setRepeatCount(float value) +{ + [m_animation.get() setRepeatCount:value]; +} + +bool PlatformCAAnimation::autoreverses() const +{ + return [m_animation.get() autoreverses]; +} + +void PlatformCAAnimation::setAutoreverses(bool value) +{ + [m_animation.get() setAutoreverses:value]; +} + +PlatformCAAnimation::FillModeType PlatformCAAnimation::fillMode() const +{ + return fromCAFillModeType([m_animation.get() fillMode]); +} + +void PlatformCAAnimation::setFillMode(FillModeType value) +{ + [m_animation.get() setFillMode:toCAFillModeType(value)]; +} + +void PlatformCAAnimation::setTimingFunction(const TimingFunction* value) +{ + [m_animation.get() setTimingFunction:toCAMediaTimingFunction(value)]; +} + +void PlatformCAAnimation::copyTimingFunctionFrom(const PlatformCAAnimation* value) +{ + [m_animation.get() setTimingFunction:[value->m_animation.get() timingFunction]]; +} + +bool PlatformCAAnimation::isRemovedOnCompletion() const +{ + return [m_animation.get() isRemovedOnCompletion]; +} + +void PlatformCAAnimation::setRemovedOnCompletion(bool value) +{ + [m_animation.get() setRemovedOnCompletion:value]; +} + +bool PlatformCAAnimation::isAdditive() const +{ + return [m_animation.get() isAdditive]; +} + +void PlatformCAAnimation::setAdditive(bool value) +{ + [m_animation.get() setAdditive:value]; +} + +PlatformCAAnimation::ValueFunctionType PlatformCAAnimation::valueFunction() const +{ +#if HAVE_MODERN_QUARTZCORE + CAValueFunction* vf = [m_animation.get() valueFunction]; + return fromCAValueFunctionType([vf name]); +#else + return NoValueFunction; +#endif +} + +void PlatformCAAnimation::setValueFunction(ValueFunctionType value) +{ +#if HAVE_MODERN_QUARTZCORE + [m_animation.get() setValueFunction:[CAValueFunction functionWithName:toCAValueFunctionType(value)]]; +#else + UNUSED_PARAM(value); +#endif +} + +void PlatformCAAnimation::setFromValue(float value) +{ + if (animationType() != Basic) + return; + [static_cast<CABasicAnimation*>(m_animation.get()) setFromValue:[NSNumber numberWithDouble:value]]; +} + +void PlatformCAAnimation::setFromValue(const WebCore::TransformationMatrix& value) +{ + if (animationType() != Basic) + return; + + [static_cast<CABasicAnimation*>(m_animation.get()) setFromValue:[NSValue valueWithCATransform3D:value]]; +} + +void PlatformCAAnimation::setFromValue(const FloatPoint3D& value) +{ + if (animationType() != Basic) + return; + + NSArray* array = [NSArray arrayWithObjects: + [NSNumber numberWithDouble:value.x()], + [NSNumber numberWithDouble:value.y()], + [NSNumber numberWithDouble:value.z()], + nil]; + [static_cast<CABasicAnimation*>(m_animation.get()) setFromValue:array]; +} + +void PlatformCAAnimation::setFromValue(const WebCore::Color& value) +{ + if (animationType() != Basic) + return; + + NSArray* array = [NSArray arrayWithObjects: + [NSNumber numberWithDouble:value.red()], + [NSNumber numberWithDouble:value.green()], + [NSNumber numberWithDouble:value.blue()], + [NSNumber numberWithDouble:value.alpha()], + nil]; + [static_cast<CABasicAnimation*>(m_animation.get()) setFromValue:array]; +} + +void PlatformCAAnimation::copyFromValueFrom(const PlatformCAAnimation* value) +{ + if (animationType() != Basic || value->animationType() != Basic) + return; + + CABasicAnimation* otherAnimation = static_cast<CABasicAnimation*>(value->m_animation.get()); + [static_cast<CABasicAnimation*>(m_animation.get()) setFromValue:[otherAnimation fromValue]]; +} + +void PlatformCAAnimation::setToValue(float value) +{ + if (animationType() != Basic) + return; + [static_cast<CABasicAnimation*>(m_animation.get()) setToValue:[NSNumber numberWithDouble:value]]; +} + +void PlatformCAAnimation::setToValue(const WebCore::TransformationMatrix& value) +{ + if (animationType() != Basic) + return; + + [static_cast<CABasicAnimation*>(m_animation.get()) setToValue:[NSValue valueWithCATransform3D:value]]; +} + +void PlatformCAAnimation::setToValue(const FloatPoint3D& value) +{ + if (animationType() != Basic) + return; + + NSArray* array = [NSArray arrayWithObjects: + [NSNumber numberWithDouble:value.x()], + [NSNumber numberWithDouble:value.y()], + [NSNumber numberWithDouble:value.z()], + nil]; + [static_cast<CABasicAnimation*>(m_animation.get()) setToValue:array]; +} + +void PlatformCAAnimation::setToValue(const WebCore::Color& value) +{ + if (animationType() != Basic) + return; + + NSArray* array = [NSArray arrayWithObjects: + [NSNumber numberWithDouble:value.red()], + [NSNumber numberWithDouble:value.green()], + [NSNumber numberWithDouble:value.blue()], + [NSNumber numberWithDouble:value.alpha()], + nil]; + [static_cast<CABasicAnimation*>(m_animation.get()) setToValue:array]; +} + +void PlatformCAAnimation::copyToValueFrom(const PlatformCAAnimation* value) +{ + if (animationType() != Basic || value->animationType() != Basic) + return; + + CABasicAnimation* otherAnimation = static_cast<CABasicAnimation*>(value->m_animation.get()); + [static_cast<CABasicAnimation*>(m_animation.get()) setToValue:[otherAnimation toValue]]; +} + + +// Keyframe-animation properties. +void PlatformCAAnimation::setValues(const Vector<float>& value) +{ + if (animationType() != Keyframe) + return; + + NSMutableArray* array = [NSMutableArray array]; + for (size_t i = 0; i < value.size(); ++i) + [array addObject:[NSNumber numberWithDouble:value[i]]]; + [static_cast<CAKeyframeAnimation*>(m_animation.get()) setValues:array]; +} + +void PlatformCAAnimation::setValues(const Vector<WebCore::TransformationMatrix>& value) +{ + if (animationType() != Keyframe) + return; + + NSMutableArray* array = [NSMutableArray array]; + + for (size_t i = 0; i < value.size(); ++i) + [array addObject:[NSValue valueWithCATransform3D:value[i]]]; + + [static_cast<CAKeyframeAnimation*>(m_animation.get()) setValues:array]; +} + +void PlatformCAAnimation::setValues(const Vector<FloatPoint3D>& value) +{ + if (animationType() != Keyframe) + return; + + NSMutableArray* array = [NSMutableArray array]; + + for (size_t i = 0; i < value.size(); ++i) { + NSArray* object = [NSArray arrayWithObjects: + [NSNumber numberWithDouble:value[i].x()], + [NSNumber numberWithDouble:value[i].y()], + [NSNumber numberWithDouble:value[i].z()], + nil]; + [array addObject:object]; + } + [static_cast<CAKeyframeAnimation*>(m_animation.get()) setValues:array]; +} + +void PlatformCAAnimation::setValues(const Vector<WebCore::Color>& value) +{ + if (animationType() != Keyframe) + return; + + NSMutableArray* array = [NSMutableArray array]; + + for (size_t i = 0; i < value.size(); ++i) { + NSArray* object = [NSArray arrayWithObjects: + [NSNumber numberWithDouble:value[i].red()], + [NSNumber numberWithDouble:value[i].green()], + [NSNumber numberWithDouble:value[i].blue()], + [NSNumber numberWithDouble:value[i].alpha()], + nil]; + [array addObject:object]; + } + [static_cast<CAKeyframeAnimation*>(m_animation.get()) setValues:array]; +} + +void PlatformCAAnimation::copyValuesFrom(const PlatformCAAnimation* value) +{ + if (animationType() != Keyframe || value->animationType() != Keyframe) + return; + + CAKeyframeAnimation* otherAnimation = static_cast<CAKeyframeAnimation*>(value->m_animation.get()); + [static_cast<CAKeyframeAnimation*>(m_animation.get()) setValues:[otherAnimation values]]; +} + +void PlatformCAAnimation::setKeyTimes(const Vector<float>& value) +{ + NSMutableArray* array = [NSMutableArray array]; + + for (size_t i = 0; i < value.size(); ++i) + [array addObject:[NSNumber numberWithFloat:value[i]]]; + + [static_cast<CAKeyframeAnimation*>(m_animation.get()) setKeyTimes:array]; +} + +void PlatformCAAnimation::copyKeyTimesFrom(const PlatformCAAnimation* value) +{ + CAKeyframeAnimation* other = static_cast<CAKeyframeAnimation*>(value->m_animation.get()); + [static_cast<CAKeyframeAnimation*>(m_animation.get()) setKeyTimes:[other keyTimes]]; +} + +void PlatformCAAnimation::setTimingFunctions(const Vector<const TimingFunction*>& value) +{ + NSMutableArray* array = [NSMutableArray array]; + + for (size_t i = 0; i < value.size(); ++i) + [array addObject:toCAMediaTimingFunction(value[i])]; + + [static_cast<CAKeyframeAnimation*>(m_animation.get()) setTimingFunctions:array]; +} + +void PlatformCAAnimation::copyTimingFunctionsFrom(const PlatformCAAnimation* value) +{ + CAKeyframeAnimation* other = static_cast<CAKeyframeAnimation*>(value->m_animation.get()); + [static_cast<CAKeyframeAnimation*>(m_animation.get()) setTimingFunctions:[other timingFunctions]]; +} + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/ca/mac/PlatformCALayerMac.mm b/WebCore/platform/graphics/ca/mac/PlatformCALayerMac.mm new file mode 100644 index 0000000..0aecf14 --- /dev/null +++ b/WebCore/platform/graphics/ca/mac/PlatformCALayerMac.mm @@ -0,0 +1,725 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) + +#import "PlatformCALayer.h" + +#import "BlockExceptions.h" +#import "FloatConversion.h" +#import "GraphicsContext.h" +#import "GraphicsLayerCA.h" +#import "WebLayer.h" +#import "WebTiledLayer.h" +#import <objc/objc-auto.h> +#import <objc/objc-runtime.h> +#import <QuartzCore/QuartzCore.h> +#import <wtf/CurrentTime.h> +#import <wtf/UnusedParam.h> + +#define HAVE_MODERN_QUARTZCORE (!defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)) + +using namespace WebCore; + +// This value must be the same as in PlatformCAAnimationMac.mm +static NSString * const WKNonZeroBeginTimeFlag = @"WKPlatformCAAnimationNonZeroBeginTimeFlag"; + +static double mediaTimeToCurrentTime(CFTimeInterval t) +{ + return WTF::currentTime() + t - CACurrentMediaTime(); +} + +// Delegate for animationDidStart callback +@interface WebAnimationDelegate : NSObject { + PlatformCALayer* m_owner; +} + +- (void)animationDidStart:(CAAnimation *)anim; +- (void)setOwner:(PlatformCALayer*)owner; + +@end + +@implementation WebAnimationDelegate + +- (void)animationDidStart:(CAAnimation *)animation +{ + // hasNonZeroBeginTime is stored in a key in the animation + bool hasNonZeroBeginTime = [[animation valueForKey:WKNonZeroBeginTimeFlag] boolValue]; + CFTimeInterval startTime; + + if (hasNonZeroBeginTime) { + // We don't know what time CA used to commit the animation, so just use the current time + // (even though this will be slightly off). + startTime = mediaTimeToCurrentTime(CACurrentMediaTime()); + } else + startTime = mediaTimeToCurrentTime([animation beginTime]); + + if (m_owner) + m_owner->animationStarted(startTime); +} + +- (void)setOwner:(PlatformCALayer*)owner +{ + m_owner = owner; +} + +@end + +@interface CALayer(Private) +- (void)setContentsChanged; +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) +- (void)setAcceleratesDrawing:(BOOL)flag; +- (BOOL)acceleratesDrawing; +#endif +@end + +static NSString * const platformCALayerPointer = @"WKPlatformCALayer"; + +bool PlatformCALayer::isValueFunctionSupported() +{ + static bool sHaveValueFunction = [CAPropertyAnimation instancesRespondToSelector:@selector(setValueFunction:)]; + return sHaveValueFunction; +} + +void PlatformCALayer::setOwner(GraphicsLayerCA* owner) +{ + m_owner = owner; + + // Change the delegate's owner if needed + if (m_delegate) + [static_cast<WebAnimationDelegate*>(m_delegate.get()) setOwner:this]; +} + +static NSDictionary* nullActionsDictionary() +{ + NSNull* nullValue = [NSNull null]; + NSDictionary* actions = [NSDictionary dictionaryWithObjectsAndKeys: + nullValue, @"anchorPoint", + nullValue, @"bounds", + nullValue, @"contents", + nullValue, @"contentsRect", + nullValue, @"opacity", + nullValue, @"position", + nullValue, @"shadowColor", + nullValue, @"sublayerTransform", + nullValue, @"sublayers", + nullValue, @"transform", + nullValue, @"zPosition", + nil]; + return actions; +} + +#if HAVE_MODERN_QUARTZCORE +static NSString* toCAFilterType(PlatformCALayer::FilterType type) +{ + switch (type) { + case PlatformCALayer::Linear: return kCAFilterLinear; + case PlatformCALayer::Nearest: return kCAFilterNearest; + case PlatformCALayer::Trilinear: return kCAFilterTrilinear; + default: return 0; + } +} +#endif + +PassRefPtr<PlatformCALayer> PlatformCALayer::create(LayerType layerType, GraphicsLayerCA* owner) +{ + return adoptRef(new PlatformCALayer(layerType, 0, owner)); +} + +PassRefPtr<PlatformCALayer> PlatformCALayer::create(void* platformLayer, GraphicsLayerCA* owner) +{ + return adoptRef(new PlatformCALayer(LayerTypeCustom, static_cast<PlatformLayer*>(platformLayer), owner)); +} + +PlatformCALayer::PlatformCALayer(LayerType layerType, PlatformLayer* layer, GraphicsLayerCA* owner) + : m_owner(owner) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + if (layer) { + m_layerType = LayerTypeCustom; + m_layer = layer; + } else { + m_layerType = layerType; + + Class layerClass = Nil; + switch(layerType) { + case LayerTypeLayer: + layerClass = [CALayer class]; + break; + case LayerTypeWebLayer: + layerClass = [WebLayer class]; + break; + case LayerTypeTransformLayer: + layerClass = NSClassFromString(@"CATransformLayer"); + break; + case LayerTypeWebTiledLayer: + layerClass = [WebTiledLayer class]; + break; + case LayerTypeCustom: + break; + } + + if (layerClass) + m_layer.adoptNS([[layerClass alloc] init]); + } + + // Save a pointer to 'this' in the CALayer + [m_layer.get() setValue:[NSValue valueWithPointer:this] forKey:platformCALayerPointer]; + + // Clear all the implicit animations on the CALayer + [m_layer.get() setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]]; + + // If this is a TiledLayer, set some initial values + if (m_layerType == LayerTypeWebTiledLayer) { + WebTiledLayer* tiledLayer = static_cast<WebTiledLayer*>(m_layer.get()); + [tiledLayer setTileSize:CGSizeMake(GraphicsLayerCA::kTiledLayerTileSize, GraphicsLayerCA::kTiledLayerTileSize)]; + [tiledLayer setLevelsOfDetail:1]; + [tiledLayer setLevelsOfDetailBias:0]; + [tiledLayer setContentsGravity:@"bottomLeft"]; + } + + END_BLOCK_OBJC_EXCEPTIONS +} + +PlatformCALayer::~PlatformCALayer() +{ + [m_layer.get() setValue:nil forKey:platformCALayerPointer]; + + // Clear the owner, which also clears it in the delegate to prevent attempts + // to use the GraphicsLayerCA after it has been destroyed. + setOwner(0); + + // Remove the owner pointer from the delegate in case there is a pending animationStarted event. + [static_cast<WebAnimationDelegate*>(m_delegate.get()) setOwner:nil]; +} + +PlatformCALayer* PlatformCALayer::platformCALayer(void* platformLayer) +{ + if (!platformLayer) + return 0; + + // Pointer to PlatformCALayer is kept in a key of the CALayer + PlatformCALayer* platformCALayer = nil; + BEGIN_BLOCK_OBJC_EXCEPTIONS + platformCALayer = static_cast<PlatformCALayer*>([[static_cast<CALayer*>(platformLayer) valueForKey:platformCALayerPointer] pointerValue]); + END_BLOCK_OBJC_EXCEPTIONS + return platformCALayer; +} + +PlatformLayer* PlatformCALayer::platformLayer() const +{ + return m_layer.get(); +} + +void PlatformCALayer::setNeedsDisplay(const FloatRect* dirtyRect) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + if (dirtyRect) + [m_layer.get() setNeedsDisplayInRect:*dirtyRect]; + else + [m_layer.get() setNeedsDisplay]; + END_BLOCK_OBJC_EXCEPTIONS +} + +void PlatformCALayer::setContentsChanged() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setContentsChanged]; + END_BLOCK_OBJC_EXCEPTIONS +} + +PlatformCALayer* PlatformCALayer::superlayer() const +{ + return platformCALayer([m_layer.get() superlayer]); +} + +void PlatformCALayer::removeFromSuperlayer() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() removeFromSuperlayer]; + END_BLOCK_OBJC_EXCEPTIONS +} + +void PlatformCALayer::setSublayers(const PlatformCALayerList& list) +{ + // Short circuiting here not only avoids the allocation of sublayers, but avoids <rdar://problem/7390716> (see below) + if (list.size() == 0) { + removeAllSublayers(); + return; + } + + BEGIN_BLOCK_OBJC_EXCEPTIONS + NSMutableArray* sublayers = [[NSMutableArray alloc] init]; + for (size_t i = 0; i < list.size(); ++i) + [sublayers addObject:list[i]->m_layer.get()]; + + [m_layer.get() setSublayers:sublayers]; + [sublayers release]; + END_BLOCK_OBJC_EXCEPTIONS +} + +void PlatformCALayer::removeAllSublayers() +{ + // Workaround for <rdar://problem/7390716>: -[CALayer setSublayers:] crashes if sublayers is an empty array, or nil, under GC. + BEGIN_BLOCK_OBJC_EXCEPTIONS + if (objc_collectingEnabled()) + while ([[m_layer.get() sublayers] count]) + [[[m_layer.get() sublayers] objectAtIndex:0] removeFromSuperlayer]; + else + [m_layer.get() setSublayers:nil]; + END_BLOCK_OBJC_EXCEPTIONS +} + +void PlatformCALayer::appendSublayer(PlatformCALayer* layer) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() addSublayer:layer->m_layer.get()]; + END_BLOCK_OBJC_EXCEPTIONS +} + +void PlatformCALayer::insertSublayer(PlatformCALayer* layer, size_t index) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() insertSublayer:layer->m_layer.get() atIndex:index]; + END_BLOCK_OBJC_EXCEPTIONS +} + +void PlatformCALayer::replaceSublayer(PlatformCALayer* reference, PlatformCALayer* layer) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() replaceSublayer:reference->m_layer.get() with:layer->m_layer.get()]; + END_BLOCK_OBJC_EXCEPTIONS +} + +size_t PlatformCALayer::sublayerCount() const +{ + return [[m_layer.get() sublayers] count]; +} + +void PlatformCALayer::adoptSublayers(PlatformCALayer* source) +{ + // Workaround for <rdar://problem/7390716>: -[CALayer setSublayers:] crashes if sublayers is an empty array, or nil, under GC. + NSArray* sublayers = [source->m_layer.get() sublayers]; + + if (objc_collectingEnabled() && ![sublayers count]) { + BEGIN_BLOCK_OBJC_EXCEPTIONS + while ([[m_layer.get() sublayers] count]) + [[[m_layer.get() sublayers] objectAtIndex:0] removeFromSuperlayer]; + END_BLOCK_OBJC_EXCEPTIONS + return; + } + + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setSublayers:sublayers]; + END_BLOCK_OBJC_EXCEPTIONS +} + +void PlatformCALayer::addAnimationForKey(const String& key, PlatformCAAnimation* animation) +{ + // Add the delegate + if (!m_delegate) { + WebAnimationDelegate* webAnimationDelegate = [[WebAnimationDelegate alloc] init]; + m_delegate.adoptNS(webAnimationDelegate); + [webAnimationDelegate setOwner:this]; + } + + CAPropertyAnimation* propertyAnimation = static_cast<CAPropertyAnimation*>(animation->platformAnimation()); + + if (![propertyAnimation delegate]) + [propertyAnimation setDelegate:static_cast<id>(m_delegate.get())]; + + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() addAnimation:animation->m_animation.get() forKey:key]; + END_BLOCK_OBJC_EXCEPTIONS +} + +void PlatformCALayer::removeAnimationForKey(const String& key) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() removeAnimationForKey:key]; + END_BLOCK_OBJC_EXCEPTIONS +} + +PassRefPtr<PlatformCAAnimation> PlatformCALayer::animationForKey(const String& key) +{ + CAPropertyAnimation* propertyAnimation = static_cast<CAPropertyAnimation*>([m_layer.get() animationForKey:key]); + if (!propertyAnimation) + return 0; + return PlatformCAAnimation::create(propertyAnimation); +} + +PlatformCALayer* PlatformCALayer::mask() const +{ + return platformCALayer([m_layer.get() mask]); +} + +void PlatformCALayer::setMask(PlatformCALayer* layer) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setMask:layer ? layer->platformLayer() : 0]; + END_BLOCK_OBJC_EXCEPTIONS +} + +bool PlatformCALayer::isOpaque() const +{ + return [m_layer.get() isOpaque]; +} + +void PlatformCALayer::setOpaque(bool value) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setOpaque:value]; + END_BLOCK_OBJC_EXCEPTIONS +} + +FloatRect PlatformCALayer::bounds() const +{ + return [m_layer.get() bounds]; +} + +void PlatformCALayer::setBounds(const FloatRect& value) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setBounds:value]; + END_BLOCK_OBJC_EXCEPTIONS +} + +FloatPoint3D PlatformCALayer::position() const +{ + CGPoint point = [m_layer.get() position]; + return FloatPoint3D(point.x, point.y, [m_layer.get() zPosition]); +} + +void PlatformCALayer::setPosition(const FloatPoint3D& value) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setPosition:CGPointMake(value.x(), value.y())]; + [m_layer.get() setZPosition:value.z()]; + END_BLOCK_OBJC_EXCEPTIONS +} + +FloatPoint3D PlatformCALayer::anchorPoint() const +{ + CGPoint point = [m_layer.get() anchorPoint]; + float z = 0; +#if HAVE_MODERN_QUARTZCORE + z = [m_layer.get() anchorPointZ]; +#endif + return FloatPoint3D(point.x, point.y, z); +} + +void PlatformCALayer::setAnchorPoint(const FloatPoint3D& value) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setAnchorPoint:CGPointMake(value.x(), value.y())]; +#if HAVE_MODERN_QUARTZCORE + [m_layer.get() setAnchorPointZ:value.z()]; +#endif + END_BLOCK_OBJC_EXCEPTIONS +} + +TransformationMatrix PlatformCALayer::transform() const +{ + return [m_layer.get() transform]; +} + +void PlatformCALayer::setTransform(const TransformationMatrix& value) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setTransform:value]; + END_BLOCK_OBJC_EXCEPTIONS +} + +TransformationMatrix PlatformCALayer::sublayerTransform() const +{ + return [m_layer.get() sublayerTransform]; +} + +void PlatformCALayer::setSublayerTransform(const TransformationMatrix& value) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setSublayerTransform:value]; + END_BLOCK_OBJC_EXCEPTIONS +} + +TransformationMatrix PlatformCALayer::contentsTransform() const +{ +#if !HAVE_MODERN_QUARTZCORE + if (m_layerType != LayerTypeWebLayer) + return TransformationMatrix(); + + return [static_cast<WebLayer*>(m_layer.get()) contentsTransform]; +#else + return TransformationMatrix(); +#endif +} + +void PlatformCALayer::setContentsTransform(const TransformationMatrix& value) +{ +#if !HAVE_MODERN_QUARTZCORE + if (m_layerType != LayerTypeWebLayer) + return; + + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setContentsTransform:value]; + END_BLOCK_OBJC_EXCEPTIONS +#else + UNUSED_PARAM(value); +#endif +} + +bool PlatformCALayer::isHidden() const +{ + return [m_layer.get() isHidden]; +} + +void PlatformCALayer::setHidden(bool value) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setHidden:value]; + END_BLOCK_OBJC_EXCEPTIONS +} + +bool PlatformCALayer::isGeometryFlipped() const +{ +#if HAVE_MODERN_QUARTZCORE + return [m_layer.get() isGeometryFlipped]; +#else + return false; +#endif +} + +void PlatformCALayer::setGeometryFlipped(bool value) +{ +#if HAVE_MODERN_QUARTZCORE + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setGeometryFlipped:value]; + END_BLOCK_OBJC_EXCEPTIONS +#else + UNUSED_PARAM(value); +#endif +} + +bool PlatformCALayer::isDoubleSided() const +{ + return [m_layer.get() isDoubleSided]; +} + +void PlatformCALayer::setDoubleSided(bool value) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setDoubleSided:value]; + END_BLOCK_OBJC_EXCEPTIONS +} + +bool PlatformCALayer::masksToBounds() const +{ + return [m_layer.get() masksToBounds]; +} + +void PlatformCALayer::setMasksToBounds(bool value) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setMasksToBounds:value]; + END_BLOCK_OBJC_EXCEPTIONS +} + +bool PlatformCALayer::acceleratesDrawing() const +{ +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) + return [m_layer.get() acceleratesDrawing]; +#else + return false; +#endif +} + +void PlatformCALayer::setAcceleratesDrawing(bool acceleratesDrawing) +{ +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setAcceleratesDrawing:acceleratesDrawing]; + END_BLOCK_OBJC_EXCEPTIONS +#else + UNUSED_PARAM(acceleratesDrawing); +#endif +} + +void* PlatformCALayer::contents() const +{ + return [m_layer.get() contents]; +} + +void PlatformCALayer::setContents(void* value) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setContents:static_cast<id>(value)]; + END_BLOCK_OBJC_EXCEPTIONS +} + +FloatRect PlatformCALayer::contentsRect() const +{ + return [m_layer.get() contentsRect]; +} + +void PlatformCALayer::setContentsRect(const FloatRect& value) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setContentsRect:value]; + END_BLOCK_OBJC_EXCEPTIONS +} + +void PlatformCALayer::setMinificationFilter(FilterType value) +{ +#if HAVE_MODERN_QUARTZCORE + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setMinificationFilter:toCAFilterType(value)]; + END_BLOCK_OBJC_EXCEPTIONS +#else + UNUSED_PARAM(value); +#endif +} + +void PlatformCALayer::setMagnificationFilter(FilterType value) +{ +#if HAVE_MODERN_QUARTZCORE + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setMagnificationFilter:toCAFilterType(value)]; + END_BLOCK_OBJC_EXCEPTIONS +#else + UNUSED_PARAM(value); +#endif +} + +Color PlatformCALayer::backgroundColor() const +{ + return [m_layer.get() backgroundColor]; +} + +void PlatformCALayer::setBackgroundColor(const Color& value) +{ + CGFloat components[4]; + value.getRGBA(components[0], components[1], components[2], components[3]); + + RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB()); + RetainPtr<CGColorRef> color(AdoptCF, CGColorCreate(colorSpace.get(), components)); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setBackgroundColor:color.get()]; + END_BLOCK_OBJC_EXCEPTIONS +} + +float PlatformCALayer::borderWidth() const +{ + return [m_layer.get() borderWidth]; +} + +void PlatformCALayer::setBorderWidth(float value) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setBorderWidth:value]; + END_BLOCK_OBJC_EXCEPTIONS +} + +Color PlatformCALayer::borderColor() const +{ + return [m_layer.get() borderColor]; +} + +void PlatformCALayer::setBorderColor(const Color& value) +{ + CGFloat components[4]; + value.getRGBA(components[0], components[1], components[2], components[3]); + + RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB()); + RetainPtr<CGColorRef> color(AdoptCF, CGColorCreate(colorSpace.get(), components)); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setBorderColor:color.get()]; + END_BLOCK_OBJC_EXCEPTIONS +} + +float PlatformCALayer::opacity() const +{ + return [m_layer.get() opacity]; +} + +void PlatformCALayer::setOpacity(float value) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setOpacity:value]; + END_BLOCK_OBJC_EXCEPTIONS +} + +String PlatformCALayer::name() const +{ + return [m_layer.get() name]; +} + +void PlatformCALayer::setName(const String& value) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setName:value]; + END_BLOCK_OBJC_EXCEPTIONS +} + +FloatRect PlatformCALayer::frame() const +{ + return [m_layer.get() frame]; +} + +void PlatformCALayer::setFrame(const FloatRect& value) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setFrame:value]; + END_BLOCK_OBJC_EXCEPTIONS +} + +float PlatformCALayer::speed() const +{ + return [m_layer.get() speed]; +} + +void PlatformCALayer::setSpeed(float value) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setSpeed:value]; + END_BLOCK_OBJC_EXCEPTIONS +} + +CFTimeInterval PlatformCALayer::timeOffset() const +{ + return [m_layer.get() timeOffset]; +} + +void PlatformCALayer::setTimeOffset(CFTimeInterval value) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setTimeOffset:value]; + END_BLOCK_OBJC_EXCEPTIONS +} + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/cairo/CairoUtilities.cpp b/WebCore/platform/graphics/cairo/CairoUtilities.cpp index 709ee8f..013a4af 100644 --- a/WebCore/platform/graphics/cairo/CairoUtilities.cpp +++ b/WebCore/platform/graphics/cairo/CairoUtilities.cpp @@ -130,7 +130,7 @@ void drawPatternToCairoContext(cairo_t* cr, cairo_surface_t* image, const IntSiz if (tileRect.size() != imageSize) { IntRect imageRect = enclosingIntRect(tileRect); clippedImageSurface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, imageRect.width(), imageRect.height())); - RefPtr<cairo_t> clippedImageContext(cairo_create(clippedImageSurface.get())); + RefPtr<cairo_t> clippedImageContext = adoptRef(cairo_create(clippedImageSurface.get())); cairo_set_source_surface(clippedImageContext.get(), image, -tileRect.x(), -tileRect.y()); cairo_paint(clippedImageContext.get()); image = clippedImageSurface.get(); diff --git a/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp b/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp index 8299b6a..ae91282 100644 --- a/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp +++ b/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp @@ -82,17 +82,27 @@ static cairo_surface_t* getScratchBuffer(const IntSize& size) return scratchBuffer; } +TransformationMatrix ContextShadow::getTransformationMatrixFromContext(PlatformContext context) +{ + cairo_matrix_t transform; + cairo_get_matrix(context, &transform); + return TransformationMatrix(transform.xx, transform.yx, transform.xy, + transform.yy, transform.x0, transform.y0); +} + PlatformContext ContextShadow::beginShadowLayer(PlatformContext context, const FloatRect& layerArea) { + adjustBlurDistance(context); + double x1, x2, y1, y2; cairo_clip_extents(context, &x1, &y1, &x2, &y2); - calculateLayerBoundingRect(layerArea, IntRect(x1, y1, x2 - x1, y2 - y1)); + IntRect layerRect = calculateLayerBoundingRect(context, layerArea, IntRect(x1, y1, x2 - x1, y2 - y1)); // Don't paint if we are totally outside the clip region. - if (m_layerRect.isEmpty()) + if (layerRect.isEmpty()) return 0; - m_layerImage = getScratchBuffer(m_layerRect.size()); + m_layerImage = getScratchBuffer(layerRect.size()); m_layerContext = cairo_create(m_layerImage); // Always clear the surface first. @@ -100,8 +110,7 @@ PlatformContext ContextShadow::beginShadowLayer(PlatformContext context, const F cairo_paint(m_layerContext); cairo_set_operator(m_layerContext, CAIRO_OPERATOR_OVER); - cairo_translate(m_layerContext, m_offset.width(), m_offset.height()); - cairo_translate(m_layerContext, -m_layerRect.x(), -m_layerRect.y()); + cairo_translate(m_layerContext, m_layerContextTranslation.x(), m_layerContextTranslation.y()); return m_layerContext; } @@ -120,7 +129,7 @@ void ContextShadow::endShadowLayer(cairo_t* cr) cairo_save(cr); setSourceRGBAFromColor(cr, m_color); - cairo_mask_surface(cr, m_layerImage, m_layerRect.x(), m_layerRect.y()); + cairo_mask_surface(cr, m_layerImage, m_layerOrigin.x(), m_layerOrigin.y()); cairo_restore(cr); // Schedule a purge of the scratch buffer. We do not need to destroy the surface. @@ -221,9 +230,9 @@ void ContextShadow::drawRectShadow(GraphicsContext* context, const IntRect& rect // Reduce the size of what we have to draw with the clip area. double x1, x2, y1, y2; cairo_clip_extents(cr, &x1, &y1, &x2, &y2); - calculateLayerBoundingRect(shadowRect, IntRect(x1, y1, x2 - x1, y2 - y1)); + calculateLayerBoundingRect(cr, shadowRect, IntRect(x1, y1, x2 - x1, y2 - y1)); - if ((shadowTemplateSize.width() * shadowTemplateSize.height() > m_layerRect.width() * m_layerRect.height())) { + if ((shadowTemplateSize.width() * shadowTemplateSize.height() > m_sourceRect.width() * m_sourceRect.height())) { drawRectShadowWithoutTiling(cr, rect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius, context->getAlpha()); return; } diff --git a/WebCore/platform/graphics/cairo/FontCairo.cpp b/WebCore/platform/graphics/cairo/FontCairo.cpp index 3d55c70..0d92ada 100644 --- a/WebCore/platform/graphics/cairo/FontCairo.cpp +++ b/WebCore/platform/graphics/cairo/FontCairo.cpp @@ -69,10 +69,10 @@ static void drawGlyphsShadow(GraphicsContext* graphicsContext, cairo_t* context, ContextShadow* shadow = graphicsContext->contextShadow(); ASSERT(shadow); - if (!(graphicsContext->textDrawingMode() & cTextFill) || shadow->m_type == ContextShadow::NoShadow) + if (!(graphicsContext->textDrawingMode() & TextModeFill) || shadow->m_type == ContextShadow::NoShadow) return; - if (shadow->m_type == ContextShadow::SolidShadow) { + if (!shadow->mustUseContextShadow(context)) { // Optimize non-blurry shadows, by just drawing text without the ContextShadow. cairo_save(context); cairo_translate(context, shadow->m_offset.width(), shadow->m_offset.height()); @@ -111,7 +111,7 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons cairo_save(cr); prepareContextForGlyphDrawing(cr, font, point); - if (context->textDrawingMode() & cTextFill) { + if (context->textDrawingMode() & TextModeFill) { if (context->fillGradient()) { cairo_set_source(cr, context->fillGradient()->platformGradient()); if (context->getAlpha() < 1.0f) { @@ -141,7 +141,7 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons // twice the size of the width of the text we will not ask cairo to stroke // the text as even one single stroke would cover the full wdth of the text. // See https://bugs.webkit.org/show_bug.cgi?id=33759. - if (context->textDrawingMode() & cTextStroke && context->strokeThickness() < 2 * offset) { + if (context->textDrawingMode() & TextModeStroke && context->strokeThickness() < 2 * offset) { if (context->strokeGradient()) { cairo_set_source(cr, context->strokeGradient()->platformGradient()); if (context->getAlpha() < 1.0f) { diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp index 1032dc2..a6edaf7 100644 --- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp +++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp @@ -5,6 +5,7 @@ * Copyright (C) 2008 Nuanti Ltd. * Copyright (C) 2009 Brent Fulgham <bfulgham@webkit.org> * Copyright (C) 2010 Igalia S.L. + * Copyright (C) Research In Motion Limited 2010. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -40,7 +41,6 @@ #include "FloatRect.h" #include "Font.h" #include "GraphicsContextPlatformPrivateCairo.h" -#include "GraphicsContextPrivate.h" #include "OwnPtrCairo.h" #include "IntRect.h" #include "NotImplemented.h" @@ -68,49 +68,46 @@ using namespace std; namespace WebCore { -static inline void setColor(cairo_t* cr, const Color& col) -{ - float red, green, blue, alpha; - col.getRGBA(red, green, blue, alpha); - cairo_set_source_rgba(cr, red, green, blue, alpha); -} - -static inline void setPlatformFill(GraphicsContext* context, cairo_t* cr, GraphicsContextPrivate* gcp) +static inline void setPlatformFill(GraphicsContext* context, cairo_t* cr) { cairo_pattern_t* pattern = 0; cairo_save(cr); - if (gcp->state.fillPattern) { + + const GraphicsContextState& state = context->state(); + if (state.fillPattern) { AffineTransform affine; - pattern = gcp->state.fillPattern->createPlatformPattern(affine); + pattern = state.fillPattern->createPlatformPattern(affine); cairo_set_source(cr, pattern); - } else if (gcp->state.fillGradient) - cairo_set_source(cr, gcp->state.fillGradient->platformGradient()); + } else if (state.fillGradient) + cairo_set_source(cr, state.fillGradient->platformGradient()); else - setColor(cr, context->fillColor()); + setSourceRGBAFromColor(cr, context->fillColor()); cairo_clip_preserve(cr); - cairo_paint_with_alpha(cr, gcp->state.globalAlpha); + cairo_paint_with_alpha(cr, state.globalAlpha); cairo_restore(cr); if (pattern) cairo_pattern_destroy(pattern); } -static inline void setPlatformStroke(GraphicsContext* context, cairo_t* cr, GraphicsContextPrivate* gcp) +static inline void setPlatformStroke(GraphicsContext* context, cairo_t* cr) { cairo_pattern_t* pattern = 0; cairo_save(cr); - if (gcp->state.strokePattern) { + + const GraphicsContextState& state = context->state(); + if (state.strokePattern) { AffineTransform affine; - pattern = gcp->state.strokePattern->createPlatformPattern(affine); + pattern = state.strokePattern->createPlatformPattern(affine); cairo_set_source(cr, pattern); - } else if (gcp->state.strokeGradient) - cairo_set_source(cr, gcp->state.strokeGradient->platformGradient()); + } else if (state.strokeGradient) + cairo_set_source(cr, state.strokeGradient->platformGradient()); else { - Color strokeColor = colorWithOverrideAlpha(context->strokeColor().rgb(), context->strokeColor().alpha() / 255.f * gcp->state.globalAlpha); - setColor(cr, strokeColor); + Color strokeColor = colorWithOverrideAlpha(context->strokeColor().rgb(), context->strokeColor().alpha() / 255.f * state.globalAlpha); + setSourceRGBAFromColor(cr, strokeColor); } - if (gcp->state.globalAlpha < 1.0f && (gcp->state.strokePattern || gcp->state.strokeGradient)) { + if (state.globalAlpha < 1.0f && (state.strokePattern || state.strokeGradient)) { cairo_push_group(cr); - cairo_paint_with_alpha(cr, gcp->state.globalAlpha); + cairo_paint_with_alpha(cr, state.globalAlpha); cairo_pop_group_to_source(cr); } cairo_stroke_preserve(cr); @@ -122,7 +119,7 @@ static inline void setPlatformStroke(GraphicsContext* context, cairo_t* cr, Grap // A fillRect helper static inline void fillRectSourceOver(cairo_t* cr, const FloatRect& rect, const Color& col) { - setColor(cr, col); + setSourceRGBAFromColor(cr, col); cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); cairo_set_operator(cr, CAIRO_OPERATOR_OVER); cairo_fill(cr); @@ -142,7 +139,7 @@ enum PathDrawingStyle { FillAndStroke = Fill + Stroke }; -static inline void drawPathShadow(GraphicsContext* context, GraphicsContextPrivate* contextPrivate, PathDrawingStyle drawingStyle) +static inline void drawPathShadow(GraphicsContext* context, PathDrawingStyle drawingStyle) { ContextShadow* shadow = context->contextShadow(); ASSERT(shadow); @@ -151,7 +148,7 @@ static inline void drawPathShadow(GraphicsContext* context, GraphicsContextPriva // Calculate the extents of the rendered solid paths. cairo_t* cairoContext = context->platformContext(); - cairo_path_t* path = cairo_copy_path(cairoContext); + OwnPtr<cairo_path_t> path(cairo_copy_path(cairoContext)); FloatRect solidFigureExtents; double x0 = 0; @@ -175,44 +172,42 @@ static inline void drawPathShadow(GraphicsContext* context, GraphicsContextPriva // It's important to copy the context properties to the new shadow // context to preserve things such as the fill rule and stroke width. copyContextProperties(cairoContext, shadowContext); - cairo_append_path(shadowContext, path); + cairo_append_path(shadowContext, path.get()); if (drawingStyle & Fill) - setPlatformFill(context, shadowContext, contextPrivate); + setPlatformFill(context, shadowContext); if (drawingStyle & Stroke) - setPlatformStroke(context, shadowContext, contextPrivate); + setPlatformStroke(context, shadowContext); shadow->endShadowLayer(cairoContext); } -static void fillCurrentCairoPath(GraphicsContext* context, GraphicsContextPrivate* gcp, cairo_t* cairoContext) +static void fillCurrentCairoPath(GraphicsContext* context, cairo_t* cairoContext) { cairo_set_fill_rule(cairoContext, context->fillRule() == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); - drawPathShadow(context, gcp, Fill); + drawPathShadow(context, Fill); - setPlatformFill(context, cairoContext, gcp); + setPlatformFill(context, cairoContext); cairo_new_path(cairoContext); } -static void strokeCurrentCairoPath(GraphicsContext* context, GraphicsContextPrivate* gcp, cairo_t* cairoContext) +static void strokeCurrentCairoPath(GraphicsContext* context, cairo_t* cairoContext) { - drawPathShadow(context, gcp, Stroke); - setPlatformStroke(context, cairoContext, gcp); + drawPathShadow(context, Stroke); + setPlatformStroke(context, cairoContext); cairo_new_path(cairoContext); } -GraphicsContext::GraphicsContext(PlatformGraphicsContext* cr) - : m_common(createGraphicsContextPrivate()) - , m_data(new GraphicsContextPlatformPrivate) +void GraphicsContext::platformInit(PlatformGraphicsContext* cr) { + m_data = new GraphicsContextPlatformPrivate; m_data->cr = cairo_reference(cr); m_data->syncContext(cr); setPaintingDisabled(!cr); } -GraphicsContext::~GraphicsContext() +void GraphicsContext::platformDestroy() { - destroyGraphicsContextPrivate(m_common); delete m_data; } @@ -262,7 +257,7 @@ void GraphicsContext::drawRect(const IntRect& rect) fillRectSourceOver(cr, rect, fillColor()); if (strokeStyle() != NoStroke) { - setColor(cr, strokeColor()); + setSourceRGBAFromColor(cr, strokeColor()); FloatRect r(rect); r.inflate(-.5f); cairo_rectangle(cr, r.x(), r.y(), r.width(), r.height()); @@ -310,7 +305,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) break; } - setColor(cr, strokeColor()); + setSourceRGBAFromColor(cr, strokeColor()); cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); @@ -380,12 +375,12 @@ void GraphicsContext::drawEllipse(const IntRect& rect) cairo_restore(cr); if (fillColor().alpha()) { - setColor(cr, fillColor()); + setSourceRGBAFromColor(cr, fillColor()); cairo_fill_preserve(cr); } if (strokeStyle() != NoStroke) { - setColor(cr, strokeColor()); + setSourceRGBAFromColor(cr, strokeColor()); cairo_set_line_width(cr, strokeThickness()); cairo_stroke(cr); } else @@ -434,7 +429,7 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp break; } - setColor(cr, strokeColor()); + setSourceRGBAFromColor(cr, strokeColor()); if (patWidth) { // Example: 80 pixels with a width of 30 pixels. @@ -493,13 +488,13 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points addConvexPolygonToContext(cr, npoints, points); if (fillColor().alpha()) { - setColor(cr, fillColor()); + setSourceRGBAFromColor(cr, fillColor()); cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); cairo_fill_preserve(cr); } if (strokeStyle() != NoStroke) { - setColor(cr, strokeColor()); + setSourceRGBAFromColor(cr, strokeColor()); cairo_set_line_width(cr, strokeThickness()); cairo_stroke(cr); } else @@ -531,42 +526,24 @@ void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* poin cairo_set_fill_rule(cr, savedFillRule); } -void GraphicsContext::fillPath() +void GraphicsContext::fillPath(const Path& path) { if (paintingDisabled()) return; cairo_t* cr = m_data->cr; - - setPathOnCairoContext(cr, m_data->m_pendingPath.context()); - fillCurrentCairoPath(this, m_common, cr); + setPathOnCairoContext(cr, path.platformPath()->context()); + fillCurrentCairoPath(this, cr); } -void GraphicsContext::strokePath() +void GraphicsContext::strokePath(const Path& path) { if (paintingDisabled()) return; cairo_t* cr = m_data->cr; - setPathOnCairoContext(cr, m_data->m_pendingPath.context()); - strokeCurrentCairoPath(this, m_common, cr); -} - -void GraphicsContext::drawPath() -{ - if (paintingDisabled()) - return; - - cairo_t* cr = m_data->cr; - - setPathOnCairoContext(cr, m_data->m_pendingPath.context()); - - cairo_set_fill_rule(cr, fillRule() == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); - drawPathShadow(this, m_common, FillAndStroke); - - setPlatformFill(this, cr, m_common); - setPlatformStroke(this, cr, m_common); - cairo_new_path(cr); + setPathOnCairoContext(cr, path.platformPath()->context()); + strokeCurrentCairoPath(this, cr); } void GraphicsContext::fillRect(const FloatRect& rect) @@ -577,7 +554,7 @@ void GraphicsContext::fillRect(const FloatRect& rect) cairo_t* cr = m_data->cr; cairo_save(cr); cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); - fillCurrentCairoPath(this, m_common, cr); + fillCurrentCairoPath(this, cr); cairo_restore(cr); } @@ -607,19 +584,57 @@ void GraphicsContext::clip(const FloatRect& rect) m_data->clip(rect); } -void GraphicsContext::clipPath(WindRule clipRule) +void GraphicsContext::clipPath(const Path& path, WindRule clipRule) { if (paintingDisabled()) return; cairo_t* cr = m_data->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); } -void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color) +static inline void adjustFocusRingColor(Color& color) { - // FIXME: implement +#if !PLATFORM(GTK) + // Force the alpha to 50%. This matches what the Mac does with outline rings. + color.setRGB(makeRGBA(color.red(), color.green(), color.blue(), 127)); +#endif +} + +static inline void adjustFocusRingLineWidth(int& width) +{ +#if PLATFORM(GTK) + width = 2; +#endif +} + +static inline StrokeStyle focusRingStrokeStyle() +{ +#if PLATFORM(GTK) + return DottedStroke; +#else + return SolidStroke; +#endif +} + +void GraphicsContext::drawFocusRing(const Path& path, int width, int /* offset */, const Color& color) +{ + // FIXME: We should draw paths that describe a rectangle with rounded corners + // so as to be consistent with how we draw rectangular focus rings. + Color ringColor = color; + adjustFocusRingColor(ringColor); + adjustFocusRingLineWidth(width); + + cairo_t* cr = m_data->cr; + cairo_save(cr); + appendWebCorePathToCairoContext(cr, path); + setSourceRGBAFromColor(cr, ringColor); + cairo_set_line_width(cr, width); + setPlatformStrokeStyle(focusRingStrokeStyle()); + cairo_stroke(cr); + cairo_restore(cr); } void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int /* offset */, const Color& color) @@ -656,10 +671,6 @@ void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int #else cairo_region_destroy(reg); #endif - - setColor(cr, color); - cairo_set_line_width(cr, 2.0f); - setPlatformStrokeStyle(DottedStroke); #else int radius = (width - 1) / 2; Path path; @@ -669,13 +680,13 @@ void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int path.addRoundedRect(rects[i], FloatSize(radius, radius)); appendWebCorePathToCairoContext(cr, path); } - - // Force the alpha to 50%. This matches what the Mac does with outline rings. - Color ringColor(color.red(), color.green(), color.blue(), 127); - setColor(cr, ringColor); - cairo_set_line_width(cr, width); - setPlatformStrokeStyle(SolidStroke); #endif + Color ringColor = color; + adjustFocusRingColor(ringColor); + adjustFocusRingLineWidth(width); + setSourceRGBAFromColor(cr, ringColor); + cairo_set_line_width(cr, width); + setPlatformStrokeStyle(focusRingStrokeStyle()); cairo_set_operator(cr, CAIRO_OPERATOR_OVER); cairo_stroke_preserve(cr); @@ -853,13 +864,15 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness void GraphicsContext::setPlatformShadow(FloatSize const& size, float blur, Color const& color, ColorSpace) { // Cairo doesn't support shadows natively, they are drawn manually in the draw* functions - if (m_common->state.shadowsIgnoreTransforms) { + if (m_state.shadowsIgnoreTransforms) { // Meaning that this graphics context is associated with a CanvasRenderingContext // We flip the height since CG and HTML5 Canvas have opposite Y axis - m_common->state.shadowOffset = FloatSize(size.width(), -size.height()); + m_state.shadowOffset = FloatSize(size.width(), -size.height()); m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), -size.height())); } else m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), size.height())); + + m_data->shadow.setShadowsIgnoreTransforms(m_state.shadowsIgnoreTransforms); } ContextShadow* GraphicsContext::contextShadow() @@ -919,7 +932,7 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float width) cairo_save(cr); cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); cairo_set_line_width(cr, width); - strokeCurrentCairoPath(this, m_common, cr); + strokeCurrentCairoPath(this, cr); cairo_restore(cr); } @@ -978,15 +991,15 @@ void GraphicsContext::setMiterLimit(float miter) void GraphicsContext::setAlpha(float alpha) { - m_common->state.globalAlpha = alpha; + m_state.globalAlpha = alpha; } float GraphicsContext::getAlpha() { - return m_common->state.globalAlpha; + return m_state.globalAlpha; } -void GraphicsContext::setCompositeOperation(CompositeOperator op) +void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op) { if (paintingDisabled()) return; @@ -994,25 +1007,6 @@ void GraphicsContext::setCompositeOperation(CompositeOperator op) cairo_set_operator(m_data->cr, toCairoOperator(op)); } -void GraphicsContext::beginPath() -{ - if (paintingDisabled()) - return; - - cairo_new_path(m_data->m_pendingPath.context()); -} - -void GraphicsContext::addPath(const Path& path) -{ - if (paintingDisabled()) - return; - - cairo_matrix_t currentMatrix; - cairo_get_matrix(m_data->cr, ¤tMatrix); - cairo_set_matrix(m_data->m_pendingPath.context(), ¤tMatrix); - appendWebCorePathToCairoContext(m_data->m_pendingPath.context(), path); -} - void GraphicsContext::clip(const Path& path) { if (paintingDisabled()) @@ -1105,7 +1099,7 @@ void GraphicsContext::fillRoundedRect(const IntRect& r, const IntSize& topLeft, Path path; path.addRoundedRect(r, topLeft, topRight, bottomLeft, bottomRight); appendWebCorePathToCairoContext(cr, path); - setColor(cr, color); + setSourceRGBAFromColor(cr, color); cairo_fill(cr); cairo_restore(cr); } @@ -1121,12 +1115,12 @@ GdkEventExpose* GraphicsContext::gdkExposeEvent() const return m_data->expose; } -GdkDrawable* GraphicsContext::gdkDrawable() const +GdkWindow* GraphicsContext::gdkWindow() const { if (!m_data->expose) return 0; - return GDK_DRAWABLE(m_data->expose->window); + return m_data->expose->window; } #endif diff --git a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h index 527cb72..494b40d 100644 --- a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h +++ b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h @@ -27,7 +27,6 @@ #include "GraphicsContext.h" -#include "CairoPath.h" #include "ContextShadow.h" #include <cairo.h> #include <math.h> @@ -97,7 +96,6 @@ public: cairo_t* cr; Vector<float> layers; - CairoPath m_pendingPath; ContextShadow shadow; Vector<ContextShadow> shadowStack; diff --git a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp index d452c3a..b353943 100644 --- a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp +++ b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp @@ -69,7 +69,7 @@ ImageBufferData::ImageBufferData(const IntSize& size) { } -ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, bool& success) +ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode, bool& success) : m_data(size) , m_size(size) { diff --git a/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp b/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp index 7a58eed..f997277 100644 --- a/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp +++ b/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp @@ -99,7 +99,8 @@ bool GraphicsContext3D::getImageData(Image* image, CGImageRef cgImage; RetainPtr<CGImageRef> decodedImage; if (image->data()) { - ImageSource decoder(false, ignoreGammaAndColorProfile); + ImageSource decoder(ImageSource::AlphaNotPremultiplied, + ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied); decoder.setData(image->data(), true); if (!decoder.frameCount()) return false; diff --git a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp index 8d72b85..7898d62 100644 --- a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp +++ b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp @@ -31,7 +31,6 @@ #include "AffineTransform.h" #include "FloatConversion.h" #include "GraphicsContextPlatformPrivateCG.h" -#include "GraphicsContextPrivate.h" #include "ImageBuffer.h" #include "KURL.h" #include "Path.h" @@ -42,6 +41,7 @@ #include <wtf/MathExtras.h> #include <wtf/OwnArrayPtr.h> #include <wtf/RetainPtr.h> +#include <wtf/UnusedParam.h> #if PLATFORM(MAC) || PLATFORM(CHROMIUM) #include "WebCoreSystemInterface.h" @@ -107,10 +107,9 @@ CGColorSpaceRef linearRGBColorSpaceRef() #endif } -GraphicsContext::GraphicsContext(CGContextRef cgContext) - : m_common(createGraphicsContextPrivate()) - , m_data(new GraphicsContextPlatformPrivate(cgContext)) +void GraphicsContext::platformInit(CGContextRef cgContext) { + m_data = new GraphicsContextPlatformPrivate(cgContext); setPaintingDisabled(!cgContext); if (cgContext) { // Make sure the context starts in sync with our state. @@ -119,9 +118,8 @@ GraphicsContext::GraphicsContext(CGContextRef cgContext) } } -GraphicsContext::~GraphicsContext() +void GraphicsContext::platformDestroy() { - destroyGraphicsContextPrivate(m_common); delete m_data; } @@ -299,21 +297,12 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) // This method is only used to draw the little circles used in lists. void GraphicsContext::drawEllipse(const IntRect& rect) { - // FIXME: CG added CGContextAddEllipseinRect in Tiger, so we should be able to quite easily draw an ellipse. - // This code can only handle circles, not ellipses. But khtml only - // uses it for circles. - ASSERT(rect.width() == rect.height()); - if (paintingDisabled()) return; - CGContextRef context = platformContext(); - CGContextBeginPath(context); - float r = (float)rect.width() / 2; - CGContextAddArc(context, rect.x() + r, rect.y() + r, r, 0.0f, 2.0f * piFloat, 0); - CGContextClosePath(context); - - drawPath(); + Path path; + path.addEllipse(rect); + drawPath(path); } @@ -405,21 +394,22 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp CGContextRestoreGState(context); } -static void addConvexPolygonToContext(CGContextRef context, size_t numPoints, const FloatPoint* points) +static void addConvexPolygonToPath(Path& path, size_t numberOfPoints, const FloatPoint* points) { - CGContextBeginPath(context); - CGContextMoveToPoint(context, points[0].x(), points[0].y()); - for (size_t i = 1; i < numPoints; i++) - CGContextAddLineToPoint(context, points[i].x(), points[i].y()); - CGContextClosePath(context); + ASSERT(numberOfPoints > 0); + + path.moveTo(points[0]); + for (size_t i = 1; i < numberOfPoints; ++i) + path.addLineTo(points[i]); + path.closeSubpath(); } -void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool antialiased) +void GraphicsContext::drawConvexPolygon(size_t numberOfPoints, const FloatPoint* points, bool antialiased) { if (paintingDisabled()) return; - if (npoints <= 1) + if (numberOfPoints <= 1) return; CGContextRef context = platformContext(); @@ -427,28 +417,30 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points if (antialiased != shouldAntialias()) CGContextSetShouldAntialias(context, antialiased); - addConvexPolygonToContext(context, npoints, points); - drawPath(); + Path path; + addConvexPolygonToPath(path, numberOfPoints, points); + drawPath(path); if (antialiased != shouldAntialias()) CGContextSetShouldAntialias(context, shouldAntialias()); } -void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialias) +void GraphicsContext::clipConvexPolygon(size_t numberOfPoints, const FloatPoint* points, bool antialias) { if (paintingDisabled()) return; - if (numPoints <= 1) + if (numberOfPoints <= 1) return; CGContextRef context = platformContext(); if (antialias != shouldAntialias()) CGContextSetShouldAntialias(context, antialias); - - addConvexPolygonToContext(context, numPoints, points); - clipPath(RULE_NONZERO); + + Path path; + addConvexPolygonToPath(path, numberOfPoints, points); + clipPath(path, RULE_NONZERO); if (antialias != shouldAntialias()) CGContextSetShouldAntialias(context, shouldAntialias()); @@ -458,7 +450,7 @@ void GraphicsContext::applyStrokePattern() { CGContextRef cgContext = platformContext(); - RetainPtr<CGPatternRef> platformPattern(AdoptCF, m_common->state.strokePattern->createPlatformPattern(getCTM())); + RetainPtr<CGPatternRef> platformPattern(AdoptCF, m_state.strokePattern->createPlatformPattern(getCTM())); if (!platformPattern) return; @@ -473,7 +465,7 @@ void GraphicsContext::applyFillPattern() { CGContextRef cgContext = platformContext(); - RetainPtr<CGPatternRef> platformPattern(AdoptCF, m_common->state.fillPattern->createPlatformPattern(getCTM())); + RetainPtr<CGPatternRef> platformPattern(AdoptCF, m_state.fillPattern->createPlatformPattern(getCTM())); if (!platformPattern) return; @@ -511,21 +503,25 @@ static inline bool calculateDrawingMode(const GraphicsContextState& state, CGPat return shouldFill || shouldStroke; } -void GraphicsContext::drawPath() +void GraphicsContext::drawPath(const Path& path) { if (paintingDisabled()) return; CGContextRef context = platformContext(); - const GraphicsContextState& state = m_common->state; + const GraphicsContextState& state = m_state; if (state.fillGradient || state.strokeGradient) { // We don't have any optimized way to fill & stroke a path using gradients - fillPath(); - strokePath(); + // FIXME: Be smarter about this. + fillPath(path); + strokePath(path); return; } + CGContextBeginPath(context); + CGContextAddPath(context, path.platformPath()); + if (state.fillPattern) applyFillPattern(); if (state.strokePattern) @@ -544,48 +540,54 @@ static inline void fillPathWithFillRule(CGContextRef context, WindRule fillRule) CGContextFillPath(context); } -void GraphicsContext::fillPath() +void GraphicsContext::fillPath(const Path& path) { if (paintingDisabled()) return; CGContextRef context = platformContext(); - if (m_common->state.fillGradient) { + CGContextBeginPath(context); + CGContextAddPath(context, path.platformPath()); + + if (m_state.fillGradient) { CGContextSaveGState(context); if (fillRule() == RULE_EVENODD) CGContextEOClip(context); else CGContextClip(context); - CGContextConcatCTM(context, m_common->state.fillGradient->gradientSpaceTransform()); - m_common->state.fillGradient->paint(this); + CGContextConcatCTM(context, m_state.fillGradient->gradientSpaceTransform()); + m_state.fillGradient->paint(this); CGContextRestoreGState(context); return; } - if (m_common->state.fillPattern) + if (m_state.fillPattern) applyFillPattern(); fillPathWithFillRule(context, fillRule()); } -void GraphicsContext::strokePath() +void GraphicsContext::strokePath(const Path& path) { if (paintingDisabled()) return; CGContextRef context = platformContext(); - if (m_common->state.strokeGradient) { + CGContextBeginPath(context); + CGContextAddPath(context, path.platformPath()); + + if (m_state.strokeGradient) { CGContextSaveGState(context); CGContextReplacePathWithStrokedPath(context); CGContextClip(context); - CGContextConcatCTM(context, m_common->state.strokeGradient->gradientSpaceTransform()); - m_common->state.strokeGradient->paint(this); + CGContextConcatCTM(context, m_state.strokeGradient->gradientSpaceTransform()); + m_state.strokeGradient->paint(this); CGContextRestoreGState(context); return; } - if (m_common->state.strokePattern) + if (m_state.strokePattern) applyStrokePattern(); CGContextStrokePath(context); } @@ -597,16 +599,16 @@ void GraphicsContext::fillRect(const FloatRect& rect) CGContextRef context = platformContext(); - if (m_common->state.fillGradient) { + if (m_state.fillGradient) { CGContextSaveGState(context); CGContextClipToRect(context, rect); - CGContextConcatCTM(context, m_common->state.fillGradient->gradientSpaceTransform()); - m_common->state.fillGradient->paint(this); + CGContextConcatCTM(context, m_state.fillGradient->gradientSpaceTransform()); + m_state.fillGradient->paint(this); CGContextRestoreGState(context); return; } - if (m_common->state.fillPattern) + if (m_state.fillPattern) applyFillPattern(); CGContextFillRect(context, rect); } @@ -643,8 +645,7 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef Path path; path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight); - addPath(path); - fillPath(); + fillPath(path); if (oldFillColor != color || oldColorSpace != colorSpace) setCGFillColor(context, oldFillColor, oldColorSpace); @@ -669,19 +670,23 @@ void GraphicsContext::clipOut(const IntRect& rect) CGContextEOClip(platformContext()); } -void GraphicsContext::clipPath(WindRule clipRule) +void GraphicsContext::clipPath(const Path& path, WindRule clipRule) { if (paintingDisabled()) return; + if (path.isEmpty()) + return; + CGContextRef context = platformContext(); - if (!CGContextIsPathEmpty(context)) { - if (clipRule == RULE_EVENODD) - CGContextEOClip(context); - else - CGContextClip(context); - } + CGContextBeginPath(platformContext()); + CGContextAddPath(platformContext(), path.platformPath()); + + if (clipRule == RULE_EVENODD) + CGContextEOClip(context); + else + CGContextClip(context); } void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness) @@ -733,7 +738,7 @@ void GraphicsContext::setPlatformShadow(const FloatSize& offset, float blur, con CGFloat blurRadius = blur; CGContextRef context = platformContext(); - if (!m_common->state.shadowsIgnoreTransforms) { + if (!m_state.shadowsIgnoreTransforms) { CGAffineTransform userToBaseCTM = wkGetUserToBaseCTM(context); CGFloat A = userToBaseCTM.a * userToBaseCTM.a + userToBaseCTM.b * userToBaseCTM.b; @@ -808,18 +813,18 @@ void GraphicsContext::strokeRect(const FloatRect& r, float lineWidth) CGContextRef context = platformContext(); - if (m_common->state.strokeGradient) { + if (m_state.strokeGradient) { CGContextSaveGState(context); setStrokeThickness(lineWidth); CGContextAddRect(context, r); CGContextReplacePathWithStrokedPath(context); CGContextClip(context); - m_common->state.strokeGradient->paint(this); + m_state.strokeGradient->paint(this); CGContextRestoreGState(context); return; } - if (m_common->state.strokePattern) + if (m_state.strokePattern) applyStrokePattern(); CGContextStrokeRectWithWidth(context, r, lineWidth); } @@ -863,16 +868,6 @@ void GraphicsContext::setLineJoin(LineJoin join) } } -void GraphicsContext::beginPath() -{ - CGContextBeginPath(platformContext()); -} - -void GraphicsContext::addPath(const Path& path) -{ - CGContextAddPath(platformContext(), path.platformPath()); -} - void GraphicsContext::clip(const Path& path) { if (paintingDisabled()) @@ -1119,7 +1114,16 @@ InterpolationQuality GraphicsContext::imageInterpolationQuality() const return InterpolationDefault; } -void GraphicsContext::setPlatformTextDrawingMode(int mode) +void GraphicsContext::setAllowsFontSmoothing(bool allowsFontSmoothing) +{ + UNUSED_PARAM(allowsFontSmoothing); +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + CGContextRef context = platformContext(); + CGContextSetAllowsFontSmoothing(context, allowsFontSmoothing); +#endif +} + +void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode) { if (paintingDisabled()) return; @@ -1127,28 +1131,28 @@ void GraphicsContext::setPlatformTextDrawingMode(int mode) // Wow, wish CG had used bits here. CGContextRef context = platformContext(); switch (mode) { - case cTextInvisible: // Invisible + case TextModeInvisible: CGContextSetTextDrawingMode(context, kCGTextInvisible); break; - case cTextFill: // Fill + case TextModeFill: CGContextSetTextDrawingMode(context, kCGTextFill); break; - case cTextStroke: // Stroke + case TextModeStroke: CGContextSetTextDrawingMode(context, kCGTextStroke); break; - case 3: // Fill | Stroke + case TextModeFill | TextModeStroke: CGContextSetTextDrawingMode(context, kCGTextFillStroke); break; - case cTextClip: // Clip + case TextModeClip: CGContextSetTextDrawingMode(context, kCGTextClip); break; - case 5: // Fill | Clip + case TextModeFill | TextModeClip: CGContextSetTextDrawingMode(context, kCGTextFillClip); break; - case 6: // Stroke | Clip + case TextModeStroke | TextModeClip: CGContextSetTextDrawingMode(context, kCGTextStrokeClip); break; - case 7: // Fill | Stroke | Clip + case TextModeFill | TextModeStroke | TextModeClip: CGContextSetTextDrawingMode(context, kCGTextFillStrokeClip); break; default: @@ -1184,8 +1188,15 @@ void GraphicsContext::setPlatformShouldAntialias(bool enable) CGContextSetShouldAntialias(platformContext(), enable); } -#ifndef BUILDING_ON_TIGER // Tiger's setCompositeOperation() is defined in GraphicsContextMac.mm. -void GraphicsContext::setCompositeOperation(CompositeOperator mode) +void GraphicsContext::setPlatformShouldSmoothFonts(bool enable) +{ + if (paintingDisabled()) + return; + CGContextSetShouldSmoothFonts(platformContext(), enable); +} + +#ifndef BUILDING_ON_TIGER // Tiger's setPlatformCompositeOperation() is defined in GraphicsContextMac.mm. +void GraphicsContext::setPlatformCompositeOperation(CompositeOperator mode) { if (paintingDisabled()) return; diff --git a/WebCore/platform/graphics/cg/ImageBufferCG.cpp b/WebCore/platform/graphics/cg/ImageBufferCG.cpp index 640692a..7bc47f2 100644 --- a/WebCore/platform/graphics/cg/ImageBufferCG.cpp +++ b/WebCore/platform/graphics/cg/ImageBufferCG.cpp @@ -42,10 +42,57 @@ #include <wtf/Threading.h> #include <math.h> +#if defined(USE_IOSURFACE) +#include <IOSurface/IOSurface.h> +#endif + +#if PLATFORM(MAC) || PLATFORM(CHROMIUM) +#include "WebCoreSystemInterface.h" +#endif + using namespace std; namespace WebCore { +#if defined(USE_IOSURFACE) +static RetainPtr<IOSurfaceRef> createIOSurface(const IntSize& size) +{ + unsigned pixelFormat = 'BGRA'; + unsigned bytesPerElement = 4; + int width = size.width(); + int height = size.height(); + + unsigned long bytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, size.width() * bytesPerElement); + if (!bytesPerRow) + return 0; + + unsigned long allocSize = IOSurfaceAlignProperty(kIOSurfaceAllocSize, size.height() * bytesPerRow); + if (!allocSize) + return 0; + + const void *keys[6]; + const void *values[6]; + keys[0] = kIOSurfaceWidth; + values[0] = CFNumberCreate(0, kCFNumberIntType, &width); + keys[1] = kIOSurfaceHeight; + values[1] = CFNumberCreate(0, kCFNumberIntType, &height); + keys[2] = kIOSurfacePixelFormat; + values[2] = CFNumberCreate(0, kCFNumberIntType, &pixelFormat); + keys[3] = kIOSurfaceBytesPerElement; + values[3] = CFNumberCreate(0, kCFNumberIntType, &bytesPerElement); + keys[4] = kIOSurfaceBytesPerRow; + values[4] = CFNumberCreate(0, kCFNumberLongType, &bytesPerRow); + keys[5] = kIOSurfaceAllocSize; + values[5] = CFNumberCreate(0, kCFNumberLongType, &allocSize); + + RetainPtr<CFDictionaryRef> dict(AdoptCF, CFDictionaryCreate(0, keys, values, 6, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); + for (unsigned i = 0; i < 6; i++) + CFRelease(values[i]); + + return RetainPtr<IOSurfaceRef>(AdoptCF, IOSurfaceCreate(dict.get())); +} +#endif + static void releaseImageData(void*, const void* data, size_t) { fastFree(const_cast<void*>(data)); @@ -53,32 +100,32 @@ static void releaseImageData(void*, const void* data, size_t) ImageBufferData::ImageBufferData(const IntSize&) : m_data(0) +#if defined(USE_IOSURFACE) + , m_surface(0) +#endif { } -ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace imageColorSpace, bool& success) +ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace imageColorSpace, RenderingMode renderingMode, bool& success) : m_data(size) , m_size(size) + , m_accelerateRendering(renderingMode == Accelerated) { +#if !defined(USE_IOSURFACE) + ASSERT(renderingMode == Unaccelerated); +#endif success = false; // Make early return mean failure. if (size.width() < 0 || size.height() < 0) return; unsigned bytesPerRow = size.width(); - - // Protect against overflow - if (bytesPerRow > 0x3FFFFFFF) + if (bytesPerRow > 0x3FFFFFFF) // Protect against overflow return; bytesPerRow *= 4; m_data.m_bytesPerRow = bytesPerRow; - size_t dataSize = size.height() * bytesPerRow; - if (!tryFastCalloc(size.height(), bytesPerRow).getValue(m_data.m_data)) - return; - - ASSERT((reinterpret_cast<size_t>(m_data.m_data) & 2) == 0); - switch(imageColorSpace) { + switch (imageColorSpace) { case ColorSpaceDeviceRGB: m_data.m_colorSpace = deviceRGBColorSpaceRef(); break; @@ -90,9 +137,25 @@ ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace imageColorSpace, bool& break; } - m_data.m_bitmapInfo = kCGImageAlphaPremultipliedLast; - RetainPtr<CGContextRef> cgContext(AdoptCF, CGBitmapContextCreate(m_data.m_data, size.width(), size.height(), 8, bytesPerRow, - m_data.m_colorSpace, m_data.m_bitmapInfo)); + RetainPtr<CGContextRef> cgContext; + if (!m_accelerateRendering) { + if (!tryFastCalloc(size.height(), bytesPerRow).getValue(m_data.m_data)) + return; + ASSERT(!(reinterpret_cast<size_t>(m_data.m_data) & 2)); + + m_data.m_bitmapInfo = kCGImageAlphaPremultipliedLast; + cgContext.adoptCF(CGBitmapContextCreate(m_data.m_data, size.width(), size.height(), 8, bytesPerRow, m_data.m_colorSpace, m_data.m_bitmapInfo)); + // Create a live image that wraps the data. + m_data.m_dataProvider.adoptCF(CGDataProviderCreateWithData(0, m_data.m_data, dataSize, releaseImageData)); + } else { +#if defined(USE_IOSURFACE) + m_data.m_surface = createIOSurface(size); + cgContext.adoptCF(wkIOSurfaceContextCreate(m_data.m_surface.get(), size.width(), size.height(), m_data.m_colorSpace)); +#else + m_accelerateRendering = false; // Force to false on older platforms +#endif + } + if (!cgContext) return; @@ -100,9 +163,6 @@ ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace imageColorSpace, bool& m_context->scale(FloatSize(1, -1)); m_context->translate(0, -size.height()); success = true; - - // Create a live image that wraps the data. - m_data.m_dataProvider.adoptCF(CGDataProviderCreateWithData(0, m_data.m_data, dataSize, releaseImageData)); } ImageBuffer::~ImageBuffer() @@ -122,7 +182,14 @@ bool ImageBuffer::drawsUsingCopy() const PassRefPtr<Image> ImageBuffer::copyImage() const { // BitmapImage will release the passed in CGImage on destruction - return BitmapImage::create(CGBitmapContextCreateImage(context()->platformContext())); + CGImageRef ctxImage = 0; + if (!m_accelerateRendering) + ctxImage = CGBitmapContextCreateImage(context()->platformContext()); +#if defined(USE_IOSURFACE) + else + ctxImage = wkIOSurfaceContextCreateImage(context()->platformContext()); +#endif + return BitmapImage::create(ctxImage); } static CGImageRef cgImage(const IntSize& size, const ImageBufferData& data) @@ -134,34 +201,50 @@ static CGImageRef cgImage(const IntSize& size, const ImageBufferData& data) void ImageBuffer::draw(GraphicsContext* destContext, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, bool useLowQualityScale) { - if (destContext == context()) { - // We're drawing into our own buffer. In order for this to work, we need to copy the source buffer first. - RefPtr<Image> copy = copyImage(); - destContext->drawImage(copy.get(), ColorSpaceDeviceRGB, destRect, srcRect, op, useLowQualityScale); + if (!m_accelerateRendering) { + if (destContext == context()) { + // We're drawing into our own buffer. In order for this to work, we need to copy the source buffer first. + RefPtr<Image> copy = copyImage(); + destContext->drawImage(copy.get(), ColorSpaceDeviceRGB, destRect, srcRect, op, useLowQualityScale); + } else { + RefPtr<Image> imageForRendering = BitmapImage::create(cgImage(m_size, m_data)); + destContext->drawImage(imageForRendering.get(), styleColorSpace, destRect, srcRect, op, useLowQualityScale); + } } else { - RefPtr<Image> imageForRendering = BitmapImage::create(cgImage(m_size, m_data)); - destContext->drawImage(imageForRendering.get(), styleColorSpace, destRect, srcRect, op, useLowQualityScale); + RefPtr<Image> copy = copyImage(); + ColorSpace colorSpace = (destContext == context()) ? ColorSpaceDeviceRGB : styleColorSpace; + destContext->drawImage(copy.get(), colorSpace, destRect, srcRect, op, useLowQualityScale); } } void ImageBuffer::drawPattern(GraphicsContext* destContext, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect) { - if (destContext == context()) { - // We're drawing into our own buffer. In order for this to work, we need to copy the source buffer first. + if (!m_accelerateRendering) { + if (destContext == context()) { + // We're drawing into our own buffer. In order for this to work, we need to copy the source buffer first. + RefPtr<Image> copy = copyImage(); + copy->drawPattern(destContext, srcRect, patternTransform, phase, styleColorSpace, op, destRect); + } else { + RefPtr<Image> imageForRendering = BitmapImage::create(cgImage(m_size, m_data)); + imageForRendering->drawPattern(destContext, srcRect, patternTransform, phase, styleColorSpace, op, destRect); + } + } else { RefPtr<Image> copy = copyImage(); copy->drawPattern(destContext, srcRect, patternTransform, phase, styleColorSpace, op, destRect); - } else { - RefPtr<Image> imageForRendering = BitmapImage::create(cgImage(m_size, m_data)); - imageForRendering->drawPattern(destContext, srcRect, patternTransform, phase, styleColorSpace, op, destRect); } } void ImageBuffer::clip(GraphicsContext* context, const FloatRect& rect) const { - RetainPtr<CGImageRef> image(AdoptCF, cgImage(m_size, m_data)); - CGContextRef platformContext = context->platformContext(); + RetainPtr<CGImageRef> image; + if (!m_accelerateRendering) + image.adoptCF(cgImage(m_size, m_data)); +#if defined(USE_IOSURFACE) + else + image.adoptCF(wkIOSurfaceContextCreateImage(platformContext)); +#endif CGContextTranslateCTM(platformContext, rect.x(), rect.y() + rect.height()); CGContextScaleCTM(platformContext, 1, -1); CGContextClipToMask(platformContext, FloatRect(FloatPoint(), rect.size()), image.get()); @@ -170,7 +253,7 @@ void ImageBuffer::clip(GraphicsContext* context, const FloatRect& rect) const } template <Multiply multiplied> -PassRefPtr<ImageData> getImageData(const IntRect& rect, const ImageBufferData& imageData, const IntSize& size) +PassRefPtr<ImageData> getImageData(const IntRect& rect, const ImageBufferData& imageData, const IntSize& size, bool accelerateRendering) { PassRefPtr<ImageData> result = ImageData::create(rect.width(), rect.height()); unsigned char* data = result->data()->data()->data(); @@ -199,43 +282,83 @@ PassRefPtr<ImageData> getImageData(const IntRect& rect, const ImageBufferData& i if (endy > size.height()) endy = size.height(); int numRows = endy - originy; - - unsigned srcBytesPerRow = 4 * size.width(); + unsigned destBytesPerRow = 4 * rect.width(); - - // ::create ensures that all ImageBuffers have valid data, so we don't need to check it here. - unsigned char* srcRows = reinterpret_cast<unsigned char*>(imageData.m_data) + originy * srcBytesPerRow + originx * 4; unsigned char* destRows = data + desty * destBytesPerRow + destx * 4; - for (int y = 0; y < numRows; ++y) { - for (int x = 0; x < numColumns; x++) { - int basex = x * 4; - unsigned char alpha = srcRows[basex + 3]; - if (multiplied == Unmultiplied && alpha) { - destRows[basex] = (srcRows[basex] * 255) / alpha; - destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha; - destRows[basex + 2] = (srcRows[basex + 2] * 255) / alpha; - destRows[basex + 3] = alpha; - } else - reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0]; + + unsigned srcBytesPerRow; + unsigned char* srcRows; + + if (!accelerateRendering) { + srcBytesPerRow = 4 * size.width(); + srcRows = reinterpret_cast<unsigned char*>(imageData.m_data) + originy * srcBytesPerRow + originx * 4; + + for (int y = 0; y < numRows; ++y) { + for (int x = 0; x < numColumns; x++) { + int basex = x * 4; + unsigned char alpha = srcRows[basex + 3]; + if (multiplied == Unmultiplied && alpha) { + destRows[basex] = (srcRows[basex] * 255) / alpha; + destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha; + destRows[basex + 2] = (srcRows[basex + 2] * 255) / alpha; + destRows[basex + 3] = alpha; + } else + reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0]; + } + srcRows += srcBytesPerRow; + destRows += destBytesPerRow; + } + } else { +#if defined(USE_IOSURFACE) + IOSurfaceRef surface = imageData.m_surface.get(); + IOSurfaceLock(surface, kIOSurfaceLockReadOnly, 0); + srcBytesPerRow = IOSurfaceGetBytesPerRow(surface); + srcRows = (unsigned char*)(IOSurfaceGetBaseAddress(surface)) + originy * srcBytesPerRow + originx * 4; + + for (int y = 0; y < numRows; ++y) { + for (int x = 0; x < numColumns; x++) { + int basex = x * 4; + unsigned char alpha = srcRows[basex + 3]; + if (multiplied == Unmultiplied && alpha) { + destRows[basex] = (srcRows[basex + 2] * 255) / alpha; + destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha; + destRows[basex + 2] = (srcRows[basex] * 255) / alpha; + destRows[basex + 3] = alpha; + } else { + destRows[basex] = srcRows[basex + 2]; + destRows[basex + 1] = srcRows[basex + 1]; + destRows[basex + 2] = srcRows[basex]; + destRows[basex + 3] = alpha; + } + } + srcRows += srcBytesPerRow; + destRows += destBytesPerRow; } - srcRows += srcBytesPerRow; - destRows += destBytesPerRow; + IOSurfaceUnlock(surface, kIOSurfaceLockReadOnly, 0); +#else + ASSERT_NOT_REACHED(); +#endif } + return result; } PassRefPtr<ImageData> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const { - return getImageData<Unmultiplied>(rect, m_data, m_size); + if (m_accelerateRendering) + CGContextFlush(context()->platformContext()); + return getImageData<Unmultiplied>(rect, m_data, m_size, m_accelerateRendering); } PassRefPtr<ImageData> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const { - return getImageData<Premultiplied>(rect, m_data, m_size); + if (m_accelerateRendering) + CGContextFlush(context()->platformContext()); + return getImageData<Premultiplied>(rect, m_data, m_size, m_accelerateRendering); } template <Multiply multiplied> -void putImageData(ImageData*& source, const IntRect& sourceRect, const IntPoint& destPoint, ImageBufferData& imageData, const IntSize& size) +void putImageData(ImageData*& source, const IntRect& sourceRect, const IntPoint& destPoint, ImageBufferData& imageData, const IntSize& size, bool accelerateRendering) { ASSERT(sourceRect.width() > 0); ASSERT(sourceRect.height() > 0); @@ -264,35 +387,73 @@ void putImageData(ImageData*& source, const IntRect& sourceRect, const IntPoint& int numRows = endy - desty; unsigned srcBytesPerRow = 4 * source->width(); - unsigned destBytesPerRow = 4 * size.width(); - unsigned char* srcRows = source->data()->data()->data() + originy * srcBytesPerRow + originx * 4; - unsigned char* destRows = reinterpret_cast<unsigned char*>(imageData.m_data) + desty * destBytesPerRow + destx * 4; - for (int y = 0; y < numRows; ++y) { - for (int x = 0; x < numColumns; x++) { - int basex = x * 4; - unsigned char alpha = srcRows[basex + 3]; - if (multiplied == Unmultiplied && alpha != 255) { - destRows[basex] = (srcRows[basex] * alpha + 254) / 255; - destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255; - destRows[basex + 2] = (srcRows[basex + 2] * alpha + 254) / 255; - destRows[basex + 3] = alpha; - } else - reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0]; + unsigned destBytesPerRow; + unsigned char* destRows; + + if (!accelerateRendering) { + destBytesPerRow = 4 * size.width(); + destRows = reinterpret_cast<unsigned char*>(imageData.m_data) + desty * destBytesPerRow + destx * 4; + for (int y = 0; y < numRows; ++y) { + for (int x = 0; x < numColumns; x++) { + int basex = x * 4; + unsigned char alpha = srcRows[basex + 3]; + if (multiplied == Unmultiplied && alpha != 255) { + destRows[basex] = (srcRows[basex] * alpha + 254) / 255; + destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255; + destRows[basex + 2] = (srcRows[basex + 2] * alpha + 254) / 255; + destRows[basex + 3] = alpha; + } else + reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0]; + } + destRows += destBytesPerRow; + srcRows += srcBytesPerRow; + } + } else { +#if defined(USE_IOSURFACE) + IOSurfaceRef surface = imageData.m_surface.get(); + IOSurfaceLock(surface, 0, 0); + destBytesPerRow = IOSurfaceGetBytesPerRow(surface); + destRows = (unsigned char*)(IOSurfaceGetBaseAddress(surface)) + desty * destBytesPerRow + destx * 4; + + for (int y = 0; y < numRows; ++y) { + for (int x = 0; x < numColumns; x++) { + int basex = x * 4; + unsigned char alpha = srcRows[basex + 3]; + if (multiplied == Unmultiplied && alpha != 255) { + destRows[basex] = (srcRows[basex + 2] * alpha + 254) / 255; + destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255; + destRows[basex + 2] = (srcRows[basex] * alpha + 254) / 255; + destRows[basex + 3] = alpha; + } else { + destRows[basex] = srcRows[basex + 2]; + destRows[basex + 1] = srcRows[basex + 1]; + destRows[basex + 2] = srcRows[basex]; + destRows[basex + 3] = alpha; + } + } + destRows += destBytesPerRow; + srcRows += srcBytesPerRow; } - destRows += destBytesPerRow; - srcRows += srcBytesPerRow; + IOSurfaceUnlock(surface, 0, 0); +#else + ASSERT_NOT_REACHED(); +#endif } } void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) { - putImageData<Unmultiplied>(source, sourceRect, destPoint, m_data, m_size); + if (m_accelerateRendering) + CGContextFlush(context()->platformContext()); + putImageData<Unmultiplied>(source, sourceRect, destPoint, m_data, m_size, m_accelerateRendering); } void ImageBuffer::putPremultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) { - putImageData<Premultiplied>(source, sourceRect, destPoint, m_data, m_size); + if (m_accelerateRendering) + CGContextFlush(context()->platformContext()); + putImageData<Premultiplied>(source, sourceRect, destPoint, m_data, m_size, m_accelerateRendering); } static inline CFStringRef jpegUTI() @@ -332,7 +493,14 @@ String ImageBuffer::toDataURL(const String& mimeType, const double* quality) con { ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType)); - RetainPtr<CGImageRef> image(AdoptCF, CGBitmapContextCreateImage(context()->platformContext())); + RetainPtr<CGImageRef> image; + if (!m_accelerateRendering) + image.adoptCF(CGBitmapContextCreateImage(context()->platformContext())); +#if defined(USE_IOSURFACE) + else + image.adoptCF(wkIOSurfaceContextCreateImage(context()->platformContext())); +#endif + if (!image) return "data:,"; @@ -361,9 +529,7 @@ String ImageBuffer::toDataURL(const String& mimeType, const double* quality) con Vector<char> out; base64Encode(reinterpret_cast<const char*>(CFDataGetBytePtr(data.get())), CFDataGetLength(data.get()), out); - out.append('\0'); - return makeString("data:", mimeType, ";base64,", out.data()); + return makeString("data:", mimeType, ";base64,", out); } - } // namespace WebCore diff --git a/WebCore/platform/graphics/cg/ImageBufferData.h b/WebCore/platform/graphics/cg/ImageBufferData.h index 456c934..1f706ec 100644 --- a/WebCore/platform/graphics/cg/ImageBufferData.h +++ b/WebCore/platform/graphics/cg/ImageBufferData.h @@ -30,6 +30,7 @@ #include <wtf/RefPtr.h> #include <wtf/RetainPtr.h> +typedef struct __IOSurface *IOSurfaceRef; typedef struct CGColorSpace *CGColorSpaceRef; typedef struct CGDataProvider *CGDataProviderRef; typedef uint32_t CGBitmapInfo; @@ -48,6 +49,7 @@ public: CGBitmapInfo m_bitmapInfo; unsigned m_bytesPerRow; CGColorSpaceRef m_colorSpace; + RetainPtr<IOSurfaceRef> m_surface; }; } // namespace WebCore diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/WebCore/platform/graphics/cg/ImageSourceCG.cpp index f01c442..4ed8684 100644 --- a/WebCore/platform/graphics/cg/ImageSourceCG.cpp +++ b/WebCore/platform/graphics/cg/ImageSourceCG.cpp @@ -63,11 +63,11 @@ void sharedBufferRelease(void* info) } #endif -ImageSource::ImageSource(bool premultiplyAlpha, bool ignoreGammaAndColorProfile) +ImageSource::ImageSource(ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption) : m_decoder(0) // FIXME: m_premultiplyAlpha is ignored in cg at the moment. - , m_premultiplyAlpha(premultiplyAlpha) - , m_ignoreGammaAndColorProfile(ignoreGammaAndColorProfile) + , m_alphaOption(alphaOption) + , m_gammaAndColorProfileOption(gammaAndColorProfileOption) { } @@ -308,9 +308,10 @@ float ImageSource::frameDurationAtIndex(size_t index) } // Many annoying ads specify a 0 duration to make an image flash as quickly as possible. - // We follow WinIE's behavior and use a duration of 100 ms for any frames that specify - // a duration of <= 50 ms. See <http://bugs.webkit.org/show_bug.cgi?id=14413> or Radar 4051389 for more. - if (duration < 0.051f) + // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify + // a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082> + // for more information. + if (duration < 0.011f) return 0.100f; return duration; } diff --git a/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp b/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp index 5fe2122..ec40836 100644 --- a/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp +++ b/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp @@ -34,6 +34,16 @@ namespace WebCore { +TransformationMatrix::TransformationMatrix(const CGAffineTransform& t) +{ + setA(t.a); + setB(t.b); + setC(t.c); + setD(t.d); + setE(t.tx); + setF(t.ty); +} + TransformationMatrix::operator CGAffineTransform() const { return CGAffineTransformMake(narrowPrecisionToCGFloat(a()), diff --git a/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp b/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp index c2cde19..ad961aa 100644 --- a/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp @@ -56,9 +56,9 @@ Canvas2DLayerChromium::~Canvas2DLayerChromium() layerRendererContext()->deleteTexture(m_textureId); } -void Canvas2DLayerChromium::updateContents() +void Canvas2DLayerChromium::updateContentsIfDirty() { - if (!m_drawingBuffer) + if (!m_contentsDirty || !m_drawingBuffer) return; if (m_textureChanged) { // We have to generate a new backing texture. GraphicsContext3D* context = layerRendererContext(); @@ -68,7 +68,7 @@ void Canvas2DLayerChromium::updateContents() context->activeTexture(GraphicsContext3D::TEXTURE0); context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textureId); IntSize size = m_drawingBuffer->size(); - context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, size.width(), size.height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, 0); + context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, size.width(), size.height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE); // Set the min-mag filters to linear and wrap modes to GraphicsContext3D::CLAMP_TO_EDGE // to get around NPOT texture limitations of GLES. context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR); diff --git a/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h b/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h index 0031229..44ef050 100644 --- a/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h +++ b/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h @@ -46,7 +46,7 @@ public: static PassRefPtr<Canvas2DLayerChromium> create(DrawingBuffer*, GraphicsLayerChromium* owner); virtual ~Canvas2DLayerChromium(); virtual bool drawsContent() { return true; } - virtual void updateContents(); + virtual void updateContentsIfDirty(); void setTextureChanged(); unsigned textureId() const; diff --git a/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp b/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp index 375a74b..d00faf8 100644 --- a/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp @@ -36,11 +36,13 @@ #include "GraphicsContext3D.h" #include "LayerRendererChromium.h" +#include "LayerTexture.h" #include "RenderLayerBacking.h" #if PLATFORM(SKIA) #include "NativeImageSkia.h" #include "PlatformContextSkia.h" +#include "SkColorPriv.h" #include "skia/ext/platform_canvas.h" #elif PLATFORM(CG) #include <CoreGraphics/CGBitmapContext.h> @@ -68,8 +70,22 @@ ContentLayerChromium::SharedValues::SharedValues(GraphicsContext3D* context) " v_texCoord = a_texCoord; \n" "} \n"; +#if PLATFORM(SKIA) + // Color is in RGBA order. + char rgbaFragmentShaderString[] = + "precision mediump float; \n" + "varying vec2 v_texCoord; \n" + "uniform sampler2D s_texture; \n" + "uniform float alpha; \n" + "void main() \n" + "{ \n" + " vec4 texColor = texture2D(s_texture, v_texCoord); \n" + " gl_FragColor = texColor * alpha; \n" + "} \n"; +#endif + // Color is in BGRA order. - char fragmentShaderString[] = + char bgraFragmentShaderString[] = "precision mediump float; \n" "varying vec2 v_texCoord; \n" "uniform sampler2D s_texture; \n" @@ -80,6 +96,12 @@ ContentLayerChromium::SharedValues::SharedValues(GraphicsContext3D* context) " gl_FragColor = vec4(texColor.z, texColor.y, texColor.x, texColor.w) * alpha; \n" "} \n"; +#if PLATFORM(SKIA) + // Assuming the packing is either Skia default RGBA or Chromium default BGRA. + char* fragmentShaderString = SK_B32_SHIFT ? rgbaFragmentShaderString : bgraFragmentShaderString; +#else + char* fragmentShaderString = bgraFragmentShaderString; +#endif m_contentShaderProgram = createShaderProgram(m_context, vertexShaderString, fragmentShaderString); if (!m_contentShaderProgram) { LOG_ERROR("ContentLayerChromium: Failed to create shader program"); @@ -123,12 +145,7 @@ ContentLayerChromium::~ContentLayerChromium() void ContentLayerChromium::cleanupResources() { LayerChromium::cleanupResources(); - if (layerRenderer()) { - if (m_contentsTexture) { - layerRenderer()->deleteLayerTexture(m_contentsTexture); - m_contentsTexture = 0; - } - } + m_contentsTexture.clear(); } bool ContentLayerChromium::requiresClippedUpdateRect() const @@ -142,33 +159,7 @@ bool ContentLayerChromium::requiresClippedUpdateRect() const || !layerRenderer()->checkTextureSize(m_bounds)); } -void ContentLayerChromium::calculateClippedUpdateRect(IntRect& dirtyRect, IntRect& drawRect) const -{ - // For the given layer size and content rect, calculate: - // 1) The minimal texture space rectangle to be uploaded, returned in dirtyRect. - // 2) The rectangle to draw this texture in relative to the target render surface, returned in drawRect. - - ASSERT(m_targetRenderSurface); - const IntRect clipRect = m_targetRenderSurface->contentRect(); - - TransformationMatrix layerOriginTransform = drawTransform(); - layerOriginTransform.translate3d(-0.5 * m_bounds.width(), -0.5 * m_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()); - - TransformationMatrix targetToLayerMatrix = layerOriginTransform.inverse(); - IntRect clipRectInLayerCoords = targetToLayerMatrix.mapRect(clipRect); - clipRectInLayerCoords.intersect(IntRect(0, 0, m_bounds.width(), m_bounds.height())); - - dirtyRect = clipRectInLayerCoords; - - // Map back to the target surface coordinate system. - drawRect = layerOriginTransform.mapRect(dirtyRect); -} - -void ContentLayerChromium::updateContents() +void ContentLayerChromium::updateContentsIfDirty() { RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_owner->client()); if (!backing || backing->paintingGoesToWindow()) @@ -183,6 +174,7 @@ void ContentLayerChromium::updateContents() IntRect updateRect; IntSize requiredTextureSize; IntSize bitmapSize; + IntRect boundsRect(IntPoint(0, 0), m_bounds); // FIXME: Remove this test when tiled layers are implemented. if (requiresClippedUpdateRect()) { @@ -194,33 +186,57 @@ void ContentLayerChromium::updateContents() return; } - calculateClippedUpdateRect(dirtyRect, m_largeLayerDrawRect); - if (!layerRenderer()->checkTextureSize(m_largeLayerDrawRect.size())) { + // Calculate the region of this layer that is currently visible. + const IntRect clipRect = m_targetRenderSurface->contentRect(); + + TransformationMatrix layerOriginTransform = drawTransform(); + layerOriginTransform.translate3d(-0.5 * m_bounds.width(), -0.5 * m_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()); + + TransformationMatrix targetToLayerMatrix = layerOriginTransform.inverse(); + IntRect visibleRectInLayerCoords = targetToLayerMatrix.mapRect(clipRect); + visibleRectInLayerCoords.intersect(IntRect(0, 0, m_bounds.width(), m_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; return; } - // If the portion of the large layer that's visible hasn't changed - // then we don't need to update it, _unless_ its contents have changed - // in which case we only update the dirty bits. - if (m_largeLayerDirtyRect == dirtyRect) { - if (!m_dirtyRect.intersects(dirtyRect)) - return; - dirtyRect.intersect(IntRect(m_dirtyRect)); - updateRect = dirtyRect; - requiredTextureSize = m_largeLayerDirtyRect.size(); - } else { - m_largeLayerDirtyRect = dirtyRect; - requiredTextureSize = dirtyRect.size(); - updateRect = IntRect(IntPoint(0, 0), dirtyRect.size()); - } + // If the visible portion of the layer is different from the last upload, or if our backing + // texture has been evicted, then the whole layer is considered dirty. + if (visibleRectInLayerCoords != m_visibleRectInLayerCoords || !m_contentsTexture || !m_contentsTexture->isValid(requiredTextureSize, GraphicsContext3D::RGBA)) + m_dirtyRect = boundsRect; + m_visibleRectInLayerCoords = visibleRectInLayerCoords; + + // Calculate the portion of the dirty rectangle that is visible. m_dirtyRect is in layer space. + IntRect visibleDirtyRectInLayerSpace = enclosingIntRect(m_dirtyRect); + visibleDirtyRectInLayerSpace.intersect(visibleRectInLayerCoords); + + // What the rectangles mean: + // dirtyRect: The region of this layer that will be updated. + // updateRect: The region of the layer's texture that will be uploaded into. + // requiredTextureSize: is the required size of this layer's texture. + dirtyRect = visibleDirtyRectInLayerSpace; + updateRect = dirtyRect; + IntSize visibleRectOffsetInLayerCoords(visibleRectInLayerCoords.x(), visibleRectInLayerCoords.y()); + updateRect.move(-visibleRectOffsetInLayerCoords); + requiredTextureSize = visibleRectInLayerCoords.size(); } else { dirtyRect = IntRect(m_dirtyRect); - IntRect boundsRect(IntPoint(0, 0), m_bounds); requiredTextureSize = m_bounds; // If the texture needs to be reallocated then we must redraw the entire // contents of the layer. - if (requiredTextureSize != m_allocatedTextureSize) + if (!m_contentsTexture || !m_contentsTexture->isValid(requiredTextureSize, GraphicsContext3D::RGBA)) dirtyRect = boundsRect; else { // Clip the dirtyRect to the size of the layer to avoid drawing @@ -289,36 +305,28 @@ void ContentLayerChromium::updateContents() #error "Need to implement for your platform." #endif - unsigned textureId = m_contentsTexture; - if (!textureId) - textureId = layerRenderer()->createLayerTexture(); - if (pixels) - updateTextureRect(pixels, bitmapSize, requiredTextureSize, updateRect, textureId); + updateTextureRect(pixels, requiredTextureSize, updateRect); } -void ContentLayerChromium::updateTextureRect(void* pixels, const IntSize& bitmapSize, const IntSize& requiredTextureSize, const IntRect& updateRect, unsigned textureId) +void ContentLayerChromium::updateTextureRect(void* pixels, const IntSize& requiredTextureSize, const IntRect& updateRect) { if (!pixels) return; GraphicsContext3D* context = layerRendererContext(); - context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId); + if (!m_contentsTexture) + m_contentsTexture = LayerTexture::create(context, layerRenderer()->textureManager()); - // If the texture id or size changed since last time then we need to tell GL - // to re-allocate a texture. - if (m_contentsTexture != textureId || requiredTextureSize != m_allocatedTextureSize) { - ASSERT(bitmapSize == requiredTextureSize); - GLC(context, context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, requiredTextureSize.width(), requiredTextureSize.height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, pixels)); - - m_contentsTexture = textureId; - m_allocatedTextureSize = requiredTextureSize; - } else { - ASSERT(updateRect.width() <= m_allocatedTextureSize.width() && updateRect.height() <= m_allocatedTextureSize.height()); - ASSERT(updateRect.width() == bitmapSize.width() && updateRect.height() == bitmapSize.height()); - GLC(context, context->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, updateRect.x(), updateRect.y(), updateRect.width(), updateRect.height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, pixels)); + if (!m_contentsTexture->reserve(requiredTextureSize, GraphicsContext3D::RGBA)) { + m_skipsDraw = true; + return; } + m_contentsTexture->bindTexture(); + + GLC(context, context->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, updateRect.x(), updateRect.y(), updateRect.width(), updateRect.height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, pixels)); + m_dirtyRect.setSize(FloatSize()); // Large layers always stay dirty, because they need to update when the content rect changes. m_contentsDirty = requiresClippedUpdateRect(); @@ -330,21 +338,22 @@ void ContentLayerChromium::draw() return; ASSERT(layerRenderer()); + const ContentLayerChromium::SharedValues* sv = layerRenderer()->contentLayerSharedValues(); ASSERT(sv && sv->initialized()); GraphicsContext3D* context = layerRendererContext(); GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); - GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_contentsTexture)); + m_contentsTexture->bindTexture(); layerRenderer()->useShader(sv->contentShaderProgram()); GLC(context, context->uniform1i(sv->shaderSamplerLocation(), 0)); if (requiresClippedUpdateRect()) { float m43 = drawTransform().m43(); TransformationMatrix transform; - transform.translate3d(m_largeLayerDrawRect.center().x(), m_largeLayerDrawRect.center().y(), m43); + transform.translate3d(m_layerCenterInSurfaceCoords.x(), m_layerCenterInSurfaceCoords.y(), m43); drawTexturedQuad(context, layerRenderer()->projectionMatrix(), - transform, m_largeLayerDrawRect.width(), - m_largeLayerDrawRect.height(), drawOpacity(), + transform, m_visibleRectInLayerCoords.width(), + m_visibleRectInLayerCoords.height(), drawOpacity(), sv->shaderMatrixLocation(), sv->shaderAlphaLocation()); } else { drawTexturedQuad(context, layerRenderer()->projectionMatrix(), @@ -352,6 +361,7 @@ void ContentLayerChromium::draw() drawOpacity(), sv->shaderMatrixLocation(), sv->shaderAlphaLocation()); } + m_contentsTexture->unreserve(); } } diff --git a/WebCore/platform/graphics/chromium/ContentLayerChromium.h b/WebCore/platform/graphics/chromium/ContentLayerChromium.h index 32c2c49..dc1630b 100644 --- a/WebCore/platform/graphics/chromium/ContentLayerChromium.h +++ b/WebCore/platform/graphics/chromium/ContentLayerChromium.h @@ -35,9 +35,12 @@ #if USE(ACCELERATED_COMPOSITING) #include "LayerChromium.h" +#include "TextureManager.h" namespace WebCore { +class LayerTexture; + // A Layer that requires a GraphicsContext to render its contents. class ContentLayerChromium : public LayerChromium { friend class LayerRendererChromium; @@ -46,7 +49,7 @@ public: virtual ~ContentLayerChromium(); - virtual void updateContents(); + virtual void updateContentsIfDirty(); virtual void draw(); virtual bool drawsContent() { return m_owner && m_owner->drawsContent(); } @@ -74,22 +77,20 @@ public: }; protected: - ContentLayerChromium(GraphicsLayerChromium* owner); + explicit ContentLayerChromium(GraphicsLayerChromium* owner); - void updateTextureRect(void* pixels, const IntSize& bitmapSize, const IntSize& requiredTextureSize, - const IntRect& updateRect, unsigned textureId); + void updateTextureRect(void* pixels, const IntSize& requiredTextureSize, const IntRect& updateRect); virtual void cleanupResources(); bool requiresClippedUpdateRect() const; - unsigned m_contentsTexture; - IntSize m_allocatedTextureSize; + OwnPtr<LayerTexture> m_contentsTexture; bool m_skipsDraw; private: - void calculateClippedUpdateRect(IntRect& dirtyRect, IntRect& drawRect) const; - IntRect m_largeLayerDrawRect; - IntRect m_largeLayerDirtyRect; + + IntRect m_visibleRectInLayerCoords; + FloatPoint m_layerCenterInSurfaceCoords; }; } diff --git a/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp b/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp index 0395bc2..507c227 100644 --- a/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp +++ b/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp @@ -60,7 +60,7 @@ static unsigned generateColorTexture(GraphicsContext3D* context, const IntSize& context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST); context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE); context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE); - context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, size.width(), size.height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, 0); + context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, size.width(), size.height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE); context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, offscreenColorTexture, 0); return offscreenColorTexture; diff --git a/WebCore/platform/graphics/chromium/Extensions3DChromium.h b/WebCore/platform/graphics/chromium/Extensions3DChromium.h index 5fda020..d120424 100644 --- a/WebCore/platform/graphics/chromium/Extensions3DChromium.h +++ b/WebCore/platform/graphics/chromium/Extensions3DChromium.h @@ -42,6 +42,7 @@ public: // Extensions3D methods. virtual bool supports(const String&); + virtual void ensureEnabled(const String&); virtual int getGraphicsResetStatusARB(); virtual void blitFramebuffer(long srcX0, long srcY0, long srcX1, long srcY1, long dstX0, long dstY0, long dstX1, long dstY1, unsigned long mask, unsigned long filter) { } virtual void renderbufferStorageMultisample(unsigned long target, unsigned long samples, unsigned long internalformat, unsigned long width, unsigned long height) { } diff --git a/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp index 347a3fb..2c79815 100644 --- a/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp @@ -50,11 +50,6 @@ using std::min; namespace WebCore { -void FontCache::platformInit() -{ - // Not needed on Windows. -} - // FIXME: consider adding to WebKit String class static bool charactersAreAllASCII(const String& s) { @@ -329,6 +324,86 @@ static bool fontContainsCharacter(const FontPlatformData* fontData, return cmap->contains(character); } +// Tries the given font and save it |outFontFamilyName| if it succeeds. +static SimpleFontData* fontDataFromDescriptionAndLogFont(FontCache* fontCache, const FontDescription& fontDescription, const LOGFONT& font, wchar_t* outFontFamilyName) +{ + SimpleFontData* fontData = fontCache->getCachedFontData(fontDescription, font.lfFaceName); + if (fontData) + memcpy(outFontFamilyName, font.lfFaceName, sizeof(font.lfFaceName)); + return fontData; +} + +static LONG toGDIFontWeight(FontWeight fontWeight) +{ + static LONG gdiFontWeights[] = { + FW_THIN, // FontWeight100 + FW_EXTRALIGHT, // FontWeight200 + FW_LIGHT, // FontWeight300 + FW_NORMAL, // FontWeight400 + FW_MEDIUM, // FontWeight500 + FW_SEMIBOLD, // FontWeight600 + FW_BOLD, // FontWeight700 + FW_EXTRABOLD, // FontWeight800 + FW_HEAVY // FontWeight900 + }; + return gdiFontWeights[fontWeight]; +} + +static void FillLogFont(const FontDescription& fontDescription, LOGFONT* winfont) +{ + // The size here looks unusual. The negative number is intentional. + // Unlike WebKit trunk, we don't multiply the size by 32. That seems to be + // some kind of artifact of their CG backend, or something. + winfont->lfHeight = -fontDescription.computedPixelSize(); + winfont->lfWidth = 0; + winfont->lfEscapement = 0; + winfont->lfOrientation = 0; + winfont->lfUnderline = false; + winfont->lfStrikeOut = false; + winfont->lfCharSet = DEFAULT_CHARSET; + winfont->lfOutPrecision = OUT_TT_ONLY_PRECIS; + winfont->lfQuality = ChromiumBridge::layoutTestMode() ? NONANTIALIASED_QUALITY : DEFAULT_QUALITY; // Honor user's desktop settings. + winfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; + winfont->lfItalic = fontDescription.italic(); + winfont->lfWeight = toGDIFontWeight(fontDescription.weight()); +} + +struct TraitsInFamilyProcData { + TraitsInFamilyProcData(const AtomicString& familyName) + : m_familyName(familyName) + { + } + + const AtomicString& m_familyName; + HashSet<unsigned> m_traitsMasks; +}; + +static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam) +{ + TraitsInFamilyProcData* procData = reinterpret_cast<TraitsInFamilyProcData*>(lParam); + + unsigned traitsMask = 0; + traitsMask |= logFont->lfItalic ? FontStyleItalicMask : FontStyleNormalMask; + traitsMask |= FontVariantNormalMask; + LONG weight = logFont->lfWeight; + traitsMask |= weight == FW_THIN ? FontWeight100Mask : + weight == FW_EXTRALIGHT ? FontWeight200Mask : + weight == FW_LIGHT ? FontWeight300Mask : + weight == FW_NORMAL ? FontWeight400Mask : + weight == FW_MEDIUM ? FontWeight500Mask : + weight == FW_SEMIBOLD ? FontWeight600Mask : + weight == FW_BOLD ? FontWeight700Mask : + weight == FW_EXTRABOLD ? FontWeight800Mask : + FontWeight900Mask; + procData->m_traitsMasks.add(traitsMask); + return 1; +} + +void FontCache::platformInit() +{ + // Not needed on Windows. +} + // Given the desired base font, this will create a SimpleFontData for a specific // font that can be used to render the given range of characters. const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length) @@ -438,73 +513,43 @@ SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& desc else if (generic == FontDescription::MonospaceFamily) fontStr = courierStr; - return getCachedFontData(description, fontStr); -} - -static LONG toGDIFontWeight(FontWeight fontWeight) -{ - static LONG gdiFontWeights[] = { - FW_THIN, // FontWeight100 - FW_EXTRALIGHT, // FontWeight200 - FW_LIGHT, // FontWeight300 - FW_NORMAL, // FontWeight400 - FW_MEDIUM, // FontWeight500 - FW_SEMIBOLD, // FontWeight600 - FW_BOLD, // FontWeight700 - FW_EXTRABOLD, // FontWeight800 - FW_HEAVY // FontWeight900 - }; - return gdiFontWeights[fontWeight]; -} - -static void FillLogFont(const FontDescription& fontDescription, LOGFONT* winfont) -{ - // The size here looks unusual. The negative number is intentional. - // Unlike WebKit trunk, we don't multiply the size by 32. That seems to be - // some kind of artifact of their CG backend, or something. - winfont->lfHeight = -fontDescription.computedPixelSize(); - winfont->lfWidth = 0; - winfont->lfEscapement = 0; - winfont->lfOrientation = 0; - winfont->lfUnderline = false; - winfont->lfStrikeOut = false; - winfont->lfCharSet = DEFAULT_CHARSET; - winfont->lfOutPrecision = OUT_TT_ONLY_PRECIS; - winfont->lfQuality = ChromiumBridge::layoutTestMode() ? NONANTIALIASED_QUALITY : DEFAULT_QUALITY; // Honor user's desktop settings. - winfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; - winfont->lfItalic = fontDescription.italic(); - winfont->lfWeight = toGDIFontWeight(fontDescription.weight()); -} - -struct TraitsInFamilyProcData { - TraitsInFamilyProcData(const AtomicString& familyName) - : m_familyName(familyName) - { + SimpleFontData* simpleFont = getCachedFontData(description, fontStr); + if (simpleFont) + return simpleFont; + + // Fall back to system fonts as Win Safari does because this function must + // return a valid font. Once we find a valid system font, we save its name + // to a static variable and use it to prevent trying system fonts again. + static wchar_t fallbackFontName[LF_FACESIZE] = {0}; + if (fallbackFontName[0]) + return getCachedFontData(description, fallbackFontName); + + // Fall back to the DEFAULT_GUI_FONT if no known Unicode fonts are available. + if (HFONT defaultGUIFont = static_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT))) { + LOGFONT defaultGUILogFont; + GetObject(defaultGUIFont, sizeof(defaultGUILogFont), &defaultGUILogFont); + if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, defaultGUILogFont, fallbackFontName)) + return simpleFont; } - const AtomicString& m_familyName; - HashSet<unsigned> m_traitsMasks; -}; - -static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam) -{ - TraitsInFamilyProcData* procData = reinterpret_cast<TraitsInFamilyProcData*>(lParam); + // Fall back to Non-client metrics fonts. + NONCLIENTMETRICS nonClientMetrics = {0}; + nonClientMetrics.cbSize = sizeof(nonClientMetrics); + if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(nonClientMetrics), &nonClientMetrics, 0)) { + if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, nonClientMetrics.lfMessageFont, fallbackFontName)) + return simpleFont; + if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, nonClientMetrics.lfMenuFont, fallbackFontName)) + return simpleFont; + if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, nonClientMetrics.lfStatusFont, fallbackFontName)) + return simpleFont; + if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, nonClientMetrics.lfCaptionFont, fallbackFontName)) + return simpleFont; + if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, nonClientMetrics.lfSmCaptionFont, fallbackFontName)) + return simpleFont; + } - unsigned traitsMask = 0; - traitsMask |= logFont->lfItalic ? FontStyleItalicMask : FontStyleNormalMask; - traitsMask |= FontVariantNormalMask; - LONG weight = logFont->lfWeight; - traitsMask |= weight == FW_THIN ? FontWeight100Mask : - weight == FW_EXTRALIGHT ? FontWeight200Mask : - weight == FW_LIGHT ? FontWeight300Mask : - weight == FW_NORMAL ? FontWeight400Mask : - weight == FW_MEDIUM ? FontWeight500Mask : - weight == FW_SEMIBOLD ? FontWeight600Mask : - weight == FW_BOLD ? FontWeight700Mask : - weight == FW_EXTRABOLD ? FontWeight800Mask : - FontWeight900Mask; - procData->m_traitsMasks.add(traitsMask); - return 1; + ASSERT_NOT_REACHED(); + return 0; } void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks) diff --git a/WebCore/platform/graphics/chromium/FontCacheLinux.cpp b/WebCore/platform/graphics/chromium/FontCacheLinux.cpp index 4399d35..bd33927 100644 --- a/WebCore/platform/graphics/chromium/FontCacheLinux.cpp +++ b/WebCore/platform/graphics/chromium/FontCacheLinux.cpp @@ -150,7 +150,8 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD name, fontDescription.computedSize(), (style & SkTypeface::kBold) && !tf->isBold(), - (style & SkTypeface::kItalic) && !tf->isItalic()); + (style & SkTypeface::kItalic) && !tf->isItalic(), + fontDescription.orientation()); tf->unref(); return result; } diff --git a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp index 8a77501..1a00833 100644 --- a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp @@ -35,6 +35,7 @@ #include "ChromiumBridge.h" #include "FontFallbackList.h" #include "GlyphBuffer.h" +#include "NotImplemented.h" #include "PlatformContextSkia.h" #include "SimpleFontData.h" #include "SkiaFontWin.h" @@ -276,7 +277,8 @@ bool TransparencyAwareGlyphPainter::drawGlyphs(int numGlyphs, FloatSize shadowOffset; float shadowBlur; Color shadowColor; - if (m_graphicsContext->getShadow(shadowOffset, shadowBlur, shadowColor)) { + ColorSpace shadowColorSpace; + if (m_graphicsContext->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace)) { // If there is a shadow and this code is reached, windowsCanHandleDrawTextShadow() // will have already returned true during the ctor initiatization of m_useGDI ASSERT(shadowColor.alpha() == 255); @@ -488,7 +490,8 @@ void Font::drawComplexText(GraphicsContext* graphicsContext, FloatSize shadowOffset; float shadowBlur; Color shadowColor; - if (graphicsContext->getShadow(shadowOffset, shadowBlur, shadowColor) && windowsCanHandleDrawTextShadow(graphicsContext)) { + ColorSpace shadowColorSpace; + if (graphicsContext->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace) && windowsCanHandleDrawTextShadow(graphicsContext)) { COLORREF textColor = skia::SkColorToCOLORREF(SkColorSetARGB(255, shadowColor.red(), shadowColor.green(), shadowColor.blue())); COLORREF savedTextColor = GetTextColor(hdc); SetTextColor(hdc, textColor); @@ -505,6 +508,11 @@ void Font::drawComplexText(GraphicsContext* graphicsContext, context->canvas()->endPlatformPaint(); } +void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const +{ + notImplemented(); +} + float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */, GlyphOverflow* /* glyphOverflow */) const { UniscribeHelperTextRun state(run, *this); diff --git a/WebCore/platform/graphics/chromium/FontLinux.cpp b/WebCore/platform/graphics/chromium/FontLinux.cpp index 79b2caf..5e3e5b2 100644 --- a/WebCore/platform/graphics/chromium/FontLinux.cpp +++ b/WebCore/platform/graphics/chromium/FontLinux.cpp @@ -91,32 +91,50 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, // patches may be upstreamed to WebKit so we always use the slower path // here. const GlyphBufferAdvance* adv = glyphBuffer.advances(from); - SkAutoSTMalloc<32, SkPoint> storage(numGlyphs); + SkAutoSTMalloc<32, SkPoint> storage(numGlyphs), storage2(numGlyphs), storage3(numGlyphs); SkPoint* pos = storage.get(); + SkPoint* vPosBegin = storage2.get(); + SkPoint* vPosEnd = storage3.get(); + bool isVertical = font->orientation() == Vertical; for (int i = 0; i < numGlyphs; i++) { + SkScalar myWidth = SkFloatToScalar(adv[i].width()); pos[i].set(x, y); - x += SkFloatToScalar(adv[i].width()); + if (isVertical) { + vPosBegin[i].set(x + myWidth, y); + vPosEnd[i].set(x + myWidth, y - myWidth); + } + x += myWidth; y += SkFloatToScalar(adv[i].height()); } gc->platformContext()->prepareForSoftwareDraw(); SkCanvas* canvas = gc->platformContext()->canvas(); - int textMode = gc->platformContext()->getTextDrawingMode(); + TextDrawingModeFlags textMode = gc->platformContext()->getTextDrawingMode(); // We draw text up to two times (once for fill, once for stroke). - if (textMode & cTextFill) { + if (textMode & TextModeFill) { SkPaint paint; gc->platformContext()->setupPaintForFilling(&paint); font->platformData().setupPaint(&paint); adjustTextRenderMode(&paint, gc->platformContext()); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); paint.setColor(gc->fillColor().rgb()); - canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint); + + if (isVertical) { + SkPath path; + for (int i = 0; i < numGlyphs; ++i) { + path.reset(); + path.moveTo(vPosBegin[i]); + path.lineTo(vPosEnd[i]); + canvas->drawTextOnPath(glyphs + i, 2, path, 0, paint); + } + } else + canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint); } - if ((textMode & cTextStroke) + if ((textMode & TextModeStroke) && gc->platformContext()->getStrokeStyle() != NoStroke && gc->platformContext()->getStrokeThickness() > 0) { @@ -127,13 +145,22 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); paint.setColor(gc->strokeColor().rgb()); - if (textMode & cTextFill) { + if (textMode & TextModeFill) { // If we also filled, we don't want to draw shadows twice. // See comment in FontChromiumWin.cpp::paintSkiaText() for more details. SkSafeUnref(paint.setLooper(0)); } - canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint); + if (isVertical) { + SkPath path; + for (int i = 0; i < numGlyphs; ++i) { + path.reset(); + path.moveTo(vPosBegin[i]); + path.lineTo(vPosEnd[i]); + canvas->drawTextOnPath(glyphs + i, 2, path, 0, paint); + } + } else + canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint); } } @@ -341,7 +368,6 @@ void TextRunWalker::setPadding(int padding) // amount to each space. The last space gets the smaller amount, if // any. unsigned numWordBreaks = 0; - bool isRTL = m_iterateBackwards; for (unsigned i = 0; i < m_item.stringLength; i++) { if (isWordBreak(i)) @@ -382,7 +408,7 @@ bool TextRunWalker::nextScriptRun() // (and the glyphs in each A, C and T section are backwards too) if (!hb_utf16_script_run_prev(&m_numCodePoints, &m_item.item, m_run.characters(), m_run.length(), &m_indexOfNextScriptRun)) return false; - m_currentFontData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false, false).fontData; + m_currentFontData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false).fontData; } else { if (!hb_utf16_script_run_next(&m_numCodePoints, &m_item.item, m_run.characters(), m_run.length(), &m_indexOfNextScriptRun)) return false; @@ -394,10 +420,10 @@ bool TextRunWalker::nextScriptRun() // in the harfbuzz data structures to e.g. pick the correct script's shaper. // So we allow that to run first, then do a second pass over the range it // found and take the largest subregion that stays within a single font. - m_currentFontData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false, false).fontData; + m_currentFontData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false).fontData; unsigned endOfRun; for (endOfRun = 1; endOfRun < m_item.item.length; ++endOfRun) { - const SimpleFontData* nextFontData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos + endOfRun], false, false).fontData; + const SimpleFontData* nextFontData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos + endOfRun], false).fontData; if (nextFontData != m_currentFontData) break; } @@ -423,7 +449,7 @@ float TextRunWalker::widthOfFullRun() void TextRunWalker::setupFontForScriptRun() { - const FontData* fontData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false, false).fontData; + const FontData* fontData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false).fontData; const FontPlatformData& platformData = fontData->fontDataForCharacter(' ')->platformData(); m_item.face = platformData.harfbuzzFace(); void* opaquePlatformData = const_cast<FontPlatformData*>(&platformData); @@ -524,7 +550,7 @@ void TextRunWalker::setGlyphXPositions(bool isRTL) // Whitespace must be laid out in logical order, so when inserting // spaces in RTL (but iterating in LTR order) we must insert spaces // _before_ the next glyph. - if (i + 1 >= m_item.num_glyphs || m_item.attributes[i + 1].clusterStart) + if (static_cast<unsigned>(i + 1) >= m_item.num_glyphs || m_item.attributes[i + 1].clusterStart) position += m_letterSpacing; position += determineWordBreakSpacing(logClustersIndex); @@ -541,7 +567,7 @@ void TextRunWalker::setGlyphXPositions(bool isRTL) position += truncateFixedPointToInteger(m_item.advances[i]); } } else { - for (int i = 0; i < m_item.num_glyphs; ++i) { + for (size_t i = 0; i < m_item.num_glyphs; ++i) { m_glyphs16[i] = m_item.glyphs[i]; double offsetX = truncateFixedPointToInteger(m_item.offsets[i].x); m_xPositions[i] = m_offsetX + position + offsetX; @@ -556,7 +582,7 @@ void TextRunWalker::setGlyphXPositions(bool isRTL) if (m_item.attributes[i].clusterStart) advance += m_letterSpacing; - while (logClustersIndex < m_item.item.length && logClusters()[logClustersIndex] == i) + while (static_cast<unsigned>(logClustersIndex) < m_item.item.length && logClusters()[logClustersIndex] == i) logClustersIndex++; position += advance; @@ -652,9 +678,9 @@ void Font::drawComplexText(GraphicsContext* gc, const TextRun& run, return; SkCanvas* canvas = gc->platformContext()->canvas(); - int textMode = gc->platformContext()->getTextDrawingMode(); - bool fill = textMode & cTextFill; - bool stroke = (textMode & cTextStroke) + TextDrawingModeFlags textMode = gc->platformContext()->getTextDrawingMode(); + bool fill = textMode & TextModeFill; + bool stroke = (textMode & TextModeStroke) && gc->platformContext()->getStrokeStyle() != NoStroke && gc->platformContext()->getStrokeThickness() > 0; @@ -691,6 +717,11 @@ void Font::drawComplexText(GraphicsContext* gc, const TextRun& run, } } +void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const +{ + notImplemented(); +} + float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */, GlyphOverflow* /* glyphOverflow */) const { TextRunWalker walker(run, 0, this); @@ -708,7 +739,7 @@ static int glyphIndexForXPositionInScriptRun(const TextRunWalker& walker, int x) for (glyphIndex = walker.length() - 1; glyphIndex >= 0; --glyphIndex) { // When iterating LTR over RTL text, we must include the whitespace // _before_ the glyph, so no + 1 here. - if (x < (walker.length() - glyphIndex) * letterSpacing + truncateFixedPointToInteger(advances[glyphIndex])) + if (x < (static_cast<int>(walker.length()) - glyphIndex) * letterSpacing + truncateFixedPointToInteger(advances[glyphIndex])) break; x -= truncateFixedPointToInteger(advances[glyphIndex]); } diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp index 3944775..42942cc 100644 --- a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp +++ b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp @@ -73,18 +73,20 @@ FontPlatformData::FontPlatformData(const FontPlatformData& src) , m_textSize(src.m_textSize) , m_fakeBold(src.m_fakeBold) , m_fakeItalic(src.m_fakeItalic) + , m_orientation(src.m_orientation) , 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) +FontPlatformData::FontPlatformData(SkTypeface* tf, const char* family, float textSize, bool fakeBold, bool fakeItalic, FontOrientation orientation) : m_typeface(tf) , m_family(family) , m_textSize(textSize) , m_fakeBold(fakeBold) , m_fakeItalic(fakeItalic) + , m_orientation(orientation) { SkSafeRef(m_typeface); querySystemForRenderStyle(); @@ -116,6 +118,7 @@ FontPlatformData& FontPlatformData::operator=(const FontPlatformData& src) m_fakeBold = src.m_fakeBold; m_fakeItalic = src.m_fakeItalic; m_harfbuzzFace = src.m_harfbuzzFace; + m_orientation = src.m_orientation; m_style = src.m_style; return *this; @@ -179,13 +182,14 @@ bool FontPlatformData::operator==(const FontPlatformData& a) const && m_textSize == a.m_textSize && m_fakeBold == a.m_fakeBold && m_fakeItalic == a.m_fakeItalic + && m_orientation == a.m_orientation && m_style == a.m_style; } unsigned FontPlatformData::hash() const { unsigned h = SkTypeface::UniqueID(m_typeface); - h ^= 0x01010101 * ((static_cast<int>(m_fakeBold) << 1) | static_cast<int>(m_fakeItalic)); + h ^= 0x01010101 * ((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/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h index 694a945..43771d7 100644 --- a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h +++ b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h @@ -72,6 +72,7 @@ public: , m_textSize(0) , m_fakeBold(false) , m_fakeItalic(false) + , m_orientation(Horizontal) { } FontPlatformData(float textSize, bool fakeBold, bool fakeItalic) @@ -79,10 +80,11 @@ public: , m_textSize(textSize) , m_fakeBold(fakeBold) , m_fakeItalic(fakeItalic) + , m_orientation(Horizontal) { } FontPlatformData(const FontPlatformData&); - FontPlatformData(SkTypeface*, const char* name, float textSize, bool fakeBold, bool fakeItalic); + FontPlatformData(SkTypeface*, const char* name, float textSize, bool fakeBold, bool fakeItalic, FontOrientation orientation = Horizontal); FontPlatformData(const FontPlatformData& src, float textSize); ~FontPlatformData(); @@ -106,7 +108,7 @@ public: unsigned hash() const; float size() const { return m_textSize; } - FontOrientation orientation() const { return Horizontal; } // FIXME: Implement. + FontOrientation orientation() const { return m_orientation; } bool operator==(const FontPlatformData&) const; FontPlatformData& operator=(const FontPlatformData&); @@ -153,6 +155,7 @@ private: float m_textSize; bool m_fakeBold; bool m_fakeItalic; + FontOrientation m_orientation; FontRenderStyle m_style; mutable RefPtr<RefCountedHarfbuzzFace> m_harfbuzzFace; diff --git a/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp b/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp index 21dcd8e..5e8d148 100644 --- a/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp @@ -115,11 +115,6 @@ void GraphicsLayerChromium::setName(const String& inName) GraphicsLayer::setName(name); } -NativeLayer GraphicsLayerChromium::nativeLayer() const -{ - return m_layer.get(); -} - bool GraphicsLayerChromium::setChildren(const Vector<GraphicsLayer*>& children) { bool childrenChanged = GraphicsLayer::setChildren(children); diff --git a/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h b/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h index 214058d..130c25c 100644 --- a/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h +++ b/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h @@ -47,9 +47,6 @@ public: virtual void setName(const String&); - // for hosting this GraphicsLayer in a native layer hierarchy - virtual NativeLayer nativeLayer() const; - virtual bool setChildren(const Vector<GraphicsLayer*>&); virtual void addChild(GraphicsLayer*); virtual void addChildAtIndex(GraphicsLayer*, int index); diff --git a/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp b/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp index adcbb82..cd299c1 100644 --- a/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp @@ -36,6 +36,7 @@ #include "Image.h" #include "LayerRendererChromium.h" +#include "LayerTexture.h" #if PLATFORM(SKIA) #include "NativeImageSkia.h" @@ -71,7 +72,7 @@ void ImageLayerChromium::setContents(Image* contents) setNeedsDisplay(); } -void ImageLayerChromium::updateContents() +void ImageLayerChromium::updateContentsIfDirty() { ASSERT(layerRenderer()); @@ -79,12 +80,11 @@ void ImageLayerChromium::updateContents() 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::updateContents(); + ContentLayerChromium::updateContentsIfDirty(); return; } void* pixels = 0; - IntSize requiredTextureSize; IntSize bitmapSize; NativeImagePtr nativeImage = m_contents->nativeImageForCurrentFrame(); @@ -93,22 +93,33 @@ void ImageLayerChromium::updateContents() // The layer contains an Image. NativeImageSkia* skiaImage = static_cast<NativeImageSkia*>(nativeImage); const SkBitmap* skiaBitmap = skiaImage; - requiredTextureSize = IntSize(skiaBitmap->width(), skiaBitmap->height()); + bitmapSize = IntSize(skiaBitmap->width(), skiaBitmap->height()); ASSERT(skiaBitmap); +#elif PLATFORM(CG) + // NativeImagePtr is a CGImageRef on Mac OS X. + int width = CGImageGetWidth(nativeImage); + int height = CGImageGetHeight(nativeImage); + bitmapSize = IntSize(width, height); +#endif + + // Clip the dirty rect to the bitmap dimensions. + IntRect dirtyRect(m_dirtyRect); + dirtyRect.intersect(IntRect(IntPoint(0, 0), bitmapSize)); + + if (!m_contentsTexture || !m_contentsTexture->isValid(bitmapSize, GraphicsContext3D::RGBA)) + dirtyRect = IntRect(IntPoint(0, 0), bitmapSize); + else if (!m_contentsDirty) { + m_contentsTexture->reserve(bitmapSize, GraphicsContext3D::RGBA); + return; + } +#if PLATFORM(SKIA) SkAutoLockPixels lock(*skiaBitmap); SkBitmap::Config skiaConfig = skiaBitmap->config(); // FIXME: do we need to support more image configurations? - if (skiaConfig == SkBitmap::kARGB_8888_Config) { + if (skiaConfig == SkBitmap::kARGB_8888_Config) pixels = skiaBitmap->getPixels(); - bitmapSize = IntSize(skiaBitmap->width(), skiaBitmap->height()); - } #elif PLATFORM(CG) - // NativeImagePtr is a CGImageRef on Mac OS X. - int width = CGImageGetWidth(nativeImage); - int height = CGImageGetHeight(nativeImage); - requiredTextureSize = IntSize(width, height); - bitmapSize = requiredTextureSize; // FIXME: we should get rid of this temporary copy where possible. int tempRowBytes = width * 4; Vector<uint8_t> tempVector; @@ -145,16 +156,8 @@ void ImageLayerChromium::updateContents() #error "Need to implement for your platform." #endif - unsigned textureId = m_contentsTexture; - if (!textureId) - textureId = layerRenderer()->createLayerTexture(); - - // Clip the dirty rect to the bitmap dimensions. - IntRect dirtyRect(m_dirtyRect); - dirtyRect.intersect(IntRect(IntPoint(0, 0), bitmapSize)); - if (pixels) - updateTextureRect(pixels, bitmapSize, requiredTextureSize, dirtyRect, textureId); + updateTextureRect(pixels, bitmapSize, dirtyRect); } } diff --git a/WebCore/platform/graphics/chromium/ImageLayerChromium.h b/WebCore/platform/graphics/chromium/ImageLayerChromium.h index b91f04a..a5c1450 100644 --- a/WebCore/platform/graphics/chromium/ImageLayerChromium.h +++ b/WebCore/platform/graphics/chromium/ImageLayerChromium.h @@ -49,7 +49,7 @@ class ImageLayerChromium : public ContentLayerChromium { public: static PassRefPtr<ImageLayerChromium> create(GraphicsLayerChromium* owner = 0); - virtual void updateContents(); + virtual void updateContentsIfDirty(); virtual bool drawsContent() { return m_contents; } void setContents(Image* image); diff --git a/WebCore/platform/graphics/chromium/LayerChromium.cpp b/WebCore/platform/graphics/chromium/LayerChromium.cpp index fab5d7b..b7ab098 100644 --- a/WebCore/platform/graphics/chromium/LayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/LayerChromium.cpp @@ -59,7 +59,7 @@ static unsigned loadShader(GraphicsContext3D* context, unsigned type, const char String sourceString(shaderSource); GLC(context, context->shaderSource(shader, sourceString)); GLC(context, context->compileShader(shader)); - int compiled; + int compiled = 0; GLC(context, context->getShaderiv(shader, GraphicsContext3D::COMPILE_STATUS, &compiled)); if (!compiled) { GLC(context, context->deleteShader(shader)); @@ -228,7 +228,7 @@ unsigned LayerChromium::createShaderProgram(GraphicsContext3D* context, const ch GLC(context, context->bindAttribLocation(programObject, s_texCoordAttribLocation, "a_texCoord")); GLC(context, context->linkProgram(programObject)); - int linked; + int linked = 0; GLC(context, context->getProgramiv(programObject, GraphicsContext3D::LINK_STATUS, &linked)); if (!linked) { LOG_ERROR("Failed to link shader program"); diff --git a/WebCore/platform/graphics/chromium/LayerChromium.h b/WebCore/platform/graphics/chromium/LayerChromium.h index 86f3580..ac95285 100644 --- a/WebCore/platform/graphics/chromium/LayerChromium.h +++ b/WebCore/platform/graphics/chromium/LayerChromium.h @@ -151,15 +151,13 @@ public: void setOwner(GraphicsLayerChromium* owner) { m_owner = owner; } - bool contentsDirty() { return m_contentsDirty; } - // Returns the rect containtaining this layer in the current view's coordinate system. const IntRect getDrawRect() const; // These methods typically need to be overwritten by derived classes. virtual bool drawsContent() { return false; } - virtual void updateContents() { }; - virtual void draw() { }; + virtual void updateContentsIfDirty() { } + virtual void draw() { } void drawDebugBorder(); @@ -197,6 +195,12 @@ public: LayerRendererChromium* layerRenderer() const { return m_layerRenderer.get(); } + static unsigned createShaderProgram(GraphicsContext3D*, const char* vertexShaderSource, const char* fragmentShaderSource); + + static void drawTexturedQuad(GraphicsContext3D*, const TransformationMatrix& projectionMatrix, const TransformationMatrix& layerMatrix, + float width, float height, float opacity, + int matrixLocation, int alphaLocation); + protected: GraphicsLayerChromium* m_owner; LayerChromium(GraphicsLayerChromium* owner); @@ -211,14 +215,8 @@ protected: // Returns true if any of the layer's descendants has content to draw. bool descendantsDrawContent(); - static void drawTexturedQuad(GraphicsContext3D*, const TransformationMatrix& projectionMatrix, const TransformationMatrix& layerMatrix, - float width, float height, float opacity, - int matrixLocation, int alphaLocation); - static void toGLMatrix(float*, const TransformationMatrix&); - static unsigned createShaderProgram(GraphicsContext3D*, const char* vertexShaderSource, const char* fragmentShaderSource); - IntSize m_bounds; FloatRect m_dirtyRect; bool m_contentsDirty; diff --git a/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp b/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp index 91580cc..882baae 100644 --- a/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp +++ b/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp @@ -37,7 +37,9 @@ #include "Canvas2DLayerChromium.h" #include "GraphicsContext3D.h" #include "LayerChromium.h" +#include "LayerTexture.h" #include "NotImplemented.h" +#include "TextureManager.h" #include "WebGLLayerChromium.h" #if PLATFORM(SKIA) #include "NativeImageSkia.h" @@ -48,6 +50,9 @@ namespace WebCore { +// FIXME: Make this limit adjustable and give it a useful value. +static size_t textureMemoryLimitBytes = 64 * 1024 * 1024; + static TransformationMatrix orthoMatrix(float left, float right, float bottom, float top) { float deltaX = right - left; @@ -98,7 +103,6 @@ LayerRendererChromium::LayerRendererChromium(PassRefPtr<GraphicsContext3D> conte : m_rootLayerTextureId(0) , m_rootLayerTextureWidth(0) , m_rootLayerTextureHeight(0) - , m_textureLayerShaderProgram(0) , m_rootLayer(0) , m_scrollPosition(IntPoint(-1, -1)) , m_currentShader(0) @@ -164,7 +168,7 @@ void LayerRendererChromium::setRootLayerCanvasSize(const IntSize& size) void LayerRendererChromium::useShader(unsigned programId) { if (programId != m_currentShader) { - GLC(m_context, m_context->useProgram(programId)); + GLC(m_context.get(), m_context->useProgram(programId)); m_currentShader = programId; } } @@ -173,7 +177,7 @@ void LayerRendererChromium::useShader(unsigned programId) // root layer texture. It resizes the root layer texture and scrolls its // contents as needed. It also sets up common GL state used by the rest // of the layer drawing code. -void LayerRendererChromium::prepareToDrawLayers(const IntRect& visibleRect, const IntRect& contentRect, +void LayerRendererChromium::prepareToDrawLayers(const IntRect& visibleRect, const IntRect& contentRect, const IntPoint& scrollPosition) { ASSERT(m_hardwareCompositing); @@ -183,8 +187,8 @@ void LayerRendererChromium::prepareToDrawLayers(const IntRect& visibleRect, cons makeContextCurrent(); - GLC(m_context, m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_rootLayerTextureId)); - + GLC(m_context.get(), m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_rootLayerTextureId)); + bool skipScroll = false; // If the size of the visible area has changed then allocate a new texture @@ -195,8 +199,7 @@ void LayerRendererChromium::prepareToDrawLayers(const IntRect& visibleRect, cons if (visibleRectWidth != m_rootLayerTextureWidth || visibleRectHeight != m_rootLayerTextureHeight) { m_rootLayerTextureWidth = visibleRectWidth; m_rootLayerTextureHeight = visibleRectHeight; - - GLC(m_context, m_context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, m_rootLayerTextureWidth, m_rootLayerTextureHeight, 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, 0)); + GLC(m_context.get(), m_context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, m_rootLayerTextureWidth, m_rootLayerTextureHeight, 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE)); // Reset the current render surface to force an update of the viewport and // projection matrix next time useRenderSurface is called. @@ -208,17 +211,17 @@ void LayerRendererChromium::prepareToDrawLayers(const IntRect& visibleRect, cons } // The GL viewport covers the entire visible area, including the scrollbars. - GLC(m_context, m_context->viewport(0, 0, visibleRectWidth, visibleRectHeight)); + GLC(m_context.get(), m_context->viewport(0, 0, visibleRectWidth, visibleRectHeight)); // Bind the common vertex attributes used for drawing all the layers. LayerChromium::prepareForDraw(layerSharedValues()); // FIXME: These calls can be made once, when the compositor context is initialized. - GLC(m_context, m_context->disable(GraphicsContext3D::DEPTH_TEST)); - GLC(m_context, m_context->disable(GraphicsContext3D::CULL_FACE)); + GLC(m_context.get(), m_context->disable(GraphicsContext3D::DEPTH_TEST)); + GLC(m_context.get(), m_context->disable(GraphicsContext3D::CULL_FACE)); - // Blending disabled by default. Root layer alpha channel on Windows is incorrect when Skia uses ClearType. - GLC(m_context, m_context->disable(GraphicsContext3D::BLEND)); + // Blending disabled by default. Root layer alpha channel on Windows is incorrect when Skia uses ClearType. + GLC(m_context.get(), m_context->disable(GraphicsContext3D::BLEND)); if (m_scrollPosition == IntPoint(-1, -1)) { m_scrollPosition = scrollPosition; @@ -244,13 +247,14 @@ void LayerRendererChromium::prepareToDrawLayers(const IntRect& visibleRect, cons 0.5 * visibleRect.height() + scrollDelta.y(), 0); scrolledLayerMatrix.scale3d(1, -1, 1); - useShader(m_textureLayerShaderProgram); - GLC(m_context, m_context->uniform1i(m_textureLayerShaderSamplerLocation, 0)); + const RenderSurfaceChromium::SharedValues* rsv = renderSurfaceSharedValues(); + useShader(rsv->shaderProgram()); + GLC(m_context.get(), m_context->uniform1i(rsv->shaderSamplerLocation(), 0)); LayerChromium::drawTexturedQuad(m_context.get(), m_projectionMatrix, scrolledLayerMatrix, visibleRect.width(), visibleRect.height(), 1, - m_textureLayerShaderMatrixLocation, m_textureLayerShaderAlphaLocation); + rsv->shaderMatrixLocation(), rsv->shaderAlphaLocation()); - GLC(m_context, m_context->copyTexSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, 0, 0, 0, 0, contentRect.width(), contentRect.height())); + GLC(m_context.get(), m_context->copyTexSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, 0, 0, 0, 0, contentRect.width(), contentRect.height())); } m_scrollPosition = scrollPosition; @@ -263,7 +267,7 @@ void LayerRendererChromium::updateRootLayerTextureRect(const IntRect& updateRect if (!m_rootLayer) return; - GLC(m_context, m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_rootLayerTextureId)); + GLC(m_context.get(), m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_rootLayerTextureId)); // Update the root layer texture. ASSERT((updateRect.right() <= m_rootLayerTextureWidth) @@ -282,7 +286,7 @@ void LayerRendererChromium::updateRootLayerTextureRect(const IntRect& updateRect #error "Need to implement for your platform." #endif // Copy the contents of the updated rect to the root layer texture. - GLC(m_context, m_context->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, updateRect.x(), updateRect.y(), updateRect.width(), updateRect.height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, pixels)); + GLC(m_context.get(), m_context->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, updateRect.x(), updateRect.y(), updateRect.width(), updateRect.height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, pixels)); } void LayerRendererChromium::drawLayers(const IntRect& visibleRect, const IntRect& contentRect) @@ -300,22 +304,22 @@ void LayerRendererChromium::drawLayers(const IntRect& visibleRect, const IntRect m_context->clearColor(0, 0, 1, 1); m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT); - GLC(m_context, m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_rootLayerTextureId)); + GLC(m_context.get(), m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_rootLayerTextureId)); // Render the root layer using a quad that takes up the entire visible area of the window. // We reuse the shader program used by ContentLayerChromium. const ContentLayerChromium::SharedValues* contentLayerValues = contentLayerSharedValues(); useShader(contentLayerValues->contentShaderProgram()); - GLC(m_context, m_context->uniform1i(contentLayerValues->shaderSamplerLocation(), 0)); + GLC(m_context.get(), m_context->uniform1i(contentLayerValues->shaderSamplerLocation(), 0)); // Mask out writes to alpha channel: ClearType via Skia results in invalid // zero alpha values on text glyphs. The root layer is always opaque. - GLC(m_context, m_context->colorMask(true, true, true, false)); + GLC(m_context.get(), m_context->colorMask(true, true, true, false)); TransformationMatrix layerMatrix; layerMatrix.translate3d(visibleRect.width() * 0.5f, visibleRect.height() * 0.5f, 0); LayerChromium::drawTexturedQuad(m_context.get(), m_projectionMatrix, layerMatrix, visibleRect.width(), visibleRect.height(), 1, contentLayerValues->shaderMatrixLocation(), contentLayerValues->shaderAlphaLocation()); - GLC(m_context, m_context->colorMask(true, true, true, true)); + GLC(m_context.get(), m_context->colorMask(true, true, true, true)); // Set the root visible/content rects --- used by subsequent drawLayers calls. m_rootVisibleRect = visibleRect; @@ -336,9 +340,9 @@ void LayerRendererChromium::drawLayers(const IntRect& visibleRect, const IntRect // The shader used to render layers returns pre-multiplied alpha colors // so we need to send the blending mode appropriately. - GLC(m_context, m_context->enable(GraphicsContext3D::BLEND)); - GLC(m_context, m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA)); - GLC(m_context, m_context->enable(GraphicsContext3D::SCISSOR_TEST)); + GLC(m_context.get(), m_context->enable(GraphicsContext3D::BLEND)); + GLC(m_context.get(), m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA)); + GLC(m_context.get(), m_context->enable(GraphicsContext3D::SCISSOR_TEST)); // Update the contents of the render surfaces. We traverse the array from // back to front to guarantee that nested render surfaces get rendered in the @@ -352,22 +356,23 @@ void LayerRendererChromium::drawLayers(const IntRect& visibleRect, const IntRect if (!renderSurfaceLayer->m_renderSurface->m_layerList.size()) continue; - useRenderSurface(renderSurfaceLayer->m_renderSurface.get()); - if (renderSurfaceLayer != m_rootLayer) { - GLC(m_context, m_context->disable(GraphicsContext3D::SCISSOR_TEST)); - GLC(m_context, m_context->clearColor(0, 0, 0, 0)); - GLC(m_context, m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT)); - GLC(m_context, m_context->enable(GraphicsContext3D::SCISSOR_TEST)); + if (useRenderSurface(renderSurfaceLayer->m_renderSurface.get())) { + if (renderSurfaceLayer != m_rootLayer) { + GLC(m_context.get(), m_context->disable(GraphicsContext3D::SCISSOR_TEST)); + GLC(m_context.get(), m_context->clearColor(0, 0, 0, 0)); + GLC(m_context.get(), m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT)); + GLC(m_context.get(), m_context->enable(GraphicsContext3D::SCISSOR_TEST)); + } + + Vector<LayerChromium*>& layerList = renderSurfaceLayer->m_renderSurface->m_layerList; + ASSERT(layerList.size()); + for (unsigned layerIndex = 0; layerIndex < layerList.size(); ++layerIndex) + drawLayer(layerList[layerIndex], renderSurfaceLayer->m_renderSurface.get()); } - - Vector<LayerChromium*>& layerList = renderSurfaceLayer->m_renderSurface->m_layerList; - ASSERT(layerList.size()); - for (unsigned layerIndex = 0; layerIndex < layerList.size(); ++layerIndex) - drawLayer(layerList[layerIndex], renderSurfaceLayer->m_renderSurface.get()); } - GLC(m_context, m_context->disable(GraphicsContext3D::SCISSOR_TEST)); - GLC(m_context, m_context->disable(GraphicsContext3D::BLEND)); + GLC(m_context.get(), m_context->disable(GraphicsContext3D::SCISSOR_TEST)); + GLC(m_context.get(), m_context->disable(GraphicsContext3D::BLEND)); } void LayerRendererChromium::finish() @@ -394,7 +399,7 @@ void LayerRendererChromium::getFramebufferPixels(void *pixels, const IntRect& re makeContextCurrent(); - GLC(m_context, m_context->readPixels(rect.x(), rect.y(), rect.width(), rect.height(), + GLC(m_context.get(), m_context->readPixels(rect.x(), rect.y(), rect.width(), rect.height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, pixels)); } @@ -402,14 +407,14 @@ void LayerRendererChromium::getFramebufferPixels(void *pixels, const IntRect& re unsigned LayerRendererChromium::createLayerTexture() { unsigned textureId = 0; - GLC(m_context, textureId = m_context->createTexture()); - GLC(m_context, m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId)); + GLC(m_context.get(), textureId = m_context->createTexture()); + GLC(m_context.get(), m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId)); // Do basic linear filtering on resize. - GLC(m_context, m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR)); - GLC(m_context, m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR)); + GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR)); + GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR)); // NPOT textures in GL ES only work when the wrap mode is set to GraphicsContext3D::CLAMP_TO_EDGE. - GLC(m_context, m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE)); - GLC(m_context, m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE)); + GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE)); + GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE)); return textureId; } @@ -418,7 +423,7 @@ void LayerRendererChromium::deleteLayerTexture(unsigned textureId) if (!textureId) return; - GLC(m_context, m_context->deleteTexture(textureId)); + GLC(m_context.get(), m_context->deleteTexture(textureId)); } // Returns true if any part of the layer falls within the visibleRect @@ -507,7 +512,7 @@ void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const Tr // Layer's opacity will be applied when drawing the render surface. renderSurface->m_drawOpacity = layer->opacity(); if (layer->superlayer()->preserves3D()) - renderSurface->m_drawOpacity *= layer->superlayer()->m_drawOpacity; + renderSurface->m_drawOpacity *= layer->superlayer()->drawOpacity(); layer->m_drawOpacity = 1; TransformationMatrix layerOriginTransform = combinedTransform; @@ -598,7 +603,7 @@ void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const Tr if (sublayer->m_renderSurface) { RenderSurfaceChromium* sublayerRenderSurface = sublayer->m_renderSurface.get(); - const IntRect& contentRect = sublayerRenderSurface->m_contentRect; + const IntRect& contentRect = sublayerRenderSurface->contentRect(); FloatRect sublayerRect(-0.5 * contentRect.width(), -0.5 * contentRect.height(), contentRect.width(), contentRect.height()); layer->m_drawableContentRect.unite(enclosingIntRect(sublayerRenderSurface->m_drawTransform.mapRect(sublayerRect))); @@ -664,17 +669,17 @@ bool LayerRendererChromium::useRenderSurface(RenderSurfaceChromium* renderSurfac m_currentRenderSurface = renderSurface; if (renderSurface == m_defaultRenderSurface) { - GLC(m_context, m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0)); + GLC(m_context.get(), m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0)); setDrawViewportRect(renderSurface->m_contentRect, true); return true; } - GLC(m_context, m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_offscreenFramebufferId)); + GLC(m_context.get(), m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_offscreenFramebufferId)); - renderSurface->prepareContentsTexture(); + if (!renderSurface->prepareContentsTexture()) + return false; - GLC(m_context, m_context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, - GraphicsContext3D::TEXTURE_2D, renderSurface->m_contentsTextureId, 0)); + renderSurface->m_contentsTexture->framebufferTexture2D(); #if !defined ( NDEBUG ) if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) { @@ -690,15 +695,7 @@ bool LayerRendererChromium::useRenderSurface(RenderSurfaceChromium* renderSurfac void LayerRendererChromium::drawLayer(LayerChromium* layer, RenderSurfaceChromium* targetSurface) { if (layer->m_renderSurface && layer->m_renderSurface != targetSurface) { - GLC(m_context, m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, layer->m_renderSurface->m_contentsTextureId)); - useShader(m_textureLayerShaderProgram); - - setScissorToRect(layer->m_renderSurface->m_scissorRect); - - IntRect contentRect = layer->m_renderSurface->m_contentRect; - LayerChromium::drawTexturedQuad(m_context.get(), m_projectionMatrix, layer->m_renderSurface->m_drawTransform, - contentRect.width(), contentRect.height(), layer->m_renderSurface->m_drawOpacity, - m_textureLayerShaderMatrixLocation, m_textureLayerShaderAlphaLocation); + layer->m_renderSurface->draw(); return; } @@ -721,12 +718,8 @@ void LayerRendererChromium::drawLayer(LayerChromium* layer, RenderSurfaceChromiu if (layer->drawsContent()) { // Update the contents of the layer if necessary. - if (layer->contentsDirty()) { - // Update the backing texture contents for any dirty portion of the layer. - layer->updateContents(); - m_context->makeContextCurrent(); - } - + layer->updateContentsIfDirty(); + m_context->makeContextCurrent(); layer->draw(); } @@ -748,7 +741,7 @@ void LayerRendererChromium::setScissorToRect(const IntRect& scissorRect) scissorY = m_currentRenderSurface->m_contentRect.height() - (scissorRect.bottom() - m_currentRenderSurface->m_contentRect.y()); else scissorY = scissorRect.y() - m_currentRenderSurface->m_contentRect.y(); - GLC(m_context, m_context->scissor(scissorX, scissorY, scissorRect.width(), scissorRect.height())); + GLC(m_context.get(), m_context->scissor(scissorX, scissorY, scissorRect.width(), scissorRect.height())); } bool LayerRendererChromium::makeContextCurrent() @@ -774,7 +767,7 @@ void LayerRendererChromium::setDrawViewportRect(const IntRect& drawRect, bool fl m_projectionMatrix = orthoMatrix(drawRect.x(), drawRect.right(), drawRect.bottom(), drawRect.y()); else m_projectionMatrix = orthoMatrix(drawRect.x(), drawRect.right(), drawRect.y(), drawRect.bottom()); - GLC(m_context, m_context->viewport(0, 0, drawRect.width(), drawRect.height())); + GLC(m_context.get(), m_context->viewport(0, 0, drawRect.width(), drawRect.height())); } @@ -789,46 +782,6 @@ bool LayerRendererChromium::initializeSharedObjects() { makeContextCurrent(); - // The following program composites layers whose contents are the results of a previous - // render operation and therefore doesn't perform any color swizzling. It is used - // in scrolling and for compositing offscreen textures. - char textureLayerVertexShaderString[] = - "attribute vec4 a_position; \n" - "attribute vec2 a_texCoord; \n" - "uniform mat4 matrix; \n" - "varying vec2 v_texCoord; \n" - "void main() \n" - "{ \n" - " gl_Position = matrix * a_position; \n" - " v_texCoord = a_texCoord; \n" - "} \n"; - char textureLayerFragmentShaderString[] = - "precision mediump float; \n" - "varying vec2 v_texCoord; \n" - "uniform sampler2D s_texture; \n" - "uniform float alpha; \n" - "void main() \n" - "{ \n" - " vec4 texColor = texture2D(s_texture, v_texCoord); \n" - " gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha; \n" - "} \n"; - - m_textureLayerShaderProgram = LayerChromium::createShaderProgram(m_context.get(), textureLayerVertexShaderString, textureLayerFragmentShaderString); - if (!m_textureLayerShaderProgram) { - LOG_ERROR("LayerRendererChromium: Failed to create scroll shader program"); - cleanupSharedObjects(); - return false; - } - - GLC(m_context, m_textureLayerShaderSamplerLocation = m_context->getUniformLocation(m_textureLayerShaderProgram, "s_texture")); - GLC(m_context, m_textureLayerShaderMatrixLocation = m_context->getUniformLocation(m_textureLayerShaderProgram, "matrix")); - GLC(m_context, m_textureLayerShaderAlphaLocation = m_context->getUniformLocation(m_textureLayerShaderProgram, "alpha")); - if (m_textureLayerShaderSamplerLocation == -1 || m_textureLayerShaderMatrixLocation == -1 || m_textureLayerShaderAlphaLocation == -1) { - LOG_ERROR("Failed to initialize texture layer shader."); - cleanupSharedObjects(); - return false; - } - // Create a texture object to hold the contents of the root layer. m_rootLayerTextureId = createLayerTexture(); if (!m_rootLayerTextureId) { @@ -838,28 +791,31 @@ bool LayerRendererChromium::initializeSharedObjects() } // Turn off filtering for the root layer to avoid blurring from the repeated // writes and reads to the framebuffer that happen while scrolling. - GLC(m_context, m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_rootLayerTextureId)); - GLC(m_context, m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST)); - GLC(m_context, m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::NEAREST)); + GLC(m_context.get(), m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_rootLayerTextureId)); + GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST)); + GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::NEAREST)); // Get the max texture size supported by the system. - GLC(m_context, m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSize)); + m_maxTextureSize = 0; + GLC(m_context.get(), m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSize)); // Create an FBO for doing offscreen rendering. - GLC(m_context, m_offscreenFramebufferId = m_context->createFramebuffer()); + GLC(m_context.get(), m_offscreenFramebufferId = m_context->createFramebuffer()); m_layerSharedValues = adoptPtr(new LayerChromium::SharedValues(m_context.get())); m_contentLayerSharedValues = adoptPtr(new ContentLayerChromium::SharedValues(m_context.get())); m_canvasLayerSharedValues = adoptPtr(new CanvasLayerChromium::SharedValues(m_context.get())); m_videoLayerSharedValues = adoptPtr(new VideoLayerChromium::SharedValues(m_context.get())); m_pluginLayerSharedValues = adoptPtr(new PluginLayerChromium::SharedValues(m_context.get())); + m_renderSurfaceSharedValues = adoptPtr(new RenderSurfaceChromium::SharedValues(m_context.get())); if (!m_layerSharedValues->initialized() || !m_contentLayerSharedValues->initialized() || !m_canvasLayerSharedValues->initialized() - || !m_videoLayerSharedValues->initialized() || !m_pluginLayerSharedValues->initialized()) { + || !m_videoLayerSharedValues->initialized() || !m_pluginLayerSharedValues->initialized() || !m_renderSurfaceSharedValues->initialized()) { cleanupSharedObjects(); return false; } + m_textureManager = TextureManager::create(m_context.get(), textureMemoryLimitBytes, m_maxTextureSize); return true; } @@ -872,11 +828,7 @@ void LayerRendererChromium::cleanupSharedObjects() m_canvasLayerSharedValues.clear(); m_videoLayerSharedValues.clear(); m_pluginLayerSharedValues.clear(); - - if (m_textureLayerShaderProgram) { - GLC(m_context, m_context->deleteProgram(m_textureLayerShaderProgram)); - m_textureLayerShaderProgram = 0; - } + m_renderSurfaceSharedValues.clear(); if (m_rootLayerTextureId) { deleteLayerTexture(m_rootLayerTextureId); @@ -884,7 +836,9 @@ void LayerRendererChromium::cleanupSharedObjects() } if (m_offscreenFramebufferId) - GLC(m_context, m_context->deleteFramebuffer(m_offscreenFramebufferId)); + GLC(m_context.get(), m_context->deleteFramebuffer(m_offscreenFramebufferId)); + + m_textureManager.clear(); } } // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/LayerRendererChromium.h b/WebCore/platform/graphics/chromium/LayerRendererChromium.h index 531d652..c0e610a 100644 --- a/WebCore/platform/graphics/chromium/LayerRendererChromium.h +++ b/WebCore/platform/graphics/chromium/LayerRendererChromium.h @@ -108,6 +108,7 @@ public: const CanvasLayerChromium::SharedValues* canvasLayerSharedValues() const { return m_canvasLayerSharedValues.get(); } const VideoLayerChromium::SharedValues* videoLayerSharedValues() const { return m_videoLayerSharedValues.get(); } const PluginLayerChromium::SharedValues* pluginLayerSharedValues() const { return m_pluginLayerSharedValues.get(); } + const RenderSurfaceChromium::SharedValues* renderSurfaceSharedValues() const { return m_renderSurfaceSharedValues.get(); } void resizeOnscreenContent(const IntSize&); @@ -115,6 +116,10 @@ public: IntRect rootLayerContentRect() const { return m_rootContentRect; } void getFramebufferPixels(void *pixels, const IntRect& rect); + TextureManager* textureManager() const { return m_textureManager.get(); } + + void setScissorToRect(const IntRect&); + private: explicit LayerRendererChromium(PassRefPtr<GraphicsContext3D> graphicsContext3D); void updateLayersRecursive(LayerChromium* layer, const TransformationMatrix& parentMatrix, Vector<LayerChromium*>& renderSurfaceLayerList, Vector<LayerChromium*>& layerList); @@ -123,8 +128,6 @@ private: bool isLayerVisible(LayerChromium*, const TransformationMatrix&, const IntRect& visibleRect); - void setScissorToRect(const IntRect&); - void setDrawViewportRect(const IntRect&, bool flipY); bool useRenderSurface(RenderSurfaceChromium*); @@ -140,13 +143,6 @@ private: int m_rootLayerTextureWidth; int m_rootLayerTextureHeight; - // Shader uniform locations used by layers whose contents are the results of a - // previous rendering operation. - unsigned m_textureLayerShaderProgram; - int m_textureLayerShaderSamplerLocation; - int m_textureLayerShaderMatrixLocation; - int m_textureLayerShaderAlphaLocation; - TransformationMatrix m_projectionMatrix; RefPtr<LayerChromium> m_rootLayer; @@ -186,6 +182,9 @@ private: OwnPtr<CanvasLayerChromium::SharedValues> m_canvasLayerSharedValues; OwnPtr<VideoLayerChromium::SharedValues> m_videoLayerSharedValues; OwnPtr<PluginLayerChromium::SharedValues> m_pluginLayerSharedValues; + OwnPtr<RenderSurfaceChromium::SharedValues> m_renderSurfaceSharedValues; + + OwnPtr<TextureManager> m_textureManager; RefPtr<GraphicsContext3D> m_context; diff --git a/WebCore/platform/graphics/chromium/LayerTexture.cpp b/WebCore/platform/graphics/chromium/LayerTexture.cpp new file mode 100644 index 0000000..32bfa0b --- /dev/null +++ b/WebCore/platform/graphics/chromium/LayerTexture.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2010, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 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" + +#if USE(ACCELERATED_COMPOSITING) + +#include "LayerTexture.h" + +#include "GraphicsContext3D.h" +#include "TextureManager.h" + +namespace WebCore { + +LayerTexture::LayerTexture(GraphicsContext3D* context, TextureManager* manager) + : m_context(context) + , m_textureManager(manager) + , m_token(0) + , m_format(0) + , m_textureId(0) +{ +} + +LayerTexture::~LayerTexture() +{ + if (m_token) + m_textureManager->releaseToken(m_token); +} + +bool LayerTexture::isValid(const IntSize& size, unsigned format) +{ + return m_token && size == m_size && format == m_format && m_textureManager->hasTexture(m_token); +} + +bool LayerTexture::reserve(const IntSize& size, unsigned format) +{ + if (!m_token) + m_token = m_textureManager->getToken(); + + if (size == m_size && format == m_format && m_textureManager->hasTexture(m_token)) + m_textureManager->protectTexture(m_token); + else { + m_textureId = m_textureManager->requestTexture(m_token, size, format); + if (m_textureId) { + m_size = size; + m_format = format; + } + } + + return m_textureId; +} + +void LayerTexture::unreserve() +{ + if (m_token) + m_textureManager->unprotectTexture(m_token); +} + +void LayerTexture::bindTexture() +{ + m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textureId); +} + +void LayerTexture::framebufferTexture2D() +{ + m_context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_textureId, 0); +} + +} + +#endif // USE(ACCELERATED_COMPOSITING) + diff --git a/WebCore/platform/graphics/chromium/LayerTexture.h b/WebCore/platform/graphics/chromium/LayerTexture.h new file mode 100644 index 0000000..312adfa --- /dev/null +++ b/WebCore/platform/graphics/chromium/LayerTexture.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2010, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 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 LayerTexture_h +#define LayerTexture_h + +#include "IntSize.h" +#include "TextureManager.h" + +#include <wtf/Noncopyable.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class GraphicsContext3D; +class TextureManager; + +class LayerTexture : public Noncopyable { +public: + static PassOwnPtr<LayerTexture> create(GraphicsContext3D* context, TextureManager* manager) + { + return adoptPtr(new LayerTexture(context, manager)); + } + ~LayerTexture(); + + bool isValid(const IntSize&, unsigned format); + bool reserve(const IntSize&, unsigned format); + void unreserve(); + + void bindTexture(); + void framebufferTexture2D(); + +private: + LayerTexture(GraphicsContext3D*, TextureManager*); + + RefPtr<GraphicsContext3D> m_context; + TextureManager* m_textureManager; + TextureToken m_token; + IntSize m_size; + unsigned m_format; + unsigned m_textureId; +}; + +} + +#endif + diff --git a/WebCore/platform/graphics/chromium/PluginLayerChromium.cpp b/WebCore/platform/graphics/chromium/PluginLayerChromium.cpp index 2d1852f..878c142 100644 --- a/WebCore/platform/graphics/chromium/PluginLayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/PluginLayerChromium.cpp @@ -102,7 +102,7 @@ void PluginLayerChromium::setTextureId(unsigned id) m_textureId = id; } -void PluginLayerChromium::updateContents() +void PluginLayerChromium::updateContentsIfDirty() { } diff --git a/WebCore/platform/graphics/chromium/PluginLayerChromium.h b/WebCore/platform/graphics/chromium/PluginLayerChromium.h index 44a6cc9..853b328 100644 --- a/WebCore/platform/graphics/chromium/PluginLayerChromium.h +++ b/WebCore/platform/graphics/chromium/PluginLayerChromium.h @@ -38,7 +38,7 @@ class PluginLayerChromium : public LayerChromium { public: static PassRefPtr<PluginLayerChromium> create(GraphicsLayerChromium* owner = 0); virtual bool drawsContent() { return true; } - virtual void updateContents(); + virtual void updateContentsIfDirty(); virtual void draw(); void setTextureId(unsigned textureId); diff --git a/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp b/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp index 816fd3d..e8b9a12 100644 --- a/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp +++ b/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp @@ -31,12 +31,67 @@ #include "GraphicsContext3D.h" #include "LayerRendererChromium.h" +#include "LayerTexture.h" namespace WebCore { +RenderSurfaceChromium::SharedValues::SharedValues(GraphicsContext3D* context) + : m_context(context) + , m_shaderProgram(0) + , m_shaderSamplerLocation(-1) + , m_shaderMatrixLocation(-1) + , m_shaderAlphaLocation(-1) + , m_initialized(false) +{ + // The following program composites layers whose contents are the results of a previous + // render operation and therefore doesn't perform any color swizzling. It is used + // in scrolling and for compositing offscreen textures. + char renderSurfaceVertexShaderString[] = + "attribute vec4 a_position; \n" + "attribute vec2 a_texCoord; \n" + "uniform mat4 matrix; \n" + "varying vec2 v_texCoord; \n" + "void main() \n" + "{ \n" + " gl_Position = matrix * a_position; \n" + " v_texCoord = a_texCoord; \n" + "} \n"; + char renderSurfaceFragmentShaderString[] = + "precision mediump float; \n" + "varying vec2 v_texCoord; \n" + "uniform sampler2D s_texture; \n" + "uniform float alpha; \n" + "void main() \n" + "{ \n" + " vec4 texColor = texture2D(s_texture, v_texCoord); \n" + " gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha; \n" + "} \n"; + + m_shaderProgram = LayerChromium::createShaderProgram(m_context, renderSurfaceVertexShaderString, renderSurfaceFragmentShaderString); + if (!m_shaderProgram) { + LOG_ERROR("RenderSurfaceChromium: Failed to create shader program"); + return; + } + + GLC(m_context, m_shaderSamplerLocation = m_context->getUniformLocation(m_shaderProgram, "s_texture")); + GLC(m_context, m_shaderMatrixLocation = m_context->getUniformLocation(m_shaderProgram, "matrix")); + GLC(m_context, m_shaderAlphaLocation = m_context->getUniformLocation(m_shaderProgram, "alpha")); + if (m_shaderSamplerLocation == -1 || m_shaderMatrixLocation == -1 || m_shaderAlphaLocation == -1) { + LOG_ERROR("Failed to initialize texture layer shader."); + return; + } + m_initialized = true; +} + +RenderSurfaceChromium::SharedValues::~SharedValues() +{ + if (m_shaderProgram) + GLC(m_context, m_context->deleteProgram(m_shaderProgram)); +} + RenderSurfaceChromium::RenderSurfaceChromium(LayerChromium* owningLayer) : m_owningLayer(owningLayer) - , m_contentsTextureId(0) + , m_skipsDraw(false) { } @@ -47,14 +102,12 @@ RenderSurfaceChromium::~RenderSurfaceChromium() void RenderSurfaceChromium::cleanupResources() { - if (!m_contentsTextureId) + if (!m_contentsTexture) return; ASSERT(layerRenderer()); - layerRenderer()->deleteLayerTexture(m_contentsTextureId); - m_contentsTextureId = 0; - m_allocatedTextureSize = IntSize(); + m_contentsTexture.clear(); } LayerRendererChromium* RenderSurfaceChromium::layerRenderer() @@ -63,25 +116,41 @@ LayerRendererChromium* RenderSurfaceChromium::layerRenderer() return m_owningLayer->layerRenderer(); } -void RenderSurfaceChromium::prepareContentsTexture() +bool RenderSurfaceChromium::prepareContentsTexture() { - ASSERT(m_owningLayer); + IntSize requiredSize(m_contentRect.size()); + TextureManager* textureManager = layerRenderer()->textureManager(); - if (!m_contentsTextureId) { - m_contentsTextureId = layerRenderer()->createLayerTexture(); - ASSERT(m_contentsTextureId); - m_allocatedTextureSize = IntSize(); - } + if (!m_contentsTexture) + m_contentsTexture = LayerTexture::create(layerRenderer()->context(), textureManager); - IntSize requiredSize(m_contentRect.width(), m_contentRect.height()); - if (m_allocatedTextureSize != requiredSize) { - GraphicsContext3D* context = m_owningLayer->layerRenderer()->context(); - GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_contentsTextureId)); - GLC(context, context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, - requiredSize.width(), requiredSize.height(), 0, GraphicsContext3D::RGBA, - GraphicsContext3D::UNSIGNED_BYTE, 0)); - m_allocatedTextureSize = requiredSize; + if (!m_contentsTexture->reserve(requiredSize, GraphicsContext3D::RGBA)) { + m_skipsDraw = true; + return false; } + + m_skipsDraw = false; + return true; +} + +void RenderSurfaceChromium::draw() +{ + if (m_skipsDraw || !m_contentsTexture) + return; + + m_contentsTexture->bindTexture(); + + const RenderSurfaceChromium::SharedValues* sv = layerRenderer()->renderSurfaceSharedValues(); + ASSERT(sv && sv->initialized()); + + layerRenderer()->useShader(sv->shaderProgram()); + layerRenderer()->setScissorToRect(m_scissorRect); + + LayerChromium::drawTexturedQuad(layerRenderer()->context(), layerRenderer()->projectionMatrix(), m_drawTransform, + m_contentRect.width(), m_contentRect.height(), m_drawOpacity, + sv->shaderMatrixLocation(), sv->shaderAlphaLocation()); + + m_contentsTexture->unreserve(); } } diff --git a/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h b/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h index 1f33527..a93218f 100644 --- a/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h +++ b/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h @@ -31,13 +31,15 @@ #include "FloatRect.h" #include "IntRect.h" +#include "TextureManager.h" #include "TransformationMatrix.h" #include <wtf/Noncopyable.h> namespace WebCore { -class LayerRendererChromium; class LayerChromium; +class LayerRendererChromium; +class LayerTexture; class RenderSurfaceChromium : public Noncopyable { friend class LayerRendererChromium; @@ -45,20 +47,45 @@ public: explicit RenderSurfaceChromium(LayerChromium*); ~RenderSurfaceChromium(); - void prepareContentsTexture(); + bool prepareContentsTexture(); void cleanupResources(); + void draw(); FloatPoint contentRectCenter() const { return FloatRect(m_contentRect).center(); } IntRect contentRect() const { return m_contentRect; } + // Stores values that are shared between instances of this class that are + // associated with the same LayerRendererChromium (and hence the same GL + // context). + class SharedValues { + public: + explicit SharedValues(GraphicsContext3D*); + ~SharedValues(); + + unsigned shaderProgram() const { return m_shaderProgram; } + int shaderSamplerLocation() const { return m_shaderSamplerLocation; } + int shaderMatrixLocation() const { return m_shaderMatrixLocation; } + int shaderAlphaLocation() const { return m_shaderAlphaLocation; } + bool initialized() const { return m_initialized; } + + private: + GraphicsContext3D* m_context; + + unsigned m_shaderProgram; + int m_shaderSamplerLocation; + int m_shaderMatrixLocation; + int m_shaderAlphaLocation; + bool m_initialized; + }; + private: LayerRendererChromium* layerRenderer(); LayerChromium* m_owningLayer; IntRect m_contentRect; - unsigned m_contentsTextureId; + bool m_skipsDraw; + OwnPtr<LayerTexture> m_contentsTexture; float m_drawOpacity; - IntSize m_allocatedTextureSize; TransformationMatrix m_drawTransform; TransformationMatrix m_originTransform; IntRect m_scissorRect; diff --git a/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp b/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp index bcef1fe..204c565 100644 --- a/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp @@ -112,20 +112,34 @@ void SimpleFontData::platformDestroy() { } +SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const +{ + LOGFONT winFont; + GetObject(m_platformData.hfont(), sizeof(LOGFONT), &winFont); + float scaledSize = scaleFactor * fontDescription.computedSize(); + winFont.lfHeight = -lroundf(scaledSize); + HFONT hfont = CreateFontIndirect(&winFont); + return new SimpleFontData(FontPlatformData(hfont, scaledSize), isCustomFont(), false); +} + SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const { - if (!m_smallCapsFontData) { - LOGFONT winFont; - GetObject(m_platformData.hfont(), sizeof(LOGFONT), &winFont); - float smallCapsSize = 0.70f * fontDescription.computedSize(); - // Unlike WebKit trunk, we don't multiply the size by 32. That seems - // to be some kind of artifact of their CG backend, or something. - winFont.lfHeight = -lroundf(smallCapsSize); - HFONT hfont = CreateFontIndirect(&winFont); - m_smallCapsFontData = - new SimpleFontData(FontPlatformData(hfont, smallCapsSize), isCustomFont(), false); - } - return m_smallCapsFontData; + if (!m_derivedFontData) + m_derivedFontData = DerivedFontData::create(isCustomFont()); + if (!m_derivedFontData->smallCaps) + m_derivedFontData->smallCaps = scaledFontData(fontDescription, .7); + + return m_derivedFontData->smallCaps.get(); +} + +SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const +{ + if (!m_derivedFontData) + m_derivedFontData = DerivedFontData::create(isCustomFont()); + if (!m_derivedFontData->emphasisMark) + m_derivedFontData->emphasisMark = scaledFontData(fontDescription, .5); + + return m_derivedFontData->emphasisMark.get(); } bool SimpleFontData::containsCharacters(const UChar* characters, int length) const diff --git a/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp b/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp index c5190fc..355d837 100644 --- a/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp +++ b/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp @@ -48,6 +48,7 @@ namespace WebCore { // Smallcaps versions of fonts are 70% the size of the normal font. static const float smallCapsFraction = 0.7f; +static const float emphasisMarkFraction = .5; // This is the largest VDMX table which we'll try to load and parse. static const size_t maxVDMXTableSize = 1024 * 1024; // 1 MB @@ -108,6 +109,15 @@ void SimpleFontData::platformInit() m_lineGap = SkScalarRound(metrics.fLeading); m_lineSpacing = m_ascent + m_descent + m_lineGap; + if (m_orientation == Vertical) { + 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; + } + // In WebKit/WebCore/platform/graphics/SimpleFontData.cpp, m_spaceWidth is // calculated for us, but we need to calculate m_maxCharWidth and // m_avgCharWidth in order for text entry widgets to be sized correctly. @@ -141,14 +151,30 @@ void SimpleFontData::platformDestroy() { } +SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const +{ + const float scaledSize = lroundf(fontDescription.computedSize() * scaleFactor); + return new SimpleFontData(FontPlatformData(m_platformData, scaledSize), isCustomFont(), false); +} + SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const { - if (!m_smallCapsFontData) { - const float smallCapsSize = lroundf(fontDescription.computedSize() * smallCapsFraction); - m_smallCapsFontData = new SimpleFontData(FontPlatformData(m_platformData, smallCapsSize), isCustomFont(), false); - } + if (!m_derivedFontData) + m_derivedFontData = DerivedFontData::create(isCustomFont()); + if (!m_derivedFontData->smallCaps) + m_derivedFontData->smallCaps = scaledFontData(fontDescription, smallCapsFraction); + + return m_derivedFontData->smallCaps.get(); +} + +SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const +{ + if (!m_derivedFontData) + m_derivedFontData = DerivedFontData::create(isCustomFont()); + if (!m_derivedFontData->emphasisMark) + m_derivedFontData->emphasisMark = scaledFontData(fontDescription, emphasisMarkFraction); - return m_smallCapsFontData; + return m_derivedFontData->emphasisMark.get(); } bool SimpleFontData::containsCharacters(const UChar* characters, int length) const diff --git a/WebCore/platform/graphics/chromium/TextureManager.cpp b/WebCore/platform/graphics/chromium/TextureManager.cpp new file mode 100644 index 0000000..9579ef9 --- /dev/null +++ b/WebCore/platform/graphics/chromium/TextureManager.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2010, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 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" + +#if USE(ACCELERATED_COMPOSITING) + +#include "TextureManager.h" + +#include "LayerRendererChromium.h" + +namespace WebCore { + +static size_t memoryUseBytes(IntSize size, unsigned textureFormat) +{ + // FIXME: This assumes all textures are 4 bytes/pixel, like RGBA. + return size.width() * size.height() * 4; +} + +TextureManager::TextureManager(GraphicsContext3D* context, size_t memoryLimitBytes, int maxTextureSize) + : m_context(context) + , m_memoryLimitBytes(memoryLimitBytes) + , m_memoryUseBytes(0) + , m_maxTextureSize(maxTextureSize) + , m_nextToken(1) +{ +} + +TextureToken TextureManager::getToken() +{ + return m_nextToken++; +} + +void TextureManager::releaseToken(TextureToken token) +{ + TextureMap::iterator it = m_textures.find(token); + if (it != m_textures.end()) + removeTexture(token, it->second); +} + +bool TextureManager::hasTexture(TextureToken token) +{ + if (m_textures.contains(token)) { + // If someone asks about a texture put it at the end of the LRU list. + m_textureLRUSet.remove(token); + m_textureLRUSet.add(token); + return true; + } + return false; +} + +void TextureManager::protectTexture(TextureToken token) +{ + ASSERT(hasTexture(token)); + ASSERT(!m_textures.get(token).isProtected); + TextureInfo info = m_textures.take(token); + info.isProtected = true; + m_textures.add(token, info); +} + +void TextureManager::unprotectTexture(TextureToken token) +{ + TextureMap::iterator it = m_textures.find(token); + if (it != m_textures.end()) { + TextureInfo info = it->second; + if (info.isProtected) { + info.isProtected = false; + m_textures.remove(it); + m_textures.add(token, info); + } + } +} + +bool TextureManager::reduceMemoryToLimit(size_t limit) +{ + while (m_memoryUseBytes > limit) { + ASSERT(!m_textureLRUSet.isEmpty()); + bool foundCandidate = false; + for (ListHashSet<TextureToken>::iterator lruIt = m_textureLRUSet.begin(); lruIt != m_textureLRUSet.end(); ++lruIt) { + TextureToken token = *lruIt; + TextureInfo info = m_textures.get(token); + if (info.isProtected) + continue; + removeTexture(token, info); + foundCandidate = true; + break; + } + if (!foundCandidate) + return false; + } + return true; +} + +void TextureManager::addTexture(TextureToken token, TextureInfo info) +{ + ASSERT(!m_textureLRUSet.contains(token)); + ASSERT(!m_textures.contains(token)); + m_memoryUseBytes += memoryUseBytes(info.size, info.format); + m_textures.set(token, info); + m_textureLRUSet.add(token); +} + +void TextureManager::removeTexture(TextureToken token, TextureInfo info) +{ + ASSERT(m_textureLRUSet.contains(token)); + ASSERT(m_textures.contains(token)); + m_memoryUseBytes -= memoryUseBytes(info.size, info.format); + m_textures.remove(token); + ASSERT(m_textureLRUSet.contains(token)); + m_textureLRUSet.remove(token); + GLC(m_context.get(), m_context->deleteTexture(info.textureId)); +} + +unsigned TextureManager::requestTexture(TextureToken token, IntSize size, unsigned format, bool* newTexture) +{ + if (size.width() > m_maxTextureSize || size.height() > m_maxTextureSize) + return 0; + + TextureMap::iterator it = m_textures.find(token); + if (it != m_textures.end()) { + ASSERT(it->second.size != size || it->second.format != format); + removeTexture(token, it->second); + } + + size_t memoryRequiredBytes = memoryUseBytes(size, format); + if (memoryRequiredBytes > m_memoryLimitBytes || !reduceMemoryToLimit(m_memoryLimitBytes - memoryRequiredBytes)) + return 0; + + unsigned textureId = m_context->createTexture(); + GLC(m_context.get(), textureId = m_context->createTexture()); + GLC(m_context.get(), m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId)); + // Do basic linear filtering on resize. + GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR)); + GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR)); + // NPOT textures in GL ES only work when the wrap mode is set to GraphicsContext3D::CLAMP_TO_EDGE. + GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE)); + GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE)); + GLC(m_context.get(), m_context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, format, size.width(), size.height(), 0, format, GraphicsContext3D::UNSIGNED_BYTE)); + TextureInfo info; + info.size = size; + info.format = format; + info.textureId = textureId; + info.isProtected = true; + addTexture(token, info); + return textureId; +} + +} + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/chromium/TextureManager.h b/WebCore/platform/graphics/chromium/TextureManager.h new file mode 100644 index 0000000..1e850cd --- /dev/null +++ b/WebCore/platform/graphics/chromium/TextureManager.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2010, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 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 TextureManager_h +#define TextureManager_h + +#include "GraphicsContext3D.h" +#include "IntRect.h" +#include "IntSize.h" + +#include <wtf/HashMap.h> +#include <wtf/ListHashSet.h> + +namespace WebCore { + +typedef int TextureToken; + +class TextureManager : public Noncopyable { +public: + static PassOwnPtr<TextureManager> create(GraphicsContext3D* context, size_t memoryLimitBytes, int maxTextureSize) + { + return adoptPtr(new TextureManager(context, memoryLimitBytes, maxTextureSize)); + } + + TextureToken getToken(); + void releaseToken(TextureToken); + bool hasTexture(TextureToken); + + unsigned requestTexture(TextureToken, IntSize, unsigned textureFormat, bool* newTexture = 0); + + void protectTexture(TextureToken); + void unprotectTexture(TextureToken); + +private: + TextureManager(GraphicsContext3D*, size_t memoryLimitBytes, int maxTextureSize); + + struct TextureInfo { + IntSize size; + unsigned format; + unsigned textureId; + bool isProtected; + }; + + bool reduceMemoryToLimit(size_t); + void addTexture(TextureToken, TextureInfo); + void removeTexture(TextureToken, TextureInfo); + + RefPtr<GraphicsContext3D> m_context; + + typedef HashMap<TextureToken, TextureInfo> TextureMap; + TextureMap m_textures; + ListHashSet<TextureToken> m_textureLRUSet; + + size_t m_memoryLimitBytes; + size_t m_memoryUseBytes; + int m_maxTextureSize; + TextureToken m_nextToken; +}; + +} + +#endif diff --git a/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp b/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp index feb7ebc..24fd732 100644 --- a/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp @@ -200,8 +200,11 @@ void VideoLayerChromium::cleanupResources() } } -void VideoLayerChromium::updateContents() +void VideoLayerChromium::updateContentsIfDirty() { + if (!m_contentsDirty) + return; + RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_owner->client()); if (!backing || backing->paintingGoesToWindow()) return; @@ -297,7 +300,7 @@ bool VideoLayerChromium::allocateTexturesIfNeeded(GraphicsContext3D* context, Vi void VideoLayerChromium::allocateTexture(GraphicsContext3D* context, unsigned textureId, const IntSize& dimensions, unsigned textureFormat) { GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId)); - GLC(context, context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, textureFormat, dimensions.width(), dimensions.height(), 0, textureFormat, GraphicsContext3D::UNSIGNED_BYTE, 0)); + 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) diff --git a/WebCore/platform/graphics/chromium/VideoLayerChromium.h b/WebCore/platform/graphics/chromium/VideoLayerChromium.h index 05b6578..0992ab7 100644 --- a/WebCore/platform/graphics/chromium/VideoLayerChromium.h +++ b/WebCore/platform/graphics/chromium/VideoLayerChromium.h @@ -45,7 +45,7 @@ public: static PassRefPtr<VideoLayerChromium> create(GraphicsLayerChromium* owner = 0, VideoFrameProvider* = 0); virtual ~VideoLayerChromium(); - virtual void updateContents(); + virtual void updateContentsIfDirty(); virtual bool drawsContent() { return true; } virtual void draw(); diff --git a/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp b/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp index 2055ae6..5b34bb9 100644 --- a/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp @@ -50,8 +50,11 @@ WebGLLayerChromium::WebGLLayerChromium(GraphicsLayerChromium* owner) { } -void WebGLLayerChromium::updateContents() +void WebGLLayerChromium::updateContentsIfDirty() { + if (!m_contentsDirty) + return; + GraphicsContext3D* rendererContext = layerRendererContext(); ASSERT(m_context); if (m_textureChanged) { diff --git a/WebCore/platform/graphics/chromium/WebGLLayerChromium.h b/WebCore/platform/graphics/chromium/WebGLLayerChromium.h index 11b8db7..c67cc2c 100644 --- a/WebCore/platform/graphics/chromium/WebGLLayerChromium.h +++ b/WebCore/platform/graphics/chromium/WebGLLayerChromium.h @@ -45,7 +45,7 @@ class WebGLLayerChromium : public CanvasLayerChromium { public: static PassRefPtr<WebGLLayerChromium> create(GraphicsLayerChromium* owner = 0); virtual bool drawsContent() { return m_context; } - virtual void updateContents(); + virtual void updateContentsIfDirty(); void setContext(const GraphicsContext3D* context); diff --git a/WebCore/platform/graphics/efl/FontEfl.cpp b/WebCore/platform/graphics/efl/FontEfl.cpp index 96d6a7b..d3ca183 100644 --- a/WebCore/platform/graphics/efl/FontEfl.cpp +++ b/WebCore/platform/graphics/efl/FontEfl.cpp @@ -40,6 +40,11 @@ void Font::drawComplexText(GraphicsContext*, const TextRun&, const FloatPoint&, notImplemented(); } +void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const +{ + notImplemented(); +} + bool Font::canReturnFallbackFontsForComplexText() { return false; diff --git a/WebCore/platform/graphics/filters/FEBlend.cpp b/WebCore/platform/graphics/filters/FEBlend.cpp index 89b44e0..f863487 100644 --- a/WebCore/platform/graphics/filters/FEBlend.cpp +++ b/WebCore/platform/graphics/filters/FEBlend.cpp @@ -88,30 +88,31 @@ static unsigned char lighten(unsigned char colorA, unsigned char colorB, unsigne void FEBlend::apply() { + if (hasResult()) + return; FilterEffect* in = inputEffect(0); FilterEffect* in2 = inputEffect(1); in->apply(); in2->apply(); - if (!in->resultImage() || !in2->resultImage()) + if (!in->hasResult() || !in2->hasResult()) return; if (m_mode <= FEBLEND_MODE_UNKNOWN || m_mode > FEBLEND_MODE_LIGHTEN) return; - if (!effectContext()) + ImageData* resultImage = createPremultipliedImageResult(); + if (!resultImage) return; IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); - RefPtr<ImageData> srcImageDataA = in->resultImage()->getPremultipliedImageData(effectADrawingRect); + RefPtr<ImageData> srcImageDataA = in->asPremultipliedImage(effectADrawingRect); ByteArray* srcPixelArrayA = srcImageDataA->data()->data(); IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect()); - RefPtr<ImageData> srcImageDataB = in2->resultImage()->getPremultipliedImageData(effectBDrawingRect); + RefPtr<ImageData> srcImageDataB = in2->asPremultipliedImage(effectBDrawingRect); ByteArray* srcPixelArrayB = srcImageDataB->data()->data(); - IntRect imageRect(IntPoint(), resultImage()->size()); - RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height()); - ByteArray* dstPixelArray = imageData->data()->data(); + ByteArray* dstPixelArray = resultImage->data()->data(); // Keep synchronized with BlendModeType static const BlendType callEffect[] = {unknown, normal, multiply, screen, darken, lighten}; @@ -131,8 +132,6 @@ void FEBlend::apply() unsigned char alphaR = 255 - ((255 - alphaA) * (255 - alphaB)) / 255; dstPixelArray->set(pixelOffset + 3, alphaR); } - - resultImage()->putPremultipliedImageData(imageData.get(), imageRect, IntPoint()); } void FEBlend::dump() diff --git a/WebCore/platform/graphics/filters/FEColorMatrix.cpp b/WebCore/platform/graphics/filters/FEColorMatrix.cpp index 1c99b1e..d316dfb 100644 --- a/WebCore/platform/graphics/filters/FEColorMatrix.cpp +++ b/WebCore/platform/graphics/filters/FEColorMatrix.cpp @@ -67,10 +67,10 @@ void FEColorMatrix::setValues(const Vector<float> &values) inline void matrix(double& red, double& green, double& blue, double& alpha, const Vector<float>& values) { - double r = values[0] * red + values[1] * green + values[2] * blue + values[3] * alpha; - double g = values[5] * red + values[6] * green + values[7] * blue + values[8] * alpha; - double b = values[10] * red + values[11] * green + values[12] * blue + values[13] * alpha; - double a = values[15] * red + values[16] * green + values[17] * blue + values[18] * alpha; + double r = values[0] * red + values[1] * green + values[2] * blue + values[3] * alpha + values[4] * 255; + double g = values[5] * red + values[6] * green + values[7] * blue + values[8] * alpha + values[9] * 255; + double b = values[10] * red + values[11] * green + values[12] * blue + values[13] * alpha + values[14] * 255; + double a = values[15] * red + values[16] * green + values[17] * blue + values[18] * alpha + values[19] * 255; red = r; green = g; @@ -150,19 +150,21 @@ void effectType(ByteArray* pixelArray, const Vector<float>& values) void FEColorMatrix::apply() { + if (hasResult()) + return; FilterEffect* in = inputEffect(0); in->apply(); - if (!in->resultImage()) + if (!in->hasResult()) return; - GraphicsContext* filterContext = effectContext(); - if (!filterContext) + ImageBuffer* resultImage = createImageBufferResult(); + if (!resultImage) return; - filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); + resultImage->context()->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); - IntRect imageRect(IntPoint(), resultImage()->size()); - RefPtr<ImageData> imageData = resultImage()->getUnmultipliedImageData(imageRect); + IntRect imageRect(IntPoint(), absolutePaintRect().size()); + RefPtr<ImageData> imageData = resultImage->getUnmultipliedImageData(imageRect); ByteArray* pixelArray = imageData->data()->data(); switch (m_type) { @@ -183,7 +185,7 @@ void FEColorMatrix::apply() break; } - resultImage()->putUnmultipliedImageData(imageData.get(), imageRect, IntPoint()); + resultImage->putUnmultipliedImageData(imageData.get(), imageRect, IntPoint()); } void FEColorMatrix::dump() diff --git a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp index cfab50b..f8f651c 100644 --- a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp +++ b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp @@ -149,12 +149,15 @@ static void gamma(unsigned char* values, const ComponentTransferFunction& transf void FEComponentTransfer::apply() { + if (hasResult()) + return; FilterEffect* in = inputEffect(0); in->apply(); - if (!in->resultImage()) + if (!in->hasResult()) return; - if (!effectContext()) + ImageData* imageData = createUnmultipliedImageResult(); + if (!imageData) return; unsigned char rValues[256], gValues[256], bValues[256], aValues[256]; @@ -168,7 +171,7 @@ void FEComponentTransfer::apply() (*callEffect[transferFunction[channel].type])(tables[channel], transferFunction[channel]); IntRect drawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); - RefPtr<ImageData> imageData = in->resultImage()->getUnmultipliedImageData(drawingRect); + in->copyUnmultipliedImage(imageData, drawingRect); ByteArray* pixelArray = imageData->data()->data(); unsigned pixelArrayLength = pixelArray->length(); @@ -178,8 +181,6 @@ void FEComponentTransfer::apply() pixelArray->set(pixelOffset + channel, tables[channel][c]); } } - - resultImage()->putUnmultipliedImageData(imageData.get(), IntRect(IntPoint(), resultImage()->size()), IntPoint()); } void FEComponentTransfer::dump() diff --git a/WebCore/platform/graphics/filters/FEComposite.cpp b/WebCore/platform/graphics/filters/FEComposite.cpp index d27321f..5ecd69b 100644 --- a/WebCore/platform/graphics/filters/FEComposite.cpp +++ b/WebCore/platform/graphics/filters/FEComposite.cpp @@ -97,23 +97,66 @@ void FEComposite::setK4(float k4) m_k4 = k4; } -inline void arithmetic(const ByteArray* srcPixelArrayA, ByteArray* srcPixelArrayB, +template <int b1, int b2, int b3, int b4> +inline void computeArithmeticPixels(unsigned char* source, unsigned char* destination, int pixelArrayLength, + float k1, float k2, float k3, float k4) +{ + float scaledK4; + float scaledK1; + if (b1) + scaledK1 = k1 / 255.f; + if (b4) + scaledK4 = k4 * 255.f; + + while (--pixelArrayLength >= 0) { + unsigned char i1 = *source; + unsigned char i2 = *destination; + float result = 0; + if (b1) + result += scaledK1 * i1 * i2; + if (b2) + result += k2 * i1; + if (b3) + result += k3 * i2; + if (b4) + result += scaledK4; + + if (result <= 0) + *destination = 0; + else if (result >= 255) + *destination = 255; + else + *destination = result; + ++source; + ++destination; + } +} + +inline void arithmetic(ByteArray* srcPixelArrayA, ByteArray* srcPixelArrayB, float k1, float k2, float k3, float k4) { - float scaledK1 = k1 / 255.f; - float scaledK4 = k4 * 255.f; - unsigned pixelArrayLength = srcPixelArrayA->length(); - for (unsigned pixelOffset = 0; pixelOffset < pixelArrayLength; pixelOffset += 4) { - for (unsigned channel = 0; channel < 4; ++channel) { - unsigned char i1 = srcPixelArrayA->get(pixelOffset + channel); - unsigned char i2 = srcPixelArrayB->get(pixelOffset + channel); + int pixelArrayLength = srcPixelArrayA->length(); + ASSERT(pixelArrayLength == static_cast<int>(srcPixelArrayB->length())); + unsigned char* source = srcPixelArrayA->data(); + unsigned char* destination = srcPixelArrayB->data(); - double result = scaledK1 * i1 * i2 + k2 * i1 + k3 * i2 + scaledK4; - srcPixelArrayB->set(pixelOffset + channel, result); + if (!k4) { + if (!k1) { + computeArithmeticPixels<0, 1, 1, 0>(source, destination, pixelArrayLength, k1, k2, k3, k4); + return; } + + computeArithmeticPixels<1, 1, 1, 0>(source, destination, pixelArrayLength, k1, k2, k3, k4); + return; + } + + if (!k1) { + computeArithmeticPixels<0, 1, 1, 1>(source, destination, pixelArrayLength, k1, k2, k3, k4); + return; } + computeArithmeticPixels<1, 1, 1, 1>(source, destination, pixelArrayLength, k1, k2, k3, k4); } - + void FEComposite::determineAbsolutePaintRect() { switch (m_type) { @@ -137,53 +180,58 @@ void FEComposite::determineAbsolutePaintRect() void FEComposite::apply() { + if (hasResult()) + return; FilterEffect* in = inputEffect(0); FilterEffect* in2 = inputEffect(1); in->apply(); in2->apply(); - if (!in->resultImage() || !in2->resultImage()) + if (!in->hasResult() || !in2->hasResult()) return; - GraphicsContext* filterContext = effectContext(); - if (!filterContext) + if (m_type == FECOMPOSITE_OPERATOR_ARITHMETIC) { + ImageData* resultImage = createPremultipliedImageResult(); + if (!resultImage) + return; + + IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); + RefPtr<ImageData> srcImageData = in->asPremultipliedImage(effectADrawingRect); + + IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect()); + in2->copyPremultipliedImage(resultImage, effectBDrawingRect); + + arithmetic(srcImageData->data()->data(), resultImage->data()->data(), m_k1, m_k2, m_k3, m_k4); + return; + } + + ImageBuffer* resultImage = createImageBufferResult(); + if (!resultImage) return; + GraphicsContext* filterContext = resultImage->context(); FloatRect srcRect = FloatRect(0, 0, -1, -1); switch (m_type) { case FECOMPOSITE_OPERATOR_OVER: - filterContext->drawImageBuffer(in2->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect())); - filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); + filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect())); + filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); break; case FECOMPOSITE_OPERATOR_IN: filterContext->save(); - filterContext->clipToImageBuffer(in2->resultImage(), drawingRegionOfInputImage(in2->absolutePaintRect())); - filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); + filterContext->clipToImageBuffer(in2->asImageBuffer(), drawingRegionOfInputImage(in2->absolutePaintRect())); + filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); filterContext->restore(); break; case FECOMPOSITE_OPERATOR_OUT: - filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); - filterContext->drawImageBuffer(in2->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()), srcRect, CompositeDestinationOut); + filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); + filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()), srcRect, CompositeDestinationOut); break; case FECOMPOSITE_OPERATOR_ATOP: - filterContext->drawImageBuffer(in2->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect())); - filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()), srcRect, CompositeSourceAtop); + filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect())); + filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()), srcRect, CompositeSourceAtop); break; case FECOMPOSITE_OPERATOR_XOR: - filterContext->drawImageBuffer(in2->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect())); - filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()), srcRect, CompositeXOR); - break; - case FECOMPOSITE_OPERATOR_ARITHMETIC: { - IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); - RefPtr<ImageData> srcImageData = in->resultImage()->getPremultipliedImageData(effectADrawingRect); - ByteArray* srcPixelArrayA = srcImageData->data()->data(); - - IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect()); - RefPtr<ImageData> imageData = in2->resultImage()->getPremultipliedImageData(effectBDrawingRect); - ByteArray* srcPixelArrayB = imageData->data()->data(); - - arithmetic(srcPixelArrayA, srcPixelArrayB, m_k1, m_k2, m_k3, m_k4); - resultImage()->putPremultipliedImageData(imageData.get(), IntRect(IntPoint(), resultImage()->size()), IntPoint()); - } + filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect())); + filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()), srcRect, CompositeXOR); break; default: break; diff --git a/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp b/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp index 198d764..d1f9c7b 100644 --- a/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp +++ b/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp @@ -372,35 +372,40 @@ ALWAYS_INLINE void FEConvolveMatrix::setOuterPixels(PaintingData& paintingData, void FEConvolveMatrix::apply() { + if (hasResult()) + return; FilterEffect* in = inputEffect(0); in->apply(); - if (!in->resultImage()) + if (!in->hasResult()) return; - if (!effectContext()) + ImageData* resultImage; + if (m_preserveAlpha) + resultImage = createUnmultipliedImageResult(); + else + resultImage = createPremultipliedImageResult(); + if (!resultImage) return; - IntRect imageRect(IntPoint(), resultImage()->size()); IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<CanvasPixelArray> srcPixelArray; if (m_preserveAlpha) - srcPixelArray = in->resultImage()->getUnmultipliedImageData(effectDrawingRect)->data(); + srcPixelArray = in->asUnmultipliedImage(effectDrawingRect)->data(); else - srcPixelArray = in->resultImage()->getPremultipliedImageData(effectDrawingRect)->data(); - - RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height()); + srcPixelArray = in->asPremultipliedImage(effectDrawingRect)->data(); + IntSize paintSize = absolutePaintRect().size(); PaintingData paintingData; paintingData.srcPixelArray = srcPixelArray.get(); - paintingData.dstPixelArray = imageData->data(); - paintingData.width = imageRect.width(); - paintingData.height = imageRect.height(); + paintingData.dstPixelArray = resultImage->data(); + paintingData.width = paintSize.width(); + paintingData.height = paintSize.height(); paintingData.bias = m_bias * 255; // Drawing fully covered pixels - int clipRight = imageRect.width() - m_kernelSize.width(); - int clipBottom = imageRect.height() - m_kernelSize.height(); + int clipRight = paintSize.width() - m_kernelSize.width(); + int clipBottom = paintSize.height() - m_kernelSize.height(); if (clipRight >= 0 && clipBottom >= 0) { setInteriorPixels(paintingData, clipRight, clipBottom); @@ -408,22 +413,17 @@ void FEConvolveMatrix::apply() clipRight += m_targetOffset.x() + 1; clipBottom += m_targetOffset.y() + 1; if (m_targetOffset.y() > 0) - setOuterPixels(paintingData, 0, 0, imageRect.width(), m_targetOffset.y()); - if (clipBottom < imageRect.height()) - setOuterPixels(paintingData, 0, clipBottom, imageRect.width(), imageRect.height()); + setOuterPixels(paintingData, 0, 0, paintSize.width(), m_targetOffset.y()); + if (clipBottom < paintSize.height()) + setOuterPixels(paintingData, 0, clipBottom, paintSize.width(), paintSize.height()); if (m_targetOffset.x() > 0) setOuterPixels(paintingData, 0, m_targetOffset.y(), m_targetOffset.x(), clipBottom); - if (clipRight < imageRect.width()) - setOuterPixels(paintingData, clipRight, m_targetOffset.y(), imageRect.width(), clipBottom); + if (clipRight < paintSize.width()) + setOuterPixels(paintingData, clipRight, m_targetOffset.y(), paintSize.width(), clipBottom); } else { // Rare situation, not optimizied for speed - setOuterPixels(paintingData, 0, 0, imageRect.width(), imageRect.height()); + setOuterPixels(paintingData, 0, 0, paintSize.width(), paintSize.height()); } - - if (m_preserveAlpha) - resultImage()->putUnmultipliedImageData(imageData.get(), imageRect, IntPoint()); - else - resultImage()->putPremultipliedImageData(imageData.get(), imageRect, IntPoint()); } void FEConvolveMatrix::dump() diff --git a/WebCore/platform/graphics/filters/FEDisplacementMap.cpp b/WebCore/platform/graphics/filters/FEDisplacementMap.cpp index 55321e6..93239c4 100644 --- a/WebCore/platform/graphics/filters/FEDisplacementMap.cpp +++ b/WebCore/platform/graphics/filters/FEDisplacementMap.cpp @@ -78,57 +78,57 @@ void FEDisplacementMap::setScale(float scale) void FEDisplacementMap::apply() { + if (hasResult()) + return; FilterEffect* in = inputEffect(0); FilterEffect* in2 = inputEffect(1); in->apply(); in2->apply(); - if (!in->resultImage() || !in2->resultImage()) + if (!in->hasResult() || !in2->hasResult()) return; if (m_xChannelSelector == CHANNEL_UNKNOWN || m_yChannelSelector == CHANNEL_UNKNOWN) return; - if (!effectContext()) + ImageData* resultImage = createPremultipliedImageResult(); + if (!resultImage) return; IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); - RefPtr<ImageData> srcImageDataA = in->resultImage()->getPremultipliedImageData(effectADrawingRect); - ByteArray* srcPixelArrayA = srcImageDataA->data()->data() ; + RefPtr<ImageData> srcImageDataA = in->asPremultipliedImage(effectADrawingRect); + ByteArray* srcPixelArrayA = srcImageDataA->data()->data(); IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect()); - RefPtr<ImageData> srcImageDataB = in2->resultImage()->getUnmultipliedImageData(effectBDrawingRect); + RefPtr<ImageData> srcImageDataB = in2->asUnmultipliedImage(effectBDrawingRect); ByteArray* srcPixelArrayB = srcImageDataB->data()->data(); - IntRect imageRect(IntPoint(), resultImage()->size()); - RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height()); - ByteArray* dstPixelArray = imageData->data()->data(); + ByteArray* dstPixelArray = resultImage->data()->data(); ASSERT(srcPixelArrayA->length() == srcPixelArrayB->length()); Filter* filter = this->filter(); + IntSize paintSize = absolutePaintRect().size(); float scaleX = filter->applyHorizontalScale(m_scale / 255); float scaleY = filter->applyVerticalScale(m_scale / 255); float scaleAdjustmentX = filter->applyHorizontalScale(0.5f - 0.5f * m_scale); float scaleAdjustmentY = filter->applyVerticalScale(0.5f - 0.5f * m_scale); - int stride = imageRect.width() * 4; - for (int y = 0; y < imageRect.height(); ++y) { + int stride = paintSize.width() * 4; + for (int y = 0; y < paintSize.height(); ++y) { int line = y * stride; - for (int x = 0; x < imageRect.width(); ++x) { + for (int x = 0; x < paintSize.width(); ++x) { int dstIndex = line + x * 4; int srcX = x + static_cast<int>(scaleX * srcPixelArrayB->get(dstIndex + m_xChannelSelector - 1) + scaleAdjustmentX); int srcY = y + static_cast<int>(scaleY * srcPixelArrayB->get(dstIndex + m_yChannelSelector - 1) + scaleAdjustmentY); for (unsigned channel = 0; channel < 4; ++channel) { - if (srcX < 0 || srcX >= imageRect.width() || srcY < 0 || srcY >= imageRect.height()) + if (srcX < 0 || srcX >= paintSize.width() || srcY < 0 || srcY >= paintSize.height()) dstPixelArray->set(dstIndex + channel, static_cast<unsigned char>(0)); else { unsigned char pixelValue = srcPixelArrayA->get(srcY * stride + srcX * 4 + channel); dstPixelArray->set(dstIndex + channel, pixelValue); } } - } } - resultImage()->putPremultipliedImageData(imageData.get(), imageRect, IntPoint()); } void FEDisplacementMap::dump() diff --git a/WebCore/platform/graphics/filters/FEFlood.cpp b/WebCore/platform/graphics/filters/FEFlood.cpp index bc6721b..8bfdef8 100644 --- a/WebCore/platform/graphics/filters/FEFlood.cpp +++ b/WebCore/platform/graphics/filters/FEFlood.cpp @@ -64,12 +64,14 @@ void FEFlood::setFloodOpacity(float floodOpacity) void FEFlood::apply() { - GraphicsContext* filterContext = effectContext(); - if (!filterContext) + if (hasResult()) + return; + ImageBuffer* resultImage = createImageBufferResult(); + if (!resultImage) return; Color color = colorWithOverrideAlpha(floodColor().rgb(), floodOpacity()); - filterContext->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size()), color, ColorSpaceDeviceRGB); + resultImage->context()->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size()), color, ColorSpaceDeviceRGB); } void FEFlood::dump() diff --git a/WebCore/platform/graphics/filters/FEGaussianBlur.cpp b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp index 876e4b3..e1ffcb7 100644 --- a/WebCore/platform/graphics/filters/FEGaussianBlur.cpp +++ b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp @@ -164,34 +164,35 @@ void FEGaussianBlur::determineAbsolutePaintRect() void FEGaussianBlur::apply() { + if (hasResult()) + return; FilterEffect* in = inputEffect(0); in->apply(); - if (!in->resultImage()) + if (!in->hasResult()) return; - if (!effectContext()) + ImageData* resultImage = createPremultipliedImageResult(); + if (!resultImage) return; setIsAlphaImage(in->isAlphaImage()); IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); - RefPtr<ImageData> srcImageData = in->resultImage()->getPremultipliedImageData(effectDrawingRect); - IntRect imageRect(IntPoint(), resultImage()->size()); + in->copyPremultipliedImage(resultImage, effectDrawingRect); - if (!m_stdX && !m_stdY) { - resultImage()->putPremultipliedImageData(srcImageData.get(), imageRect, IntPoint()); + if (!m_stdX && !m_stdY) return; - } unsigned kernelSizeX = 0; unsigned kernelSizeY = 0; calculateKernelSize(filter(), kernelSizeX, kernelSizeY, m_stdX, m_stdY); - ByteArray* srcPixelArray = srcImageData->data()->data(); - RefPtr<ImageData> tmpImageData = ImageData::create(imageRect.width(), imageRect.height()); + IntSize paintSize = absolutePaintRect().size(); + ByteArray* srcPixelArray = resultImage->data()->data(); + RefPtr<ImageData> tmpImageData = ImageData::create(paintSize.width(), paintSize.height()); ByteArray* tmpPixelArray = tmpImageData->data()->data(); - int stride = 4 * imageRect.width(); + int stride = 4 * paintSize.width(); int dxLeft = 0; int dxRight = 0; int dyLeft = 0; @@ -199,7 +200,7 @@ void FEGaussianBlur::apply() for (int i = 0; i < 3; ++i) { if (kernelSizeX) { kernelPosition(i, kernelSizeX, dxLeft, dxRight); - boxBlur(srcPixelArray, tmpPixelArray, kernelSizeX, dxLeft, dxRight, 4, stride, imageRect.width(), imageRect.height(), isAlphaImage()); + boxBlur(srcPixelArray, tmpPixelArray, kernelSizeX, dxLeft, dxRight, 4, stride, paintSize.width(), paintSize.height(), isAlphaImage()); } else { ByteArray* auxPixelArray = tmpPixelArray; tmpPixelArray = srcPixelArray; @@ -208,15 +209,13 @@ void FEGaussianBlur::apply() if (kernelSizeY) { kernelPosition(i, kernelSizeY, dyLeft, dyRight); - boxBlur(tmpPixelArray, srcPixelArray, kernelSizeY, dyLeft, dyRight, stride, 4, imageRect.height(), imageRect.width(), isAlphaImage()); + boxBlur(tmpPixelArray, srcPixelArray, kernelSizeY, dyLeft, dyRight, stride, 4, paintSize.height(), paintSize.width(), isAlphaImage()); } else { ByteArray* auxPixelArray = tmpPixelArray; tmpPixelArray = srcPixelArray; srcPixelArray = auxPixelArray; } } - - resultImage()->putPremultipliedImageData(srcImageData.get(), imageRect, IntPoint()); } void FEGaussianBlur::dump() diff --git a/WebCore/platform/graphics/filters/FELighting.cpp b/WebCore/platform/graphics/filters/FELighting.cpp index 812920c..4db40f1 100644 --- a/WebCore/platform/graphics/filters/FELighting.cpp +++ b/WebCore/platform/graphics/filters/FELighting.cpp @@ -331,19 +331,22 @@ bool FELighting::drawLighting(ByteArray* pixels, int width, int height) void FELighting::apply() { + if (hasResult()) + return; FilterEffect* in = inputEffect(0); in->apply(); - if (!in->resultImage()) + if (!in->hasResult()) return; - if (!effectContext()) + ImageData* resultImage = createUnmultipliedImageResult(); + if (!resultImage) return; setIsAlphaImage(false); IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); - RefPtr<ImageData> srcImageData = in->resultImage()->getUnmultipliedImageData(effectDrawingRect); - ByteArray* srcPixelArray = srcImageData->data()->data(); + in->copyUnmultipliedImage(resultImage, effectDrawingRect); + ByteArray* srcPixelArray = resultImage->data()->data(); // FIXME: support kernelUnitLengths other than (1,1). The issue here is that the W3 // standard has no test case for them, and other browsers (like Firefox) has strange @@ -351,8 +354,7 @@ void FELighting::apply() // Anyway, feConvolveMatrix should also use the implementation IntSize absolutePaintSize = absolutePaintRect().size(); - if (drawLighting(srcPixelArray, absolutePaintSize.width(), absolutePaintSize.height())) - resultImage()->putUnmultipliedImageData(srcImageData.get(), IntRect(IntPoint(), absolutePaintSize), IntPoint()); + drawLighting(srcPixelArray, absolutePaintSize.width(), absolutePaintSize.height()); } } // namespace WebCore diff --git a/WebCore/platform/graphics/filters/FEMerge.cpp b/WebCore/platform/graphics/filters/FEMerge.cpp index ca53a86..4395321 100644 --- a/WebCore/platform/graphics/filters/FEMerge.cpp +++ b/WebCore/platform/graphics/filters/FEMerge.cpp @@ -41,22 +41,25 @@ PassRefPtr<FEMerge> FEMerge::create(Filter* filter) void FEMerge::apply() { + if (hasResult()) + return; unsigned size = numberOfEffectInputs(); ASSERT(size > 0); for (unsigned i = 0; i < size; ++i) { FilterEffect* in = inputEffect(i); in->apply(); - if (!in->resultImage()) + if (!in->hasResult()) return; } - GraphicsContext* filterContext = effectContext(); - if (!filterContext) + ImageBuffer* resultImage = createImageBufferResult(); + if (!resultImage) return; + GraphicsContext* filterContext = resultImage->context(); for (unsigned i = 0; i < size; ++i) { FilterEffect* in = inputEffect(i); - filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); + filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); } } diff --git a/WebCore/platform/graphics/filters/FEMerge.h b/WebCore/platform/graphics/filters/FEMerge.h index 24d071e..dbee610 100644 --- a/WebCore/platform/graphics/filters/FEMerge.h +++ b/WebCore/platform/graphics/filters/FEMerge.h @@ -20,7 +20,7 @@ */ #ifndef FEMerge_h -#define EMerge_h +#define FEMerge_h #if ENABLE(FILTERS) #include "FilterEffect.h" diff --git a/WebCore/platform/graphics/filters/FEMorphology.cpp b/WebCore/platform/graphics/filters/FEMorphology.cpp index dd7659a..b20adc5 100644 --- a/WebCore/platform/graphics/filters/FEMorphology.cpp +++ b/WebCore/platform/graphics/filters/FEMorphology.cpp @@ -91,12 +91,15 @@ void FEMorphology::setRadiusY(float radiusY) void FEMorphology::apply() { + if (hasResult()) + return; FilterEffect* in = inputEffect(0); in->apply(); - if (!in->resultImage()) + if (!in->hasResult()) return; - if (!effectContext()) + ImageData* resultImage = createPremultipliedImageResult(); + if (!resultImage) return; setIsAlphaImage(in->isAlphaImage()); @@ -107,12 +110,10 @@ void FEMorphology::apply() int radiusX = static_cast<int>(floorf(filter->applyHorizontalScale(m_radiusX))); int radiusY = static_cast<int>(floorf(filter->applyVerticalScale(m_radiusY))); - IntRect imageRect(IntPoint(), resultImage()->size()); IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); - RefPtr<ImageData> srcImageData = in->resultImage()->getPremultipliedImageData(effectDrawingRect); + RefPtr<ImageData> srcImageData = in->asPremultipliedImage(effectDrawingRect); ByteArray* srcPixelArray = srcImageData->data()->data(); - RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height()); - ByteArray* dstPixelArray = imageData->data()->data(); + ByteArray* dstPixelArray = resultImage->data()->data(); int effectWidth = effectDrawingRect.width() * 4; @@ -162,7 +163,6 @@ void FEMorphology::apply() } } } - resultImage()->putPremultipliedImageData(imageData.get(), imageRect, IntPoint()); } void FEMorphology::dump() diff --git a/WebCore/platform/graphics/filters/FEOffset.cpp b/WebCore/platform/graphics/filters/FEOffset.cpp index b640054..f1d5914 100644 --- a/WebCore/platform/graphics/filters/FEOffset.cpp +++ b/WebCore/platform/graphics/filters/FEOffset.cpp @@ -74,13 +74,15 @@ void FEOffset::determineAbsolutePaintRect() void FEOffset::apply() { + if (hasResult()) + return; FilterEffect* in = inputEffect(0); in->apply(); - if (!in->resultImage()) + if (!in->hasResult()) return; - GraphicsContext* filterContext = effectContext(); - if (!filterContext) + ImageBuffer* resultImage = createImageBufferResult(); + if (!resultImage) return; setIsAlphaImage(in->isAlphaImage()); @@ -88,7 +90,7 @@ void FEOffset::apply() FloatRect drawingRegion = drawingRegionOfInputImage(in->absolutePaintRect()); Filter* filter = this->filter(); drawingRegion.move(filter->applyHorizontalScale(m_dx), filter->applyVerticalScale(m_dy)); - filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegion); + resultImage->context()->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegion); } void FEOffset::dump() diff --git a/WebCore/platform/graphics/filters/FETile.cpp b/WebCore/platform/graphics/filters/FETile.cpp index 6b11401..e516c7e 100644 --- a/WebCore/platform/graphics/filters/FETile.cpp +++ b/WebCore/platform/graphics/filters/FETile.cpp @@ -45,13 +45,15 @@ void FETile::apply() { // FIXME: See bug 47315. This is a hack to work around a compile failure, but is incorrect behavior otherwise. #if ENABLE(SVG) + if (hasResult()) + return; FilterEffect* in = inputEffect(0); in->apply(); - if (!in->resultImage()) + if (!in->hasResult()) return; - GraphicsContext* filterContext = effectContext(); - if (!filterContext) + ImageBuffer* resultImage = createImageBufferResult(); + if (!resultImage) return; setIsAlphaImage(in->isAlphaImage()); @@ -73,13 +75,14 @@ void FETile::apply() GraphicsContext* tileImageContext = tileImage->context(); tileImageContext->translate(-inMaxEffectLocation.x(), -inMaxEffectLocation.y()); - tileImageContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, in->absolutePaintRect().location()); + tileImageContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, in->absolutePaintRect().location()); RefPtr<Pattern> pattern = Pattern::create(tileImage->copyImage(), true, true); AffineTransform patternTransform; patternTransform.translate(inMaxEffectLocation.x() - maxEffectLocation.x(), inMaxEffectLocation.y() - maxEffectLocation.y()); pattern->setPatternSpaceTransform(patternTransform); + GraphicsContext* filterContext = resultImage->context(); filterContext->setFillPattern(pattern); filterContext->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size())); #endif diff --git a/WebCore/platform/graphics/filters/FETurbulence.cpp b/WebCore/platform/graphics/filters/FETurbulence.cpp index 8914db7..becf784 100644 --- a/WebCore/platform/graphics/filters/FETurbulence.cpp +++ b/WebCore/platform/graphics/filters/FETurbulence.cpp @@ -320,15 +320,16 @@ unsigned char FETurbulence::calculateTurbulenceValueForPoint(PaintingData& paint void FETurbulence::apply() { - if (!effectContext()) + if (hasResult()) + return; + ImageData* resultImage = createUnmultipliedImageResult(); + if (!resultImage) return; - IntRect imageRect(IntPoint(), resultImage()->size()); - if (!imageRect.size().width() || !imageRect.size().height()) + if (absolutePaintRect().isEmpty()) return; - RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height()); - ByteArray* pixelArray = imageData->data()->data(); + ByteArray* pixelArray = resultImage->data()->data(); PaintingData paintingData(m_seed, roundedIntSize(filterPrimitiveSubregion().size())); initPaint(paintingData); @@ -336,16 +337,15 @@ void FETurbulence::apply() FloatPoint point; point.setY(filterRegion.y()); int indexOfPixelChannel = 0; - for (int y = 0; y < imageRect.height(); ++y) { + for (int y = 0; y < absolutePaintRect().height(); ++y) { point.setY(point.y() + 1); point.setX(filterRegion.x()); - for (int x = 0; x < imageRect.width(); ++x) { + for (int x = 0; x < absolutePaintRect().width(); ++x) { point.setX(point.x() + 1); for (paintingData.channel = 0; paintingData.channel < 4; ++paintingData.channel, ++indexOfPixelChannel) pixelArray->set(indexOfPixelChannel, calculateTurbulenceValueForPoint(paintingData, filter()->mapAbsolutePointToLocalPoint(point))); } } - resultImage()->putUnmultipliedImageData(imageData.get(), imageRect, IntPoint()); } void FETurbulence::dump() diff --git a/WebCore/platform/graphics/filters/FilterEffect.cpp b/WebCore/platform/graphics/filters/FilterEffect.cpp index c228731..ebc6af0 100644 --- a/WebCore/platform/graphics/filters/FilterEffect.cpp +++ b/WebCore/platform/graphics/filters/FilterEffect.cpp @@ -23,6 +23,7 @@ #if ENABLE(FILTERS) #include "FilterEffect.h" +#include "ImageData.h" namespace WebCore { @@ -54,10 +55,10 @@ void FilterEffect::determineAbsolutePaintRect() IntRect FilterEffect::requestedRegionOfInputImageData(const IntRect& effectRect) const { - ASSERT(m_effectBuffer); + ASSERT(hasResult()); IntPoint location = m_absolutePaintRect.location(); location.move(-effectRect.x(), -effectRect.y()); - return IntRect(location, m_effectBuffer->size()); + return IntRect(location, m_absolutePaintRect.size()); } IntRect FilterEffect::drawingRegionOfInputImage(const IntRect& srcRect) const @@ -72,15 +73,170 @@ FilterEffect* FilterEffect::inputEffect(unsigned number) const return m_inputEffects.at(number).get(); } -GraphicsContext* FilterEffect::effectContext() +ImageBuffer* FilterEffect::asImageBuffer() { + if (!hasResult()) + return 0; + if (m_imageBufferResult) + return m_imageBufferResult.get(); + m_imageBufferResult = ImageBuffer::create(m_absolutePaintRect.size(), ColorSpaceLinearRGB); + IntRect destinationRect(IntPoint(), m_absolutePaintRect.size()); + if (m_premultipliedImageResult) + m_imageBufferResult->putPremultipliedImageData(m_premultipliedImageResult.get(), destinationRect, IntPoint()); + else + m_imageBufferResult->putUnmultipliedImageData(m_unmultipliedImageResult.get(), destinationRect, IntPoint()); + return m_imageBufferResult.get(); +} + +PassRefPtr<ImageData> FilterEffect::asUnmultipliedImage(const IntRect& rect) +{ + RefPtr<ImageData> imageData = ImageData::create(rect.width(), rect.height()); + copyUnmultipliedImage(imageData.get(), rect); + return imageData.release(); +} + +PassRefPtr<ImageData> FilterEffect::asPremultipliedImage(const IntRect& rect) +{ + RefPtr<ImageData> imageData = ImageData::create(rect.width(), rect.height()); + copyPremultipliedImage(imageData.get(), rect); + return imageData.release(); +} + +inline void FilterEffect::copyImageBytes(ImageData* source, ImageData* destination, const IntRect& rect) +{ + // Copy the necessary lines. + ASSERT(IntSize(destination->width(), destination->height()) == rect.size()); + if (rect.x() < 0 || rect.y() < 0 || rect.bottom() > m_absolutePaintRect.width() || rect.bottom() > m_absolutePaintRect.height()) + memset(destination->data()->data()->data(), 0, destination->data()->length()); + + int xOrigin = rect.x(); + int xDest = 0; + if (xOrigin < 0) { + xDest = -xOrigin; + xOrigin = 0; + } + int xEnd = rect.right(); + if (xEnd > m_absolutePaintRect.width()) + xEnd = m_absolutePaintRect.width(); + + int yOrigin = rect.y(); + int yDest = 0; + if (yOrigin < 0) { + yDest = -yOrigin; + yOrigin = 0; + } + int yEnd = rect.bottom(); + if (yEnd > m_absolutePaintRect.height()) + yEnd = m_absolutePaintRect.height(); + + int size = (xEnd - xOrigin) * 4; + int destinationScanline = rect.width() * 4; + int sourceScanline = m_absolutePaintRect.width() * 4; + unsigned char *destinationPixel = destination->data()->data()->data() + ((yDest * rect.width()) + xDest) * 4; + unsigned char *sourcePixel = source->data()->data()->data() + ((yOrigin * m_absolutePaintRect.width()) + xOrigin) * 4; + + while (yOrigin < yEnd) { + memcpy(destinationPixel, sourcePixel, size); + destinationPixel += destinationScanline; + sourcePixel += sourceScanline; + ++yOrigin; + } +} + +void FilterEffect::copyUnmultipliedImage(ImageData* destination, const IntRect& rect) +{ + ASSERT(hasResult()); + + if (!m_unmultipliedImageResult) { + // We prefer a conversion from the image buffer. + if (m_imageBufferResult) + m_unmultipliedImageResult = m_imageBufferResult->getUnmultipliedImageData(IntRect(IntPoint(), m_absolutePaintRect.size())); + else { + m_unmultipliedImageResult = ImageData::create(m_absolutePaintRect.width(), m_absolutePaintRect.height()); + unsigned char* sourceComponent = m_premultipliedImageResult->data()->data()->data(); + unsigned char* destinationComponent = m_unmultipliedImageResult->data()->data()->data(); + unsigned char* end = sourceComponent + (m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4); + while (sourceComponent < end) { + int alpha = sourceComponent[3]; + if (alpha) { + destinationComponent[0] = static_cast<int>(sourceComponent[0]) * 255 / alpha; + destinationComponent[1] = static_cast<int>(sourceComponent[1]) * 255 / alpha; + destinationComponent[2] = static_cast<int>(sourceComponent[2]) * 255 / alpha; + } else { + destinationComponent[0] = 0; + destinationComponent[1] = 0; + destinationComponent[2] = 0; + } + destinationComponent[3] = alpha; + sourceComponent += 4; + destinationComponent += 4; + } + } + } + copyImageBytes(m_unmultipliedImageResult.get(), destination, rect); +} + +void FilterEffect::copyPremultipliedImage(ImageData* destination, const IntRect& rect) +{ + ASSERT(hasResult()); + + if (!m_premultipliedImageResult) { + // We prefer a conversion from the image buffer. + if (m_imageBufferResult) + m_premultipliedImageResult = m_imageBufferResult->getPremultipliedImageData(IntRect(IntPoint(), m_absolutePaintRect.size())); + else { + m_premultipliedImageResult = ImageData::create(m_absolutePaintRect.width(), m_absolutePaintRect.height()); + unsigned char* sourceComponent = m_unmultipliedImageResult->data()->data()->data(); + unsigned char* destinationComponent = m_premultipliedImageResult->data()->data()->data(); + unsigned char* end = sourceComponent + (m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4); + while (sourceComponent < end) { + int alpha = sourceComponent[3]; + destinationComponent[0] = static_cast<int>(sourceComponent[0]) * alpha / 255; + destinationComponent[1] = static_cast<int>(sourceComponent[1]) * alpha / 255; + destinationComponent[2] = static_cast<int>(sourceComponent[2]) * alpha / 255; + destinationComponent[3] = alpha; + sourceComponent += 4; + destinationComponent += 4; + } + } + } + copyImageBytes(m_premultipliedImageResult.get(), destination, rect); +} + +ImageBuffer* FilterEffect::createImageBufferResult() +{ + // Only one result type is allowed. + ASSERT(!hasResult()); + determineAbsolutePaintRect(); + if (m_absolutePaintRect.isEmpty()) + return 0; + m_imageBufferResult = ImageBuffer::create(m_absolutePaintRect.size(), ColorSpaceLinearRGB); + if (!m_imageBufferResult) + return 0; + ASSERT(m_imageBufferResult->context()); + return m_imageBufferResult.get(); +} + +ImageData* FilterEffect::createUnmultipliedImageResult() +{ + // Only one result type is allowed. + ASSERT(!hasResult()); determineAbsolutePaintRect(); if (m_absolutePaintRect.isEmpty()) return 0; - m_effectBuffer = ImageBuffer::create(m_absolutePaintRect.size(), ColorSpaceLinearRGB); - if (!m_effectBuffer) + m_unmultipliedImageResult = ImageData::create(m_absolutePaintRect.width(), m_absolutePaintRect.height()); + return m_unmultipliedImageResult.get(); +} + +ImageData* FilterEffect::createPremultipliedImageResult() +{ + // Only one result type is allowed. + ASSERT(!hasResult()); + determineAbsolutePaintRect(); + if (m_absolutePaintRect.isEmpty()) return 0; - return m_effectBuffer->context(); + m_premultipliedImageResult = ImageData::create(m_absolutePaintRect.width(), m_absolutePaintRect.height()); + return m_premultipliedImageResult.get(); } TextStream& FilterEffect::externalRepresentation(TextStream& ts, int) const diff --git a/WebCore/platform/graphics/filters/FilterEffect.h b/WebCore/platform/graphics/filters/FilterEffect.h index f9674e2..81d5409 100644 --- a/WebCore/platform/graphics/filters/FilterEffect.h +++ b/WebCore/platform/graphics/filters/FilterEffect.h @@ -50,13 +50,12 @@ class FilterEffect : public RefCounted<FilterEffect> { public: virtual ~FilterEffect(); - // The result is bounded to the size of the filter primitive to save resources. - ImageBuffer* resultImage() const { return m_effectBuffer.get(); } - void setEffectBuffer(PassOwnPtr<ImageBuffer> effectBuffer) { m_effectBuffer = effectBuffer; } - - // Creates the ImageBuffer for the current filter primitive result in the size of the - // repaintRect. Gives back the GraphicsContext of the own ImageBuffer. - GraphicsContext* effectContext(); + bool hasResult() const { return m_imageBufferResult || m_unmultipliedImageResult || m_premultipliedImageResult; } + ImageBuffer* asImageBuffer(); + PassRefPtr<ImageData> asUnmultipliedImage(const IntRect&); + PassRefPtr<ImageData> asPremultipliedImage(const IntRect&); + void copyUnmultipliedImage(ImageData* destination, const IntRect&); + void copyPremultipliedImage(ImageData* destination, const IntRect&); FilterEffectVector& inputEffects() { return m_inputEffects; } FilterEffect* inputEffect(unsigned) const; @@ -110,8 +109,14 @@ public: protected: FilterEffect(Filter*); + ImageBuffer* createImageBufferResult(); + ImageData* createUnmultipliedImageResult(); + ImageData* createPremultipliedImageResult(); + private: - OwnPtr<ImageBuffer> m_effectBuffer; + OwnPtr<ImageBuffer> m_imageBufferResult; + RefPtr<ImageData> m_unmultipliedImageResult; + RefPtr<ImageData> m_premultipliedImageResult; FilterEffectVector m_inputEffects; bool m_alphaImage; @@ -124,6 +129,8 @@ private: Filter* m_filter; private: + inline void copyImageBytes(ImageData* source, ImageData* destination, const IntRect&); + // The following member variables are SVG specific and will move to RenderSVGResourceFilterPrimitive. // See bug https://bugs.webkit.org/show_bug.cgi?id=45614. diff --git a/WebCore/platform/graphics/filters/SourceAlpha.cpp b/WebCore/platform/graphics/filters/SourceAlpha.cpp index a505b4b..2d2de00 100644 --- a/WebCore/platform/graphics/filters/SourceAlpha.cpp +++ b/WebCore/platform/graphics/filters/SourceAlpha.cpp @@ -52,14 +52,17 @@ void SourceAlpha::determineAbsolutePaintRect() void SourceAlpha::apply() { - GraphicsContext* filterContext = effectContext(); + if (hasResult()) + return; + ImageBuffer* resultImage = createImageBufferResult(); Filter* filter = this->filter(); - if (!filterContext || !filter->sourceImage()) + if (!resultImage || !filter->sourceImage()) return; setIsAlphaImage(true); FloatRect imageRect(FloatPoint(), absolutePaintRect().size()); + GraphicsContext* filterContext = resultImage->context(); filterContext->save(); filterContext->clipToImageBuffer(filter->sourceImage(), imageRect); filterContext->fillRect(imageRect, Color::black, ColorSpaceDeviceRGB); diff --git a/WebCore/platform/graphics/filters/SourceGraphic.cpp b/WebCore/platform/graphics/filters/SourceGraphic.cpp index 6aac367..04082ad 100644 --- a/WebCore/platform/graphics/filters/SourceGraphic.cpp +++ b/WebCore/platform/graphics/filters/SourceGraphic.cpp @@ -51,12 +51,14 @@ void SourceGraphic::determineAbsolutePaintRect() void SourceGraphic::apply() { - GraphicsContext* filterContext = effectContext(); + if (hasResult()) + return; + ImageBuffer* resultImage = createImageBufferResult(); Filter* filter = this->filter(); - if (!filterContext || !filter->sourceImage()) + if (!resultImage || !filter->sourceImage()) return; - filterContext->drawImageBuffer(filter->sourceImage(), ColorSpaceDeviceRGB, IntPoint()); + resultImage->context()->drawImageBuffer(filter->sourceImage(), ColorSpaceDeviceRGB, IntPoint()); } void SourceGraphic::dump() diff --git a/WebCore/platform/graphics/filters/SourceGraphic.h b/WebCore/platform/graphics/filters/SourceGraphic.h index fa47f12..97d6882 100644 --- a/WebCore/platform/graphics/filters/SourceGraphic.h +++ b/WebCore/platform/graphics/filters/SourceGraphic.h @@ -19,7 +19,7 @@ */ #ifndef SourceGraphic_h -#define SourceGrahpic_h +#define SourceGraphic_h #if ENABLE(FILTERS) #include "FilterEffect.h" diff --git a/WebCore/platform/graphics/freetype/FontCacheFreeType.cpp b/WebCore/platform/graphics/freetype/FontCacheFreeType.cpp index 61ee625..1430124 100644 --- a/WebCore/platform/graphics/freetype/FontCacheFreeType.cpp +++ b/WebCore/platform/graphics/freetype/FontCacheFreeType.cpp @@ -181,19 +181,26 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD FcChar8* fontConfigFamilyNameAfterMatching; FcPatternGetString(resultPattern.get(), FC_FAMILY, 0, &fontConfigFamilyNameAfterMatching); String familyNameAfterMatching = String::fromUTF8(reinterpret_cast<char*>(fontConfigFamilyNameAfterMatching)); - if (equalIgnoringCase(familyNameAfterConfiguration, familyNameAfterMatching)) - return new FontPlatformData(resultPattern.get(), fontDescription); // If Fontconfig gave use a different font family than the one we requested, we should ignore it // and allow WebCore to give us the next font on the CSS fallback list. The only exception is if // this family name is a commonly used generic family. - if (equalIgnoringCase(familyNameString, "sans") || equalIgnoringCase(familyNameString, "sans-serif") - || equalIgnoringCase(familyNameString, "serif") || equalIgnoringCase(familyNameString, "monospace") - || equalIgnoringCase(familyNameString, "fantasy") || equalIgnoringCase(familyNameString, "cursive")) - return new FontPlatformData(resultPattern.get(), fontDescription); + if (!equalIgnoringCase(familyNameAfterConfiguration, familyNameAfterMatching) + && !(equalIgnoringCase(familyNameString, "sans") || equalIgnoringCase(familyNameString, "sans-serif") + || equalIgnoringCase(familyNameString, "serif") || equalIgnoringCase(familyNameString, "monospace") + || equalIgnoringCase(familyNameString, "fantasy") || equalIgnoringCase(familyNameString, "cursive"))) + return 0; - // Fontconfig did not return a good match. - return 0; + // Verify that this font has an encoding compatible with Fontconfig. Fontconfig currently + // supports three encodings in FcFreeTypeCharIndex: Unicode, Symbol and AppleRoman. + // If this font doesn't have one of these three encodings, don't select it. + FontPlatformData* platformData = new FontPlatformData(resultPattern.get(), fontDescription); + if (!platformData->hasCompatibleCharmap()) { + delete platformData; + return 0; + } + + return platformData; } } diff --git a/WebCore/platform/graphics/freetype/FontPlatformData.h b/WebCore/platform/graphics/freetype/FontPlatformData.h index 0793746..2841b14 100644 --- a/WebCore/platform/graphics/freetype/FontPlatformData.h +++ b/WebCore/platform/graphics/freetype/FontPlatformData.h @@ -68,6 +68,7 @@ public: void setSize(float size) { m_size = size; } bool syntheticBold() const { return m_syntheticBold; } bool syntheticOblique() const { return m_syntheticOblique; } + bool hasCompatibleCharmap(); FontOrientation orientation() const { return Horizontal; } // FIXME: Implement. diff --git a/WebCore/platform/graphics/freetype/FontPlatformDataFreeType.cpp b/WebCore/platform/graphics/freetype/FontPlatformDataFreeType.cpp index c0756ee..7340e76 100644 --- a/WebCore/platform/graphics/freetype/FontPlatformDataFreeType.cpp +++ b/WebCore/platform/graphics/freetype/FontPlatformDataFreeType.cpp @@ -272,5 +272,17 @@ void FontPlatformData::initializeWithFontFace(cairo_font_face_t* fontFace) cairo_font_options_destroy(options); } +bool FontPlatformData::hasCompatibleCharmap() +{ + if (!m_scaledFont) + return false; + + FT_Face freeTypeFace = cairo_ft_scaled_font_lock_face(m_scaledFont); + bool hasCompatibleCharmap = !(FT_Select_Charmap(freeTypeFace, ft_encoding_unicode) + && FT_Select_Charmap(freeTypeFace, ft_encoding_symbol) + && FT_Select_Charmap(freeTypeFace, ft_encoding_apple_roman)); + cairo_ft_scaled_font_unlock_face(m_scaledFont); + return hasCompatibleCharmap; +} } diff --git a/WebCore/platform/graphics/freetype/SimpleFontDataFreeType.cpp b/WebCore/platform/graphics/freetype/SimpleFontDataFreeType.cpp index cb096c3..97fd81a 100644 --- a/WebCore/platform/graphics/freetype/SimpleFontDataFreeType.cpp +++ b/WebCore/platform/graphics/freetype/SimpleFontDataFreeType.cpp @@ -79,16 +79,32 @@ void SimpleFontData::platformDestroy() { } +SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const +{ + return new SimpleFontData(FontPlatformData(cairo_scaled_font_get_font_face(m_platformData.scaledFont()), + scaleFactor * fontDescription.computedSize(), m_platformData.syntheticBold(), m_platformData.syntheticOblique()), + isCustomFont(), false); +} + SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const { + if (!m_derivedFontData) + m_derivedFontData = DerivedFontData::create(isCustomFont()); // FIXME: I think we want to ask FontConfig for the right font again. - if (!m_smallCapsFontData) - m_smallCapsFontData = new SimpleFontData( - FontPlatformData(cairo_scaled_font_get_font_face(m_platformData.scaledFont()), - 0.70f * fontDescription.computedSize(), m_platformData.syntheticBold(), m_platformData.syntheticOblique()), - isCustomFont(), false); + if (!m_derivedFontData->smallCaps) + m_derivedFontData->smallCaps = scaledFontData(fontDescription, .7); + + return m_derivedFontData->smallCaps.get(); +} + +SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const +{ + if (!m_derivedFontData) + m_derivedFontData = DerivedFontData::create(isCustomFont()); + if (!m_derivedFontData->emphasisMark) + m_derivedFontData->emphasisMark = scaledFontData(fontDescription, .5); - return m_smallCapsFontData; + return m_derivedFontData->emphasisMark.get(); } bool SimpleFontData::containsCharacters(const UChar* characters, int length) const diff --git a/WebCore/platform/graphics/gpu/DrawingBuffer.cpp b/WebCore/platform/graphics/gpu/DrawingBuffer.cpp index 8cb6d0c..d2415ca 100644 --- a/WebCore/platform/graphics/gpu/DrawingBuffer.cpp +++ b/WebCore/platform/graphics/gpu/DrawingBuffer.cpp @@ -41,7 +41,13 @@ namespace WebCore { PassRefPtr<DrawingBuffer> DrawingBuffer::create(GraphicsContext3D* context, const IntSize& size) { RefPtr<DrawingBuffer> drawingBuffer = adoptRef(new DrawingBuffer(context, size)); - drawingBuffer->m_multisampleExtensionSupported = context->getExtensions()->supports("GL_ANGLE_framebuffer_blit") && context->getExtensions()->supports("GL_ANGLE_framebuffer_multisample"); + Extensions3D* extensions = context->getExtensions(); + bool multisampleSupported = extensions->supports("GL_ANGLE_framebuffer_blit") && extensions->supports("GL_ANGLE_framebuffer_multisample"); + if (multisampleSupported) { + extensions->ensureEnabled("GL_ANGLE_framebuffer_blit"); + extensions->ensureEnabled("GL_ANGLE_framebuffer_multisample"); + } + drawingBuffer->m_multisampleExtensionSupported = multisampleSupported; return (drawingBuffer->m_context) ? drawingBuffer.release() : 0; } @@ -113,13 +119,11 @@ void DrawingBuffer::reset(const IntSize& newSize) // resize multisample FBO if (multisample()) { - int maxSampleCount; + int maxSampleCount = 0; m_context->getIntegerv(Extensions3D::MAX_SAMPLES, &maxSampleCount); int sampleCount = std::min(8, maxSampleCount); - if (sampleCount > maxSampleCount) - sampleCount = maxSampleCount; - + m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO); m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_multisampleColorBuffer); @@ -145,7 +149,7 @@ void DrawingBuffer::reset(const IntSize& newSize) m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo); m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_colorBuffer); - m_context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, internalColorFormat, m_size.width(), m_size.height(), 0, colorFormat, GraphicsContext3D::UNSIGNED_BYTE, 0); + m_context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, internalColorFormat, m_size.width(), m_size.height(), 0, colorFormat, GraphicsContext3D::UNSIGNED_BYTE); m_context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE, m_colorBuffer, 0); m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0); if (!multisample() && (attributes.stencil || attributes.depth)) { @@ -166,57 +170,48 @@ void DrawingBuffer::reset(const IntSize& newSize) if (multisample()) m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO); - // Initialize renderbuffers to 0. - float clearColor[] = {0, 0, 0, 0}, clearDepth = 0; - int clearStencil = 0; - unsigned char colorMask[] = {true, true, true, true}, depthMask = true; - unsigned int stencilMask = 0xffffffff; - unsigned char isScissorEnabled = false; - unsigned char isDitherEnabled = false; - unsigned long clearMask = GraphicsContext3D::COLOR_BUFFER_BIT; - m_context->getFloatv(GraphicsContext3D::COLOR_CLEAR_VALUE, clearColor); - m_context->clearColor(0, 0, 0, 0); - m_context->getBooleanv(GraphicsContext3D::COLOR_WRITEMASK, colorMask); - m_context->colorMask(true, true, true, true); - if (attributes.depth) { - m_context->getFloatv(GraphicsContext3D::DEPTH_CLEAR_VALUE, &clearDepth); - m_context->clearDepth(1); - m_context->getBooleanv(GraphicsContext3D::DEPTH_WRITEMASK, &depthMask); - m_context->depthMask(true); - clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT; - } - if (attributes.stencil) { - m_context->getIntegerv(GraphicsContext3D::STENCIL_CLEAR_VALUE, &clearStencil); - m_context->clearStencil(0); - m_context->getIntegerv(GraphicsContext3D::STENCIL_WRITEMASK, reinterpret_cast<int*>(&stencilMask)); - m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, 0xffffffff); - clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT; - } - isScissorEnabled = m_context->isEnabled(GraphicsContext3D::SCISSOR_TEST); - m_context->disable(GraphicsContext3D::SCISSOR_TEST); - isDitherEnabled = m_context->isEnabled(GraphicsContext3D::DITHER); - m_context->disable(GraphicsContext3D::DITHER); - - m_context->clear(clearMask); - - m_context->clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); - m_context->colorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]); - if (attributes.depth) { - m_context->clearDepth(clearDepth); - m_context->depthMask(depthMask); - } - if (attributes.stencil) { - m_context->clearStencil(clearStencil); - m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, stencilMask); + if (!m_context->getExtensions()->supports("GL_CHROMIUM_resource_safe")) { + // Initialize renderbuffers (depth/stencil). + float clearDepth = 0; + int clearStencil = 0; + unsigned char depthMask = true; + unsigned int stencilMask = 0xffffffff; + unsigned char isScissorEnabled = false; + unsigned long clearMask = 0; + if (attributes.depth) { + m_context->getFloatv(GraphicsContext3D::DEPTH_CLEAR_VALUE, &clearDepth); + m_context->clearDepth(1); + m_context->getBooleanv(GraphicsContext3D::DEPTH_WRITEMASK, &depthMask); + m_context->depthMask(true); + clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT; + } + if (attributes.stencil) { + m_context->getIntegerv(GraphicsContext3D::STENCIL_CLEAR_VALUE, &clearStencil); + m_context->clearStencil(0); + m_context->getIntegerv(GraphicsContext3D::STENCIL_WRITEMASK, reinterpret_cast<int*>(&stencilMask)); + m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, 0xffffffff); + clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT; + } + if (clearMask) { + isScissorEnabled = m_context->isEnabled(GraphicsContext3D::SCISSOR_TEST); + m_context->disable(GraphicsContext3D::SCISSOR_TEST); + + m_context->clear(clearMask); + + if (attributes.depth) { + m_context->clearDepth(clearDepth); + m_context->depthMask(depthMask); + } + if (attributes.stencil) { + m_context->clearStencil(clearStencil); + m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, stencilMask); + } + if (isScissorEnabled) + m_context->enable(GraphicsContext3D::SCISSOR_TEST); + else + m_context->disable(GraphicsContext3D::SCISSOR_TEST); + } } - if (isScissorEnabled) - m_context->enable(GraphicsContext3D::SCISSOR_TEST); - else - m_context->disable(GraphicsContext3D::SCISSOR_TEST); - if (isDitherEnabled) - m_context->enable(GraphicsContext3D::DITHER); - else - m_context->disable(GraphicsContext3D::DITHER); m_context->flush(); diff --git a/WebCore/platform/graphics/gpu/Shader.cpp b/WebCore/platform/graphics/gpu/Shader.cpp index 8983adc..6978322 100644 --- a/WebCore/platform/graphics/gpu/Shader.cpp +++ b/WebCore/platform/graphics/gpu/Shader.cpp @@ -65,7 +65,7 @@ unsigned Shader::loadShader(GraphicsContext3D* context, unsigned type, const cha String shaderSourceStr(shaderSource); context->shaderSource(shader, shaderSourceStr); context->compileShader(shader); - int compileStatus; + int compileStatus = 0; context->getShaderiv(shader, GraphicsContext3D::COMPILE_STATUS, &compileStatus); if (!compileStatus) { String infoLog = context->getShaderInfoLog(shader); @@ -91,7 +91,7 @@ unsigned Shader::loadProgram(GraphicsContext3D* context, const char* vertexShade context->attachShader(program, vertexShader); context->attachShader(program, fragmentShader); context->linkProgram(program); - int linkStatus; + int linkStatus = 0; context->getProgramiv(program, GraphicsContext3D::LINK_STATUS, &linkStatus); if (!linkStatus) context->deleteProgram(program); diff --git a/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp b/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp index a230384..a166d9c 100644 --- a/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp +++ b/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp @@ -68,11 +68,18 @@ PassRefPtr<SharedGraphicsContext3D> SharedGraphicsContext3D::create(HostWindow* SharedGraphicsContext3D::SharedGraphicsContext3D(PassRefPtr<GraphicsContext3D> context, PassOwnPtr<SolidFillShader> solidFillShader, PassOwnPtr<TexShader> texShader) : m_context(context) + , m_bgraSupported(false) , m_quadVertices(0) , m_solidFillShader(solidFillShader) , m_texShader(texShader) { allContexts()->add(this); + Extensions3D* extensions = m_context->getExtensions(); + m_bgraSupported = extensions->supports("GL_EXT_texture_format_BGRA8888") && extensions->supports("GL_EXT_read_format_bgra"); + if (m_bgraSupported) { + extensions->ensureEnabled("GL_EXT_texture_format_BGRA8888"); + extensions->ensureEnabled("GL_EXT_read_format_bgra"); + } } SharedGraphicsContext3D::~SharedGraphicsContext3D() @@ -165,6 +172,10 @@ void SharedGraphicsContext3D::texParameteri(unsigned target, unsigned pname, int int SharedGraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, void* pixels) { + if (!pixels) { + m_context->texImage2DResourceSafe(target, level, internalformat, width, height, border, format, type); + return 0; + } return m_context->texImage2D(target, level, internalformat, width, height, border, format, type, pixels); } @@ -180,8 +191,7 @@ void SharedGraphicsContext3D::readPixels(long x, long y, unsigned long width, un bool SharedGraphicsContext3D::supportsBGRA() { - return m_context->getExtensions()->supports("GL_EXT_texture_format_BGRA8888") - && m_context->getExtensions()->supports("GL_EXT_read_format_bgra"); + return m_bgraSupported; } Texture* SharedGraphicsContext3D::createTexture(NativeImagePtr ptr, Texture::Format format, int width, int height) diff --git a/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h b/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h index 86c64b4..a1ae8f2 100644 --- a/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h +++ b/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h @@ -124,6 +124,7 @@ private: void removeTextureFor(NativeImagePtr); RefPtr<GraphicsContext3D> m_context; + bool m_bgraSupported; unsigned m_quadVertices; diff --git a/WebCore/platform/graphics/gpu/Texture.cpp b/WebCore/platform/graphics/gpu/Texture.cpp index 18c9ead..e1f8114 100644 --- a/WebCore/platform/graphics/gpu/Texture.cpp +++ b/WebCore/platform/graphics/gpu/Texture.cpp @@ -106,15 +106,15 @@ PassRefPtr<Texture> Texture::create(GraphicsContext3D* context, Format format, i IntRect tileBoundsWithBorder = tiling.tileBoundsWithBorder(i); - unsigned int glFormat = 0; - unsigned int glType = 0; - bool swizzle; - convertFormat(context, format, &glFormat, &glType, &swizzle); - context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId); - context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, glFormat, - tileBoundsWithBorder.width(), - tileBoundsWithBorder.height(), - 0, glFormat, glType, 0); + unsigned int glFormat = 0; + unsigned int glType = 0; + bool swizzle; + convertFormat(context, format, &glFormat, &glType, &swizzle); + context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId); + context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, glFormat, + tileBoundsWithBorder.width(), + tileBoundsWithBorder.height(), + 0, glFormat, glType); } return adoptRef(new Texture(context, textureIds.leakPtr(), format, width, height, maxTextureSize)); } @@ -149,8 +149,11 @@ void Texture::load(void* pixels) updateSubRect(pixels, IntRect(0, 0, m_tiles.totalSizeX(), m_tiles.totalSizeY())); } -void Texture::updateSubRect(void* pixels, const IntRect updateRect) +void Texture::updateSubRect(void* pixels, const IntRect& updateRect) { + IntRect updateRectSanitized(updateRect); + updateRectSanitized.intersect(IntRect(0, 0, m_tiles.totalSizeX(), m_tiles.totalSizeY())); + uint32_t* pixels32 = static_cast<uint32_t*>(pixels); unsigned int glFormat = 0; unsigned int glType = 0; @@ -160,16 +163,16 @@ void Texture::updateSubRect(void* pixels, const IntRect updateRect) ASSERT(glFormat == GraphicsContext3D::RGBA && glType == GraphicsContext3D::UNSIGNED_BYTE); // FIXME: This could use PBO's to save doing an extra copy here. } - int tempBuffSize = // Temporary buffer size is the smaller of the max texture size or the updateRect - min(m_tiles.maxTextureSize(), m_tiles.borderTexels() + updateRect.width()) * - min(m_tiles.maxTextureSize(), m_tiles.borderTexels() + updateRect.height()); + int tempBuffSize = // Temporary buffer size is the smaller of the max texture size or the updateRectSanitized + min(m_tiles.maxTextureSize(), m_tiles.borderTexels() + updateRectSanitized.width()) * + min(m_tiles.maxTextureSize(), m_tiles.borderTexels() + updateRectSanitized.height()); OwnArrayPtr<uint32_t> tempBuff(new uint32_t[tempBuffSize]); for (int tile = 0; tile < m_tiles.numTiles(); tile++) { // Intersect with tile IntRect tileBoundsWithBorder = m_tiles.tileBoundsWithBorder(tile); - IntRect updateRectIntersected = updateRect; + IntRect updateRectIntersected = updateRectSanitized; updateRectIntersected.intersect(tileBoundsWithBorder); IntRect dstRect = updateRectIntersected; diff --git a/WebCore/platform/graphics/gpu/Texture.h b/WebCore/platform/graphics/gpu/Texture.h index 92b6d0a..1f35006 100644 --- a/WebCore/platform/graphics/gpu/Texture.h +++ b/WebCore/platform/graphics/gpu/Texture.h @@ -50,7 +50,7 @@ public: static PassRefPtr<Texture> create(GraphicsContext3D*, Format, int width, int height); void bindTile(int tile); void load(void* pixels); - void updateSubRect(void* pixels, const IntRect); + void updateSubRect(void* pixels, const IntRect&); Format format() const { return m_format; } const TilingData& tiles() const { return m_tiles; } private: diff --git a/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.cpp b/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.cpp deleted file mode 100644 index 5a94fd4..0000000 --- a/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (C) 2009 Igalia S.L - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include "DataSourceGStreamer.h" -#if USE(GSTREAMER) - -#include <gio/gio.h> -#include <glib.h> -#include <gst/gst.h> -#include <gst/pbutils/missing-plugins.h> - -static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -GST_DEBUG_CATEGORY_STATIC(webkit_data_src_debug); -#define GST_CAT_DEFAULT webkit_data_src_debug - -static void webkit_data_src_uri_handler_init(gpointer g_iface, - gpointer iface_data); - -static void webkit_data_src_finalize(WebkitDataSrc* src); -static GstStateChangeReturn webkit_data_src_change_state(GstElement* element, - GstStateChange transition); - -static const GInterfaceInfo urihandler_info = { - webkit_data_src_uri_handler_init, - 0, 0 -}; - - -static void _do_init(GType datasrc_type) -{ - GST_DEBUG_CATEGORY_INIT(webkit_data_src_debug, "webkit_data_src", 0, "datasrc element"); - g_type_add_interface_static(datasrc_type, GST_TYPE_URI_HANDLER, - &urihandler_info); -} - -GST_BOILERPLATE_FULL(WebkitDataSrc, webkit_data_src, GstBin, GST_TYPE_BIN, _do_init); - -static void webkit_data_src_base_init(gpointer klass) -{ - GstElementClass* element_class = GST_ELEMENT_CLASS(klass); - - gst_element_class_add_pad_template(element_class, - gst_static_pad_template_get(&src_template)); - gst_element_class_set_details_simple(element_class, (gchar*) "WebKit data source element", - (gchar*) "Source", - (gchar*) "Handles data: uris", - (gchar*) "Philippe Normand <pnormand@igalia.com>"); - -} - -static void webkit_data_src_class_init(WebkitDataSrcClass* klass) -{ - GObjectClass* oklass = G_OBJECT_CLASS(klass); - GstElementClass* eklass = GST_ELEMENT_CLASS(klass); - - oklass->finalize = (GObjectFinalizeFunc) webkit_data_src_finalize; - eklass->change_state = webkit_data_src_change_state; -} - - -static gboolean webkit_data_src_reset(WebkitDataSrc* src) -{ - GstPad* targetpad; - - if (src->kid) { - gst_element_set_state(src->kid, GST_STATE_NULL); - gst_bin_remove(GST_BIN(src), src->kid); - } - - src->kid = gst_element_factory_make("giostreamsrc", "streamsrc"); - if (!src->kid) { - GST_ERROR_OBJECT(src, "Failed to create giostreamsrc"); - return FALSE; - } - - gst_bin_add(GST_BIN(src), src->kid); - - targetpad = gst_element_get_static_pad(src->kid, "src"); - gst_ghost_pad_set_target(GST_GHOST_PAD(src->pad), targetpad); - gst_object_unref(targetpad); - - return TRUE; -} - -static void webkit_data_src_init(WebkitDataSrc* src, - WebkitDataSrcClass* g_class) -{ - GstPadTemplate* pad_template = gst_static_pad_template_get(&src_template); - src->pad = gst_ghost_pad_new_no_target_from_template("src", - pad_template); - - gst_element_add_pad(GST_ELEMENT(src), src->pad); - - webkit_data_src_reset(src); -} - -static void webkit_data_src_finalize(WebkitDataSrc* src) -{ - g_free(src->uri); - - if (src->kid) { - GST_DEBUG_OBJECT(src, "Removing giostreamsrc element"); - gst_element_set_state(src->kid, GST_STATE_NULL); - gst_bin_remove(GST_BIN(src), src->kid); - src->kid = 0; - } - - GST_CALL_PARENT(G_OBJECT_CLASS, finalize, ((GObject* )(src))); -} - -static GstStateChangeReturn webkit_data_src_change_state(GstElement* element, GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - WebkitDataSrc* src = WEBKIT_DATA_SRC(element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - if (!src->kid) { - gst_element_post_message(element, - gst_missing_element_message_new(element, "giostreamsrc")); - GST_ELEMENT_ERROR(src, CORE, MISSING_PLUGIN, (0), ("no giostreamsrc")); - return GST_STATE_CHANGE_FAILURE; - } - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition); - if (G_UNLIKELY(ret == GST_STATE_CHANGE_FAILURE)) - return ret; - - // Downwards state change code should be here, after chaining up - // to the parent class. - - return ret; -} - -/*** GSTURIHANDLER INTERFACE *************************************************/ - -static GstURIType webkit_data_src_uri_get_type(void) -{ - return GST_URI_SRC; -} - -static gchar** webkit_data_src_uri_get_protocols(void) -{ - static gchar* protocols[] = {(gchar*) "data", 0 }; - - return protocols; -} - -static const gchar* webkit_data_src_uri_get_uri(GstURIHandler* handler) -{ - WebkitDataSrc* src = WEBKIT_DATA_SRC(handler); - - return src->uri; -} - -static gboolean webkit_data_src_uri_set_uri(GstURIHandler* handler, const gchar* uri) -{ - WebkitDataSrc* src = WEBKIT_DATA_SRC(handler); - - // URI as defined in RFC2397: - // "data:" [ mediatype ] [ ";base64" ] "," data - // we parse URIs like this one: - // data:audio/3gpp;base64,AA... - - gchar** scheme_and_remains = g_strsplit(uri, ":", 2); - gchar** mime_type_and_options = g_strsplit(scheme_and_remains[1], ";", 0); - gint options_size = g_strv_length(mime_type_and_options); - gchar* data = 0; - gchar* mime_type = 0; - gint ret = FALSE; - - // we require uris with a specified mime-type and base64-encoded - // data. It doesn't make much sense anyway to play plain/text data - // with very few allowed characters (as per the RFC). - - if (GST_STATE(src) >= GST_STATE_PAUSED) { - GST_ERROR_OBJECT(src, "Element already configured. Reset it and retry"); - } else if (!options_size) - GST_ERROR_OBJECT(src, "A mime-type is needed in %s", uri); - else { - mime_type = mime_type_and_options[0]; - data = mime_type_and_options[options_size-1]; - - guchar* decoded_data = 0; - gsize decoded_size; - - if (!g_str_has_prefix(data, "base64")) - GST_ERROR_OBJECT(src, "Data has to be base64-encoded in %s", uri); - else { - decoded_data = g_base64_decode(data+7, &decoded_size); - GInputStream* stream = g_memory_input_stream_new_from_data(decoded_data, - decoded_size, - g_free); - g_object_set(src->kid, "stream", stream, NULL); - g_object_unref(stream); - - if (src->uri) { - g_free(src->uri); - src->uri = 0; - } - - src->uri = g_strdup(uri); - ret = TRUE; - } - } - - g_strfreev(scheme_and_remains); - g_strfreev(mime_type_and_options); - return ret; -} - -static void webkit_data_src_uri_handler_init(gpointer g_iface, gpointer iface_data) -{ - GstURIHandlerInterface* iface = (GstURIHandlerInterface *) g_iface; - - iface->get_type = webkit_data_src_uri_get_type; - iface->get_protocols = webkit_data_src_uri_get_protocols; - iface->get_uri = webkit_data_src_uri_get_uri; - iface->set_uri = webkit_data_src_uri_set_uri; -} - -#endif // USE(GSTREAMER) diff --git a/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.h b/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.h deleted file mode 100644 index d462ccc4..0000000 --- a/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2009 Igalia S.L - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef DataSourceGStreamer_h -#define DataSourceGStreamer_h - -#if USE(GSTREAMER) - -#include <glib-object.h> -#include <gst/base/gstbasesrc.h> - -G_BEGIN_DECLS - -#define WEBKIT_TYPE_DATA_SRC (webkit_data_src_get_type ()) -#define WEBKIT_DATA_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), WEBKIT_TYPE_DATA_SRC, WebkitDataSrc)) -#define WEBKIT_DATA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), WEBKIT_TYPE_DATA_SRC, WebkitDataSrcClass)) -#define WEBKIT_IS_DATA_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), WEBKIT_TYPE_DATA_SRC)) -#define WEBKIT_IS_DATA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), WEBKIT_TYPE_DATA_SRC)) - -typedef struct _WebkitDataSrc WebkitDataSrc; -typedef struct _WebkitDataSrcClass WebkitDataSrcClass; - - -struct _WebkitDataSrc { - GstBin parent; - - /* explicit pointers to stuff used */ - GstElement* kid; - GstPad* pad; - gchar* uri; -}; - -struct _WebkitDataSrcClass { - GstBinClass parent_class; -}; - -GType webkit_data_src_get_type(void); - -G_END_DECLS - -#endif // USE(GSTREAMER) -#endif diff --git a/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp b/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp index b18bf84..e8c87ac 100644 --- a/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp +++ b/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp @@ -91,9 +91,16 @@ bool GStreamerGWorld::enterFullscreen() g_object_set(valve, "drop-probability", 1.0, NULL); - // Add and link a queue, ffmpegcolorspace and sink in the bin. + // Add and link a queue, ffmpegcolorspace, videoscale and sink in the bin. gst_bin_add_many(GST_BIN(videoSink.get()), platformVideoSink, videoScale, colorspace, queue, NULL); +#if GST_CHECK_VERSION(0, 10, 30) + // Faster elements linking, if possible. + gst_element_link_pads_full(queue, "src", colorspace, "sink", GST_PAD_LINK_CHECK_NOTHING); + gst_element_link_pads_full(colorspace, "src", videoScale, "sink", GST_PAD_LINK_CHECK_NOTHING); + gst_element_link_pads_full(videoScale, "src", platformVideoSink, "sink", GST_PAD_LINK_CHECK_NOTHING); +#else gst_element_link_many(queue, colorspace, videoScale, platformVideoSink, NULL); +#endif // Link a new src pad from tee to queue. GstPad* srcPad = gst_element_get_request_pad(tee, "src%d"); diff --git a/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp index 695d1f7..3cddd2e 100644 --- a/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp +++ b/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp @@ -27,7 +27,6 @@ #if USE(GSTREAMER) #include "ColorSpace.h" -#include "DataSourceGStreamer.h" #include "Document.h" #include "Frame.h" #include "FrameView.h" @@ -134,6 +133,13 @@ gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpo mp->didEnd(); break; case GST_MESSAGE_STATE_CHANGED: + // Ignore state changes if load is delayed (preload=none). The + // player state will be updated once commitLoad() is called. + if (mp->loadDelayed()) { + LOG_VERBOSE(Media, "Media load has been delayed. Ignoring state changes for now"); + break; + } + // Ignore state changes from internal elements. They are // forwarded to playbin2 anyway. if (GST_MESSAGE_SRC(message) == reinterpret_cast<GstObject*>(pipeline)) @@ -177,6 +183,13 @@ void mediaPlayerPrivateVolumeChangedCallback(GObject *element, GParamSpec *pspec mp->volumeChanged(); } +gboolean mediaPlayerPrivateVolumeChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player) +{ + // This is the callback of the timeout source created in ::volumeChanged. + player->notifyPlayerOfVolumeChange(); + return FALSE; +} + void mediaPlayerPrivateMuteChangedCallback(GObject *element, GParamSpec *pspec, gpointer data) { // This is called when playbin receives the notify::mute signal. @@ -184,6 +197,37 @@ void mediaPlayerPrivateMuteChangedCallback(GObject *element, GParamSpec *pspec, mp->muteChanged(); } +gboolean mediaPlayerPrivateMuteChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player) +{ + // This is the callback of the timeout source created in ::muteChanged. + player->notifyPlayerOfMute(); + return FALSE; +} + +void mediaPlayerPrivateVideoTagsChangedCallback(GObject* element, gint streamId, MediaPlayerPrivateGStreamer* player) +{ + player->videoTagsChanged(streamId); +} + +void mediaPlayerPrivateAudioTagsChangedCallback(GObject* element, gint streamId, MediaPlayerPrivateGStreamer* player) +{ + player->audioTagsChanged(streamId); +} + +gboolean mediaPlayerPrivateAudioTagsChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player) +{ + // This is the callback of the timeout source created in ::audioTagsChanged. + player->notifyPlayerOfAudioTags(); + return FALSE; +} + +gboolean mediaPlayerPrivateVideoTagsChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player) +{ + // This is the callback of the timeout source created in ::videoTagsChanged. + player->notifyPlayerOfVideoTags(); + return FALSE; +} + static float playbackPosition(GstElement* playbin) { @@ -238,16 +282,12 @@ static bool doGstInit() if (!gstInitialized) { GOwnPtr<GError> error; gstInitialized = gst_init_check(0, 0, &error.outPtr()); - if (!gstInitialized) { + if (!gstInitialized) LOG_VERBOSE(Media, "Could not initialize GStreamer: %s", error ? error->message : "unknown error occurred"); - } else { - gst_element_register(0, "webkitmediasrc", GST_RANK_PRIMARY, - WEBKIT_TYPE_DATA_SRC); + else gst_element_register(0, "webkitwebsrc", GST_RANK_PRIMARY + 100, WEBKIT_TYPE_WEB_SRC); - } - } return gstInitialized; } @@ -295,6 +335,12 @@ MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer(MediaPlayer* player) , m_preload(MediaPlayer::Auto) , m_delayingLoad(false) , m_mediaDurationKnown(true) + , m_volumeTimerHandler(0) + , m_muteTimerHandler(0) + , m_hasVideo(false) + , m_hasAudio(false) + , m_audioTagsTimerHandler(0) + , m_videoTagsTimerHandler(0) { if (doGstInit()) createGSTPlayBin(); @@ -327,8 +373,22 @@ MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer() if (m_playBin) { gst_element_set_state(m_playBin, GST_STATE_NULL); gst_object_unref(GST_OBJECT(m_playBin)); + m_playBin = 0; } + m_player = 0; + + if (m_muteTimerHandler) + g_source_remove(m_muteTimerHandler); + + if (m_volumeTimerHandler) + g_source_remove(m_volumeTimerHandler); + + if (m_videoTagsTimerHandler) + g_source_remove(m_videoTagsTimerHandler); + + if (m_audioTagsTimerHandler) + g_source_remove(m_audioTagsTimerHandler); } void MediaPlayerPrivateGStreamer::load(const String& url) @@ -340,27 +400,21 @@ void MediaPlayerPrivateGStreamer::load(const String& url) if (m_preload == MediaPlayer::None) { LOG_VERBOSE(Media, "Delaying load."); m_delayingLoad = true; - return; } - commitLoad(); -} - -void MediaPlayerPrivateGStreamer::commitLoad() -{ // GStreamer needs to have the pipeline set to a paused state to // start providing anything useful. gst_element_set_state(m_playBin, GST_STATE_PAUSED); + if (!m_delayingLoad) + commitLoad(); +} + +void MediaPlayerPrivateGStreamer::commitLoad() +{ + ASSERT(!m_delayingLoad); LOG_VERBOSE(Media, "Committing load."); - if (m_networkState != MediaPlayer::Loading) { - m_networkState = MediaPlayer::Loading; - m_player->networkStateChanged(); - } - if (m_readyState != MediaPlayer::HaveNothing) { - m_readyState = MediaPlayer::HaveNothing; - m_player->readyStateChanged(); - } + updateStates(); } bool MediaPlayerPrivateGStreamer::changePipelineState(GstState newState) @@ -472,21 +526,6 @@ void MediaPlayerPrivateGStreamer::seek(float time) } } -void MediaPlayerPrivateGStreamer::startEndPointTimerIfNeeded() -{ - notImplemented(); -} - -void MediaPlayerPrivateGStreamer::cancelSeek() -{ - notImplemented(); -} - -void MediaPlayerPrivateGStreamer::endPointTimerFired(Timer<MediaPlayerPrivateGStreamer>*) -{ - notImplemented(); -} - bool MediaPlayerPrivateGStreamer::paused() const { return m_paused; @@ -560,20 +599,40 @@ IntSize MediaPlayerPrivateGStreamer::naturalSize() const return IntSize(static_cast<int>(width), static_cast<int>(height)); } -bool MediaPlayerPrivateGStreamer::hasVideo() const +void MediaPlayerPrivateGStreamer::videoTagsChanged(gint streamId) { + if (m_videoTagsTimerHandler) + g_source_remove(m_videoTagsTimerHandler); + m_videoTagsTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateVideoTagsChangeTimeoutCallback), this); +} + +void MediaPlayerPrivateGStreamer::notifyPlayerOfVideoTags() +{ + m_videoTagsTimerHandler = 0; + gint currentVideo = -1; if (m_playBin) g_object_get(m_playBin, "current-video", ¤tVideo, NULL); - return currentVideo > -1; + m_hasVideo = currentVideo > -1; + m_player->mediaPlayerClient()->mediaPlayerEngineUpdated(m_player); +} + +void MediaPlayerPrivateGStreamer::audioTagsChanged(gint streamId) +{ + if (m_audioTagsTimerHandler) + g_source_remove(m_audioTagsTimerHandler); + m_audioTagsTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateAudioTagsChangeTimeoutCallback), this); } -bool MediaPlayerPrivateGStreamer::hasAudio() const +void MediaPlayerPrivateGStreamer::notifyPlayerOfAudioTags() { + m_audioTagsTimerHandler = 0; + gint currentAudio = -1; if (m_playBin) g_object_get(m_playBin, "current-audio", ¤tAudio, NULL); - return currentAudio > -1; + m_hasAudio = currentAudio > -1; + m_player->mediaPlayerClient()->mediaPlayerEngineUpdated(m_player); } void MediaPlayerPrivateGStreamer::setVolume(float volume) @@ -584,8 +643,12 @@ void MediaPlayerPrivateGStreamer::setVolume(float volume) g_object_set(m_playBin, "volume", static_cast<double>(volume), NULL); } -void MediaPlayerPrivateGStreamer::volumeChangedTimerFired(Timer<MediaPlayerPrivateGStreamer>*) +void MediaPlayerPrivateGStreamer::notifyPlayerOfVolumeChange() { + m_volumeTimerHandler = 0; + + if (!m_player || !m_playBin) + return; double volume; g_object_get(m_playBin, "volume", &volume, NULL); m_player->volumeChanged(static_cast<float>(volume)); @@ -593,8 +656,9 @@ void MediaPlayerPrivateGStreamer::volumeChangedTimerFired(Timer<MediaPlayerPriva void MediaPlayerPrivateGStreamer::volumeChanged() { - Timer<MediaPlayerPrivateGStreamer> volumeChangedTimer(this, &MediaPlayerPrivateGStreamer::volumeChangedTimerFired); - volumeChangedTimer.startOneShot(0); + if (m_volumeTimerHandler) + g_source_remove(m_volumeTimerHandler); + m_volumeTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateVolumeChangeTimeoutCallback), this); } void MediaPlayerPrivateGStreamer::setRate(float rate) @@ -663,9 +727,40 @@ MediaPlayer::ReadyState MediaPlayerPrivateGStreamer::readyState() const PassRefPtr<TimeRanges> MediaPlayerPrivateGStreamer::buffered() const { RefPtr<TimeRanges> timeRanges = TimeRanges::create(); + if (m_errorOccured || m_isStreaming) + return timeRanges.release(); + +#if GST_CHECK_VERSION(0, 10, 31) + float mediaDuration(duration()); + if (!mediaDuration || isinf(mediaDuration)) + return timeRanges.release(); + + GstQuery* query = gst_query_new_buffering(GST_FORMAT_PERCENT); + + if (!gst_element_query(m_playBin, query)) { + gst_query_unref(query); + return timeRanges.release(); + } + + gint64 rangeStart = 0, rangeStop = 0; + for (guint index = 0; index < gst_query_get_n_buffering_ranges(query); index++) { + if (gst_query_parse_nth_buffering_range(query, index, &rangeStart, &rangeStop)) + timeRanges->add(static_cast<float>((rangeStart * mediaDuration) / 100), + static_cast<float>((rangeStop * mediaDuration) / 100)); + } + + // Fallback to the more general maxTimeLoaded() if no range has + // been found. + if (!timeRanges->length()) + if (float loaded = maxTimeLoaded()) + timeRanges->add(0, loaded); + + gst_query_unref(query); +#else float loaded = maxTimeLoaded(); if (!m_errorOccured && !m_isStreaming && loaded > 0) timeRanges->add(0, loaded); +#endif return timeRanges.release(); } @@ -1140,8 +1235,10 @@ void MediaPlayerPrivateGStreamer::durationChanged() float previousDuration = m_mediaDuration; cacheDuration(); - - if (m_mediaDuration != previousDuration) + // Avoid emiting durationchanged in the case where the previous + // duration was 0 because that case is already handled by the + // HTMLMediaElement. + if (previousDuration && m_mediaDuration != previousDuration) m_player->durationChanged(); } @@ -1158,8 +1255,13 @@ void MediaPlayerPrivateGStreamer::setMuted(bool muted) g_object_set(m_playBin, "mute", muted, NULL); } -void MediaPlayerPrivateGStreamer::muteChangedTimerFired(Timer<MediaPlayerPrivateGStreamer>*) +void MediaPlayerPrivateGStreamer::notifyPlayerOfMute() { + m_muteTimerHandler = 0; + + if (!m_player || !m_playBin) + return; + gboolean muted; g_object_get(m_playBin, "mute", &muted, NULL); m_player->muteChanged(static_cast<bool>(muted)); @@ -1167,8 +1269,9 @@ void MediaPlayerPrivateGStreamer::muteChangedTimerFired(Timer<MediaPlayerPrivate void MediaPlayerPrivateGStreamer::muteChanged() { - Timer<MediaPlayerPrivateGStreamer> muteChangedTimer(this, &MediaPlayerPrivateGStreamer::muteChangedTimerFired); - muteChangedTimer.startOneShot(0); + if (m_muteTimerHandler) + g_source_remove(m_muteTimerHandler); + m_muteTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateMuteChangeTimeoutCallback), this); } void MediaPlayerPrivateGStreamer::loadingFailed(MediaPlayer::NetworkState error) @@ -1359,7 +1462,12 @@ bool MediaPlayerPrivateGStreamer::hasSingleSecurityOrigin() const bool MediaPlayerPrivateGStreamer::supportsFullscreen() const { +#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) + // See <rdar://problem/7389945> + return false; +#else return true; +#endif } PlatformMedia MediaPlayerPrivateGStreamer::platformMedia() const @@ -1401,9 +1509,13 @@ void MediaPlayerPrivateGStreamer::createGSTPlayBin() g_signal_connect(bus, "message", G_CALLBACK(mediaPlayerPrivateMessageCallback), this); gst_object_unref(bus); + g_object_set(m_playBin, "mute", m_player->muted(), "volume", m_player->volume(), NULL); + g_signal_connect(m_playBin, "notify::volume", G_CALLBACK(mediaPlayerPrivateVolumeChangedCallback), this); g_signal_connect(m_playBin, "notify::source", G_CALLBACK(mediaPlayerPrivateSourceChangedCallback), this); g_signal_connect(m_playBin, "notify::mute", G_CALLBACK(mediaPlayerPrivateMuteChangedCallback), this); + g_signal_connect(m_playBin, "video-tags-changed", G_CALLBACK(mediaPlayerPrivateVideoTagsChangedCallback), this); + g_signal_connect(m_playBin, "audio-tags-changed", G_CALLBACK(mediaPlayerPrivateAudioTagsChangedCallback), this); m_webkitVideoSink = webkit_video_sink_new(); @@ -1437,16 +1549,32 @@ void MediaPlayerPrivateGStreamer::createGSTPlayBin() if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_fpsSink), "video-sink")) { g_object_set(m_fpsSink, "video-sink", m_webkitVideoSink, NULL); gst_bin_add(GST_BIN(m_videoSinkBin), m_fpsSink); +#if GST_CHECK_VERSION(0, 10, 30) + // Faster elements linking, if possible. + gst_element_link_pads_full(queue, "src", m_fpsSink, "sink", GST_PAD_LINK_CHECK_NOTHING); +#else gst_element_link(queue, m_fpsSink); +#endif } else { m_fpsSink = 0; gst_bin_add(GST_BIN(m_videoSinkBin), m_webkitVideoSink); +#if GST_CHECK_VERSION(0, 10, 30) + // Faster elements linking, if possible. + gst_element_link_pads_full(queue, "src", m_webkitVideoSink, "sink", GST_PAD_LINK_CHECK_NOTHING); +#else gst_element_link(queue, m_webkitVideoSink); +#endif LOG_VERBOSE(Media, "Can't display FPS statistics, you need gst-plugins-bad >= 0.10.18"); } } else { gst_bin_add(GST_BIN(m_videoSinkBin), m_webkitVideoSink); +#if GST_CHECK_VERSION(0, 10, 30) + // Faster elements linking, if possible. + gst_element_link_pads_full(queue, "src", identity, "sink", GST_PAD_LINK_CHECK_NOTHING); + gst_element_link_pads_full(identity, "src", m_webkitVideoSink, "sink", GST_PAD_LINK_CHECK_NOTHING); +#else gst_element_link_many(queue, identity, m_webkitVideoSink, NULL); +#endif } // Add a ghostpad to the bin so it can proxy to tee. diff --git a/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h b/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h index 800ca6d..11eb81b 100644 --- a/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h +++ b/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h @@ -43,11 +43,19 @@ class GraphicsContext; class IntSize; class IntRect; class GStreamerGWorld; +class MediaPlayerPrivateGStreamer; gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data); void mediaPlayerPrivateVolumeChangedCallback(GObject* element, GParamSpec* pspec, gpointer data); void mediaPlayerPrivateMuteChangedCallback(GObject* element, GParamSpec* pspec, gpointer data); void mediaPlayerPrivateSourceChangedCallback(GObject* element, GParamSpec* pspec, gpointer data); +void mediaPlayerPrivateVideoTagsChangedCallback(GObject* element, gint, MediaPlayerPrivateGStreamer*); +void mediaPlayerPrivateAudioTagsChangedCallback(GObject* element, gint, MediaPlayerPrivateGStreamer*); +gboolean mediaPlayerPrivateAudioTagsChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player); +gboolean mediaPlayerPrivateVideoTagsChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player); + +gboolean mediaPlayerPrivateVolumeChangeTimeoutCallback(MediaPlayerPrivateGStreamer*); +gboolean mediaPlayerPrivateMuteChangeTimeoutCallback(MediaPlayerPrivateGStreamer*); class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { friend gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data); @@ -58,8 +66,8 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { static void registerMediaEngine(MediaEngineRegistrar); IntSize naturalSize() const; - bool hasVideo() const; - bool hasAudio() const; + bool hasVideo() const { return m_hasVideo; } + bool hasAudio() const { return m_hasAudio; } void load(const String &url); void commitLoad(); @@ -81,13 +89,14 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { void setVolume(float); void volumeChanged(); - void volumeChangedTimerFired(Timer<MediaPlayerPrivateGStreamer>*); + void notifyPlayerOfVolumeChange(); bool supportsMuting() const; void setMuted(bool); void muteChanged(); - void muteChangedTimerFired(Timer<MediaPlayerPrivateGStreamer>*); + void notifyPlayerOfMute(); + bool loadDelayed() const { return m_delayingLoad; } void setPreload(MediaPlayer::Preload); void fillTimerFired(Timer<MediaPlayerPrivateGStreamer>*); @@ -121,6 +130,11 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { GstElement* pipeline() const { return m_playBin; } bool pipelineReset() const { return m_resetPipeline; } + void videoTagsChanged(gint); + void audioTagsChanged(gint); + void notifyPlayerOfVideoTags(); + void notifyPlayerOfAudioTags(); + private: MediaPlayerPrivateGStreamer(MediaPlayer*); ~MediaPlayerPrivateGStreamer(); @@ -133,10 +147,7 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { void cacheDuration(); void updateStates(); - void cancelSeek(); - void endPointTimerFired(Timer<MediaPlayerPrivateGStreamer>*); float maxTimeLoaded() const; - void startEndPointTimerIfNeeded(); void createGSTPlayBin(); bool changePipelineState(GstState state); @@ -176,6 +187,12 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { bool m_delayingLoad; bool m_mediaDurationKnown; RefPtr<GStreamerGWorld> m_gstGWorld; + guint m_volumeTimerHandler; + guint m_muteTimerHandler; + bool m_hasVideo; + bool m_hasAudio; + guint m_audioTagsTimerHandler; + guint m_videoTagsTimerHandler; }; } diff --git a/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp b/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp index 635feff..e10e61f 100644 --- a/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp +++ b/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp @@ -110,6 +110,7 @@ static void webKitWebSrcFinalize(GObject* object); static void webKitWebSrcSetProperty(GObject* object, guint propID, const GValue* value, GParamSpec* pspec); static void webKitWebSrcGetProperty(GObject* object, guint propID, GValue* value, GParamSpec* pspec); static GstStateChangeReturn webKitWebSrcChangeState(GstElement* element, GstStateChange transition); +static gboolean webKitWebSrcQuery(GstPad* pad, GstQuery* query); static void webKitWebSrcNeedDataCb(GstAppSrc* appsrc, guint length, gpointer userData); static void webKitWebSrcEnoughDataCb(GstAppSrc* appsrc, gpointer userData); @@ -221,6 +222,7 @@ static void webkit_web_src_init(WebKitWebSrc* src, padTemplate); gst_element_add_pad(GST_ELEMENT(src), priv->srcpad); + gst_pad_set_query_function(priv->srcpad, webKitWebSrcQuery); priv->appsrc = GST_APP_SRC(gst_element_factory_make("appsrc", 0)); if (!priv->appsrc) { @@ -476,6 +478,36 @@ static GstStateChangeReturn webKitWebSrcChangeState(GstElement* element, GstStat return ret; } +static gboolean webKitWebSrcQuery(GstPad* pad, GstQuery* query) +{ + WebKitWebSrc* src = WEBKIT_WEB_SRC(gst_pad_get_parent(pad)); + gboolean result = FALSE; + + switch (GST_QUERY_TYPE(query)) { + case GST_QUERY_DURATION: + { + GstFormat format; + + gst_query_parse_duration(query, &format, NULL); + + GST_DEBUG_OBJECT(src, "duration query in format %s", gst_format_get_name(format)); + if ((format == GST_FORMAT_BYTES) && (src->priv->size > 0)) { + gst_query_set_duration(query, format, src->priv->size); + result = TRUE; + } + break; + } + default: + break; + } + + if (!result) + result = gst_pad_query_default(pad, query); + + gst_object_unref(src); + return result; +} + // uri handler interface static GstURIType webKitWebSrcUriGetType(void) @@ -541,13 +573,7 @@ static gboolean webKitWebSrcNeedDataMainCb(WebKitWebSrc* src) { WebKitWebSrcPrivate* priv = src->priv; -#if USE(NETWORK_SOUP) - ResourceHandleInternal* d = priv->resourceHandle->getInternal(); - if (d->m_msg) - soup_session_unpause_message(ResourceHandle::defaultSession(), d->m_msg); -#endif - // Ports not using libsoup need to call the unpause/schedule API of their - // underlying network implementation here. + priv->resourceHandle->setDefersLoading(false); GST_OBJECT_LOCK(src); priv->paused = FALSE; @@ -577,12 +603,7 @@ static gboolean webKitWebSrcEnoughDataMainCb(WebKitWebSrc* src) { WebKitWebSrcPrivate* priv = src->priv; -#if USE(NETWORK_SOUP) - ResourceHandleInternal* d = priv->resourceHandle->getInternal(); - soup_session_pause_message(ResourceHandle::defaultSession(), d->m_msg); -#endif - // Ports not using libsoup need to call the pause/unschedule API of their - // underlying network implementation here. + priv->resourceHandle->setDefersLoading(true); GST_OBJECT_LOCK(src); priv->paused = TRUE; diff --git a/WebCore/platform/graphics/gtk/FontGtk.cpp b/WebCore/platform/graphics/gtk/FontGtk.cpp index 54e18c9..eabd913 100644 --- a/WebCore/platform/graphics/gtk/FontGtk.cpp +++ b/WebCore/platform/graphics/gtk/FontGtk.cpp @@ -36,6 +36,7 @@ #include "CairoUtilities.h" #include "ContextShadow.h" #include "GraphicsContext.h" +#include "NotImplemented.h" #include "SimpleFontData.h" #include <cairo.h> #include <gdk/gdk.h> @@ -218,13 +219,13 @@ static void drawGlyphsShadow(GraphicsContext* graphicsContext, cairo_t* context, ContextShadow* shadow = graphicsContext->contextShadow(); ASSERT(shadow); - if (!(graphicsContext->textDrawingMode() & cTextFill) || shadow->m_type == ContextShadow::NoShadow) + if (!(graphicsContext->textDrawingMode() & TextModeFill) || shadow->m_type == ContextShadow::NoShadow) return; FloatPoint totalOffset(point + shadow->m_offset); // Optimize non-blurry shadows, by just drawing text without the ContextShadow. - if (shadow->m_type == ContextShadow::SolidShadow) { + if (!shadow->mustUseContextShadow(context)) { cairo_save(context); cairo_translate(context, totalOffset.x(), totalOffset.y()); @@ -300,7 +301,7 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F pango_cairo_show_layout_line(cr, layoutLine); - if (context->textDrawingMode() & cTextStroke) { + if (context->textDrawingMode() & TextModeStroke) { Color strokeColor = context->strokeColor(); strokeColor.getRGBA(red, green, blue, alpha); cairo_set_source_rgba(cr, red, green, blue, alpha); @@ -319,6 +320,11 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F cairo_restore(cr); } +void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const +{ + notImplemented(); +} + // We should create the layout with our actual context but we can't access it from here. static PangoLayout* getDefaultPangoLayout(const TextRun& run) { diff --git a/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp b/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp index 486a317..cf0470f 100644 --- a/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp +++ b/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp @@ -66,9 +66,8 @@ String ImageBuffer::toDataURL(const String& mimeType, const double* quality) con Vector<char> out; base64Encode(reinterpret_cast<const char*>(buffer.get()), bufferSize, out); - out.append('\0'); - return makeString("data:", mimeType, ";base64,", out.data()); + return makeString("data:", mimeType, ";base64,", out); } } diff --git a/WebCore/platform/graphics/haiku/FontHaiku.cpp b/WebCore/platform/graphics/haiku/FontHaiku.cpp index a991bfc..819fecb 100644 --- a/WebCore/platform/graphics/haiku/FontHaiku.cpp +++ b/WebCore/platform/graphics/haiku/FontHaiku.cpp @@ -93,6 +93,10 @@ void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const Float notImplemented(); } +void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const +{ + notImplemented(); +} float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { diff --git a/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp b/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp index 05012e8..38c1fb7 100644 --- a/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp +++ b/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp @@ -62,16 +62,14 @@ GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate() { } -GraphicsContext::GraphicsContext(PlatformGraphicsContext* context) - : m_common(createGraphicsContextPrivate()) - , m_data(new GraphicsContextPlatformPrivate(context)) +void GraphicsContext::platformInit(PlatformGraphicsContext* context) { + m_data = new GraphicsContextPlatformPrivate(context); setPaintingDisabled(!context); } -GraphicsContext::~GraphicsContext() +void GraphicsContext::platformDestroy() { - destroyGraphicsContextPrivate(m_common); delete m_data; } @@ -132,7 +130,7 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp m_data->m_view->StrokeArc(rect, startAngle, angleSpan, getHaikuStrokeStyle()); } -void GraphicsContext::strokePath() +void GraphicsContext::strokePath(const Path&) { notImplemented(); } @@ -191,17 +189,7 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef // FillRect and FillArc calls are needed. } -void GraphicsContext::fillPath() -{ - notImplemented(); -} - -void GraphicsContext::beginPath() -{ - notImplemented(); -} - -void GraphicsContext::addPath(const Path& path) +void GraphicsContext::fillPath(const Path&) { notImplemented(); } @@ -355,7 +343,7 @@ void GraphicsContext::setAlpha(float opacity) notImplemented(); } -void GraphicsContext::setCompositeOperation(CompositeOperator op) +void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op) { if (paintingDisabled()) return; @@ -370,7 +358,7 @@ void GraphicsContext::setCompositeOperation(CompositeOperator op) mode = B_OP_OVER; break; default: - printf("GraphicsContext::setCompositeOperation: Unsupported composite operation %s\n", + printf("GraphicsContext::setPlatformCompositeOperation: Unsupported composite operation %s\n", compositeOperatorName(op).utf8().data()); } m_data->m_view->SetDrawingMode(mode); diff --git a/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp b/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp index d1b06f3..cc12de7 100644 --- a/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp +++ b/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp @@ -66,7 +66,7 @@ ImageBufferData::~ImageBufferData() m_bitmap.Unlock(); } -ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, bool& success) +ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, RenderingMode, bool& success) : m_data(size) , m_size(size) { @@ -368,7 +368,7 @@ String ImageBuffer::toDataURL(const String& mimeType, const double*) const base64Encode(reinterpret_cast<const char*>(translatedStream.Buffer()), translatedStream.BufferLength(), encodedBuffer); - return makeString("data:", mimeType, ";base64,", encodedBuffer.data()); + return makeString("data:", mimeType, ";base64,", encodedBuffer); } } // namespace WebCore diff --git a/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp b/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp index a960972..b1e7082 100644 --- a/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp +++ b/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp @@ -66,15 +66,32 @@ void SimpleFontData::platformDestroy() { } +SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const +{ + FontDescription desc = FontDescription(fontDescription); + desc.setSpecifiedSize(scaleFactor * fontDescription.computedSize()); + FontPlatformData fontPlatformData(desc, desc.family().family()); + return new SimpleFontData(fontPlatformData, isCustomFont(), false); +} + SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const { - if (!m_smallCapsFontData) { - FontDescription desc = FontDescription(fontDescription); - desc.setSpecifiedSize(0.70f * fontDescription.computedSize()); - FontPlatformData fontPlatformData(desc, desc.family().family()); - m_smallCapsFontData = new SimpleFontData(fontPlatformData, isCustomFont(), false); - } - return m_smallCapsFontData; + if (!m_derivedFontData) + m_derivedFontData = DerivedFontData::create(isCustomFont()); + if (!m_derivedFontData->smallCaps) + m_derivedFontData->smallCaps = scaledFontData(fontDescription, .7); + + return m_derivedFontData->smallCaps.get(); +} + +SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const +{ + if (!m_derivedFontData) + m_derivedFontData = DerivedFontData::create(isCustomFont()); + if (!m_derivedFontData->emphasisMark) + m_derivedFontData->emphasisMark = scaledFontData(fontDescription, .5); + + return m_derivedFontData->emphasisMark.get(); } bool SimpleFontData::containsCharacters(const UChar* characters, int length) const diff --git a/WebCore/platform/graphics/mac/ComplexTextController.cpp b/WebCore/platform/graphics/mac/ComplexTextController.cpp index e6a7bef..206fd5f 100644 --- a/WebCore/platform/graphics/mac/ComplexTextController.cpp +++ b/WebCore/platform/graphics/mac/ComplexTextController.cpp @@ -56,10 +56,11 @@ static inline CGFloat ceilCGFloat(CGFloat f) return static_cast<CGFloat>(ceil(f)); } -ComplexTextController::ComplexTextController(const Font* font, const TextRun& run, bool mayUseNaturalWritingDirection, HashSet<const SimpleFontData*>* fallbackFonts) +ComplexTextController::ComplexTextController(const Font* font, const TextRun& run, bool mayUseNaturalWritingDirection, HashSet<const SimpleFontData*>* fallbackFonts, bool forTextEmphasis) : m_font(*font) , m_run(run) , m_mayUseNaturalWritingDirection(mayUseNaturalWritingDirection) + , m_forTextEmphasis(forTextEmphasis) , m_currentCharacter(0) , m_end(run.length()) , m_totalWidth(0) @@ -240,7 +241,7 @@ void ComplexTextController::collectComplexTextRuns() nextGlyphData = m_font.glyphDataForCharacter(U16_GET_SUPPLEMENTARY(curr[-1], curr[0]), false); } } else - nextGlyphData = m_font.glyphDataForCharacter(*curr, false, forceSmallCaps); + nextGlyphData = m_font.glyphDataForCharacter(*curr, false, forceSmallCaps ? SmallCapsVariant : AutoVariant); if (!isSurrogate && m_font.isSmallCaps()) { nextIsSmallCaps = forceSmallCaps || (newC = u_toupper(c)) != c; @@ -462,7 +463,7 @@ void ComplexTextController::adjustGlyphsAndAdvances() if (ch == '\t' && m_run.allowTabs()) { float tabWidth = m_font.tabWidth(*fontData); advance.width = tabWidth - fmodf(m_run.xPos() + m_totalWidth + widthSinceLastRounding, tabWidth); - } else if (ch == zeroWidthSpace || Font::treatAsZeroWidthSpace(ch) && !treatAsSpace) { + } else if (ch == zeroWidthSpace || (Font::treatAsZeroWidthSpace(ch) && !treatAsSpace)) { advance.width = 0; glyph = fontData->spaceGlyph(); } @@ -518,7 +519,7 @@ void ComplexTextController::adjustGlyphsAndAdvances() // Check to see if the next character is a "rounding hack character", if so, adjust the // width so that the total run width will be on an integer boundary. - if (m_run.applyWordRounding() && !lastGlyph && Font::isRoundingHackCharacter(nextCh) || m_run.applyRunRounding() && lastGlyph) { + if ((m_run.applyWordRounding() && !lastGlyph && Font::isRoundingHackCharacter(nextCh)) || (m_run.applyRunRounding() && lastGlyph)) { CGFloat totalWidth = widthSinceLastRounding + advance.width; widthSinceLastRounding = ceilCGFloat(totalWidth); CGFloat extraWidth = widthSinceLastRounding - totalWidth; @@ -536,6 +537,10 @@ void ComplexTextController::adjustGlyphsAndAdvances() } else widthSinceLastRounding += advance.width; + // FIXME: Combining marks should receive a text emphasis mark if they are combine with a space. + if (m_forTextEmphasis && (!Font::canReceiveTextEmphasis(ch) || (U_GET_GC_MASK(ch) & U_GC_M_MASK))) + glyph = 0; + advance.height *= -1; m_adjustedAdvances.append(advance); m_adjustedGlyphs.append(glyph); diff --git a/WebCore/platform/graphics/mac/ComplexTextController.h b/WebCore/platform/graphics/mac/ComplexTextController.h index 85407c7..9cf80a6 100644 --- a/WebCore/platform/graphics/mac/ComplexTextController.h +++ b/WebCore/platform/graphics/mac/ComplexTextController.h @@ -47,7 +47,7 @@ class TextRun; // OS Versions >= 10.6, ATSUI is used otherwise. class ComplexTextController { public: - ComplexTextController(const Font*, const TextRun&, bool mayUseNaturalWritingDirection = false, HashSet<const SimpleFontData*>* fallbackFonts = 0); + ComplexTextController(const Font*, const TextRun&, bool mayUseNaturalWritingDirection = false, HashSet<const SimpleFontData*>* fallbackFonts = 0, bool forTextEmphasis = false); // Advance and emit glyphs up to the specified character. void advance(unsigned to, GlyphBuffer* = 0); @@ -156,6 +156,7 @@ private: const Font& m_font; const TextRun& m_run; bool m_mayUseNaturalWritingDirection; + bool m_forTextEmphasis; Vector<UChar, 256> m_smallCapsBuffer; diff --git a/WebCore/platform/graphics/mac/FontComplexTextMac.cpp b/WebCore/platform/graphics/mac/FontComplexTextMac.cpp index 05eae03..ca006d9 100644 --- a/WebCore/platform/graphics/mac/FontComplexTextMac.cpp +++ b/WebCore/platform/graphics/mac/FontComplexTextMac.cpp @@ -55,34 +55,55 @@ FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h); } -void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, - int from, int to) const +float Font::getGlyphsAndAdvancesForComplexText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const { - // This glyph buffer holds our glyphs + advances + font data for each glyph. - GlyphBuffer glyphBuffer; + float initialAdvance; - float startX = point.x(); - ComplexTextController controller(this, run); + ComplexTextController controller(this, run, false, 0, forTextEmphasis); controller.advance(from); float beforeWidth = controller.runWidthSoFar(); controller.advance(to, &glyphBuffer); - - // We couldn't generate any glyphs for the run. Give up. + if (glyphBuffer.isEmpty()) - return; - + return 0; + float afterWidth = controller.runWidthSoFar(); if (run.rtl()) { - startX += controller.totalWidth() + controller.finalRoundingWidth() - afterWidth; + initialAdvance = controller.totalWidth() + controller.finalRoundingWidth() - afterWidth; for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end) glyphBuffer.swap(i, end); } else - startX += beforeWidth; + initialAdvance = beforeWidth; + + return initialAdvance; +} + +void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const +{ + // This glyph buffer holds our glyphs + advances + font data for each glyph. + GlyphBuffer glyphBuffer; + + float startX = point.x() + getGlyphsAndAdvancesForComplexText(run, from, to, glyphBuffer); + + // We couldn't generate any glyphs for the run. Give up. + if (glyphBuffer.isEmpty()) + return; // Draw the glyph buffer now at the starting point returned in startX. FloatPoint startPoint(startX, point.y()); - drawGlyphBuffer(context, glyphBuffer, run, startPoint); + drawGlyphBuffer(context, glyphBuffer, startPoint); +} + +void Font::drawEmphasisMarksForComplexText(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const +{ + GlyphBuffer glyphBuffer; + float initialAdvance = getGlyphsAndAdvancesForComplexText(run, from, to, glyphBuffer, ForTextEmphasis); + + if (glyphBuffer.isEmpty()) + return; + + drawEmphasisMarks(context, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y())); } float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const diff --git a/WebCore/platform/graphics/mac/FontMac.mm b/WebCore/platform/graphics/mac/FontMac.mm index 8dc741b..8519667 100644 --- a/WebCore/platform/graphics/mac/FontMac.mm +++ b/WebCore/platform/graphics/mac/FontMac.mm @@ -91,22 +91,27 @@ static void showGlyphsWithAdvances(const SimpleFontData* font, CGContextRef cont void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { CGContextRef cgContext = context->platformContext(); - bool newShouldUseFontSmoothing = shouldUseSmoothing(); + bool shouldSmoothFonts = true; + bool changeFontSmoothing = false; + switch(fontDescription().fontSmoothing()) { case Antialiased: { context->setShouldAntialias(true); - newShouldUseFontSmoothing = false; + shouldSmoothFonts = false; + changeFontSmoothing = true; break; } case SubpixelAntialiased: { context->setShouldAntialias(true); - newShouldUseFontSmoothing = true; + shouldSmoothFonts = true; + changeFontSmoothing = true; break; } case NoSmoothing: { context->setShouldAntialias(false); - newShouldUseFontSmoothing = false; + shouldSmoothFonts = false; + changeFontSmoothing = true; break; } case AutoSmoothing: { @@ -116,11 +121,18 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons default: ASSERT_NOT_REACHED(); } - - bool originalShouldUseFontSmoothing = wkCGContextGetShouldSmoothFonts(cgContext); - if (originalShouldUseFontSmoothing != newShouldUseFontSmoothing) - CGContextSetShouldSmoothFonts(cgContext, newShouldUseFontSmoothing); + if (!shouldUseSmoothing()) { + shouldSmoothFonts = false; + changeFontSmoothing = true; + } + + bool originalShouldUseFontSmoothing = false; + if (changeFontSmoothing) { + originalShouldUseFontSmoothing = wkCGContextGetShouldSmoothFonts(cgContext); + CGContextSetShouldSmoothFonts(cgContext, shouldSmoothFonts); + } + const FontPlatformData& platformData = font->platformData(); NSFont* drawFont; if (!isPrinterFont()) { @@ -157,20 +169,24 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons FloatSize shadowOffset; float shadowBlur; Color shadowColor; + ColorSpace shadowColorSpace; ColorSpace fillColorSpace = context->fillColorSpace(); - context->getShadow(shadowOffset, shadowBlur, shadowColor); + context->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace); - bool hasSimpleShadow = context->textDrawingMode() == cTextFill && shadowColor.isValid() && !shadowBlur && !platformData.isColorBitmapFont(); + bool hasSimpleShadow = context->textDrawingMode() == TextModeFill && shadowColor.isValid() && !shadowBlur && !platformData.isColorBitmapFont() && (!context->shadowsIgnoreTransforms() || context->getCTM().isIdentityOrTranslationOrFlipped()); if (hasSimpleShadow) { // Paint simple shadows ourselves instead of relying on CG shadows, to avoid losing subpixel antialiasing. context->clearShadow(); Color fillColor = context->fillColor(); Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255); - context->setFillColor(shadowFillColor, fillColorSpace); - CGContextSetTextPosition(cgContext, point.x() + shadowOffset.width(), point.y() + shadowOffset.height()); + context->setFillColor(shadowFillColor, shadowColorSpace); + 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, point.x() + shadowOffset.width() + font->syntheticBoldOffset(), point.y() + shadowOffset.height()); + CGContextSetTextPosition(cgContext, shadowTextX + font->syntheticBoldOffset(), shadowTextY); showGlyphsWithAdvances(font, cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); } context->setFillColor(fillColor, fillColorSpace); @@ -184,9 +200,9 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons } if (hasSimpleShadow) - context->setShadow(shadowOffset, shadowBlur, shadowColor, fillColorSpace); + context->setShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace); - if (originalShouldUseFontSmoothing != newShouldUseFontSmoothing) + if (changeFontSmoothing) CGContextSetShouldSmoothFonts(cgContext, originalShouldUseFontSmoothing); } diff --git a/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp b/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp index 9524cd2..5388c24 100644 --- a/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp +++ b/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp @@ -28,6 +28,7 @@ #include "config.h" #include "GlyphPageTreeNode.h" +#include "Font.h" #include "SimpleFontData.h" #include "WebCoreSystemInterface.h" @@ -35,12 +36,27 @@ namespace WebCore { +#ifndef BUILDING_ON_TIGER +static bool shouldUseCoreText(UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) +{ + if (fontData->orientation() == Vertical && !fontData->isBrokenIdeographFont()) { + // Ideographs don't have a vertical variant. + for (unsigned i = 0; i < bufferLength; ++i) { + if (!Font::isCJKIdeograph(buffer[i])) + return true; + } + } + + return false; +} +#endif + bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) { bool haveGlyphs = false; #ifndef BUILDING_ON_TIGER - if (fontData->orientation() == Horizontal || fontData->isBrokenIdeographFont()) { + if (!shouldUseCoreText(buffer, bufferLength, fontData)) { Vector<CGGlyph, 512> glyphs(bufferLength); wkGetGlyphsForCharacters(fontData->platformData().cgFont(), buffer, glyphs.data(), bufferLength); for (unsigned i = 0; i < length; ++i) { diff --git a/WebCore/platform/graphics/mac/GraphicsContextMac.mm b/WebCore/platform/graphics/mac/GraphicsContextMac.mm index c149d70..6a4fa03 100644 --- a/WebCore/platform/graphics/mac/GraphicsContextMac.mm +++ b/WebCore/platform/graphics/mac/GraphicsContextMac.mm @@ -87,8 +87,8 @@ void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int drawFocusRingToContext(platformContext(), focusRingPath.get(), colorRef, radius); } -#ifdef BUILDING_ON_TIGER // Post-Tiger's setCompositeOperation() is defined in GraphicsContextCG.cpp. -void GraphicsContext::setCompositeOperation(CompositeOperator op) +#ifdef BUILDING_ON_TIGER // Post-Tiger's setPlatformCompositeOperation() is defined in GraphicsContextCG.cpp. +void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op) { if (paintingDisabled()) return; diff --git a/WebCore/platform/graphics/mac/GraphicsLayerMac.mm b/WebCore/platform/graphics/mac/GraphicsLayerMac.mm deleted file mode 100644 index f9b16a0..0000000 --- a/WebCore/platform/graphics/mac/GraphicsLayerMac.mm +++ /dev/null @@ -1,2514 +0,0 @@ -/* - * Copyright (C) 2009 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import "config.h" - -#if USE(ACCELERATED_COMPOSITING) - -#import "GraphicsLayerMac.h" - -#import "Animation.h" -#import "BlockExceptions.h" -#import "FloatConversion.h" -#import "FloatRect.h" -#import "Image.h" -#import "PlatformString.h" -#import <QuartzCore/QuartzCore.h> -#import "RotateTransformOperation.h" -#import "ScaleTransformOperation.h" -#import "SystemTime.h" -#import "TranslateTransformOperation.h" -#import "WebLayer.h" -#import "WebTiledLayer.h" -#import <limits.h> -#import <objc/objc-auto.h> -#import <wtf/CurrentTime.h> -#import <wtf/UnusedParam.h> -#import <wtf/RetainPtr.h> -#import <wtf/text/StringConcatenate.h> - -using namespace std; - -#define HAVE_MODERN_QUARTZCORE (!defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)) - -namespace WebCore { - -static NSString * const WebKitAnimationBeginTimeSetKey = @"WebKitAnimationBeginTimeSet"; - -// The threshold width or height above which a tiled layer will be used. This should be -// large enough to avoid tiled layers for most GraphicsLayers, but less than the OpenGL -// texture size limit on all supported hardware. -static const int cMaxPixelDimension = 2000; - -// The width and height of a single tile in a tiled layer. Should be large enough to -// avoid lots of small tiles (and therefore lots of drawing callbacks), but small enough -// to keep the overall tile cost low. -static const int cTiledLayerTileSize = 512; - -// If we send a duration of 0 to CA, then it will use the default duration -// of 250ms. So send a very small value instead. -static const float cAnimationAlmostZeroDuration = 1e-3f; - -// CACurrentMediaTime() is a time since boot. These methods convert between that and -// WebCore time, which is system time (UTC). -static CFTimeInterval currentTimeToMediaTime(double t) -{ - return CACurrentMediaTime() + t - WTF::currentTime(); -} - -static double mediaTimeToCurrentTime(CFTimeInterval t) -{ - return WTF::currentTime() + t - CACurrentMediaTime(); -} - -} // namespace WebCore - -@interface CALayer(Private) -- (void)setContentsChanged; -@end - -@interface WebAnimationDelegate : NSObject { - WebCore::GraphicsLayerMac* m_graphicsLayer; -} - -- (void)animationDidStart:(CAAnimation *)anim; -- (WebCore::GraphicsLayerMac*)graphicsLayer; -- (void)setLayer:(WebCore::GraphicsLayerMac*)graphicsLayer; - -@end - -@implementation WebAnimationDelegate - -- (void)animationDidStart:(CAAnimation *)animation -{ - if (m_graphicsLayer) - m_graphicsLayer->animationDidStart(animation); -} - -- (WebCore::GraphicsLayerMac*)graphicsLayer -{ - return m_graphicsLayer; -} - -- (void)setLayer:(WebCore::GraphicsLayerMac*)graphicsLayer -{ - m_graphicsLayer = graphicsLayer; -} - -@end - -namespace WebCore { - -static inline void copyTransform(CATransform3D& toT3D, const TransformationMatrix& t) -{ - toT3D.m11 = narrowPrecisionToFloat(t.m11()); - toT3D.m12 = narrowPrecisionToFloat(t.m12()); - toT3D.m13 = narrowPrecisionToFloat(t.m13()); - toT3D.m14 = narrowPrecisionToFloat(t.m14()); - toT3D.m21 = narrowPrecisionToFloat(t.m21()); - toT3D.m22 = narrowPrecisionToFloat(t.m22()); - toT3D.m23 = narrowPrecisionToFloat(t.m23()); - toT3D.m24 = narrowPrecisionToFloat(t.m24()); - toT3D.m31 = narrowPrecisionToFloat(t.m31()); - toT3D.m32 = narrowPrecisionToFloat(t.m32()); - toT3D.m33 = narrowPrecisionToFloat(t.m33()); - toT3D.m34 = narrowPrecisionToFloat(t.m34()); - toT3D.m41 = narrowPrecisionToFloat(t.m41()); - toT3D.m42 = narrowPrecisionToFloat(t.m42()); - toT3D.m43 = narrowPrecisionToFloat(t.m43()); - toT3D.m44 = narrowPrecisionToFloat(t.m44()); -} - -static NSValue* getTransformFunctionValue(const TransformOperation* transformOp, TransformOperation::OperationType transformType, const IntSize& size) -{ - switch (transformType) { - case TransformOperation::ROTATE: - case TransformOperation::ROTATE_X: - case TransformOperation::ROTATE_Y: - return [NSNumber numberWithDouble:transformOp ? deg2rad(static_cast<const RotateTransformOperation*>(transformOp)->angle()) : 0]; - case TransformOperation::SCALE_X: - return [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->x() : 1]; - case TransformOperation::SCALE_Y: - return [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->y() : 1]; - case TransformOperation::SCALE_Z: - return [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->z() : 1]; - case TransformOperation::TRANSLATE_X: - return [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->x(size) : 0]; - case TransformOperation::TRANSLATE_Y: - return [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->y(size) : 0]; - case TransformOperation::TRANSLATE_Z: - return [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->z(size) : 0]; - case TransformOperation::SCALE: - case TransformOperation::SCALE_3D: - return [NSArray arrayWithObjects: - [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->x() : 1], - [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->y() : 1], - [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->z() : 1], - nil]; - case TransformOperation::TRANSLATE: - case TransformOperation::TRANSLATE_3D: - return [NSArray arrayWithObjects: - [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->x(size) : 0], - [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->y(size) : 0], - [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->z(size) : 0], - nil]; - case TransformOperation::SKEW_X: - case TransformOperation::SKEW_Y: - case TransformOperation::SKEW: - case TransformOperation::MATRIX: - case TransformOperation::ROTATE_3D: - case TransformOperation::MATRIX_3D: - case TransformOperation::PERSPECTIVE: - case TransformOperation::IDENTITY: - case TransformOperation::NONE: { - TransformationMatrix transform; - if (transformOp) - transformOp->apply(transform, size); - CATransform3D caTransform; - copyTransform(caTransform, transform); - return [NSValue valueWithCATransform3D:caTransform]; - } - } - - return 0; -} - -#if HAVE_MODERN_QUARTZCORE -static NSString *getValueFunctionNameForTransformOperation(TransformOperation::OperationType transformType) -{ - // Use literal strings to avoid link-time dependency on those symbols. - switch (transformType) { - case TransformOperation::ROTATE_X: - return @"rotateX"; // kCAValueFunctionRotateX; - case TransformOperation::ROTATE_Y: - return @"rotateY"; // kCAValueFunctionRotateY; - case TransformOperation::ROTATE: - return @"rotateZ"; // kCAValueFunctionRotateZ; - case TransformOperation::SCALE_X: - return @"scaleX"; // kCAValueFunctionScaleX; - case TransformOperation::SCALE_Y: - return @"scaleY"; // kCAValueFunctionScaleY; - case TransformOperation::SCALE_Z: - return @"scaleZ"; // kCAValueFunctionScaleZ; - case TransformOperation::TRANSLATE_X: - return @"translateX"; // kCAValueFunctionTranslateX; - case TransformOperation::TRANSLATE_Y: - return @"translateY"; // kCAValueFunctionTranslateY; - case TransformOperation::TRANSLATE_Z: - return @"translateZ"; // kCAValueFunctionTranslateZ; - case TransformOperation::SCALE: - case TransformOperation::SCALE_3D: - return @"scale"; // kCAValueFunctionScale; - case TransformOperation::TRANSLATE: - case TransformOperation::TRANSLATE_3D: - return @"translate"; // kCAValueFunctionTranslate; - default: - return nil; - } -} -#endif - -static String propertyIdToString(AnimatedPropertyID property) -{ - switch (property) { - case AnimatedPropertyWebkitTransform: - return "transform"; - case AnimatedPropertyOpacity: - return "opacity"; - case AnimatedPropertyBackgroundColor: - return "backgroundColor"; - case AnimatedPropertyInvalid: - ASSERT_NOT_REACHED(); - } - ASSERT_NOT_REACHED(); - return ""; -} - -static String animationIdentifier(const String& animationName, AnimatedPropertyID property, int index) -{ - return makeString(animationName, '_', String::number(property), '_', String::number(index)); -} - -static CAMediaTimingFunction* getCAMediaTimingFunction(const TimingFunction* timingFunction) -{ - // By this point, timing functions can only be linear or cubic, not steps. - ASSERT(!timingFunction->isStepsTimingFunction()); - if (timingFunction->isCubicBezierTimingFunction()) { - const CubicBezierTimingFunction* ctf = static_cast<const CubicBezierTimingFunction*>(timingFunction); - return [CAMediaTimingFunction functionWithControlPoints:static_cast<float>(ctf->x1()) :static_cast<float>(ctf->y1()) - :static_cast<float>(ctf->x2()) :static_cast<float>(ctf->y2())]; - } else - return [CAMediaTimingFunction functionWithName:@"linear"]; -} - -static void setLayerBorderColor(PlatformLayer* layer, const Color& color) -{ - [layer setBorderColor:cachedCGColor(color, ColorSpaceDeviceRGB)]; -} - -static void clearBorderColor(PlatformLayer* layer) -{ - [layer setBorderColor:nil]; -} - -static void setLayerBackgroundColor(PlatformLayer* layer, const Color& color) -{ - [layer setBackgroundColor:cachedCGColor(color, ColorSpaceDeviceRGB)]; -} - -static void clearLayerBackgroundColor(PlatformLayer* layer) -{ - [layer setBackgroundColor:0]; -} - -static void safeSetSublayers(CALayer* layer, NSArray* sublayers) -{ - // Workaround for <rdar://problem/7390716>: -[CALayer setSublayers:] crashes if sublayers is an empty array, or nil, under GC. - if (objc_collectingEnabled() && ![sublayers count]) { - while ([[layer sublayers] count]) - [[[layer sublayers] objectAtIndex:0] removeFromSuperlayer]; - return; - } - - [layer setSublayers:sublayers]; -} - -static bool caValueFunctionSupported() -{ - static bool sHaveValueFunction = [CAPropertyAnimation instancesRespondToSelector:@selector(setValueFunction:)]; - return sHaveValueFunction; -} - -static bool forceSoftwareAnimation() -{ - static bool forceSoftwareAnimation = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreForceSoftwareAnimation"]; - return forceSoftwareAnimation; -} - -static NSDictionary* nullActionsDictionary() -{ - NSNull* nullValue = [NSNull null]; - NSDictionary* actions = [NSDictionary dictionaryWithObjectsAndKeys: - nullValue, @"anchorPoint", - nullValue, @"bounds", - nullValue, @"contents", - nullValue, @"contentsRect", - nullValue, @"opacity", - nullValue, @"position", - nullValue, @"shadowColor", - nullValue, @"sublayerTransform", - nullValue, @"sublayers", - nullValue, @"transform", - nullValue, @"zPosition", - nil]; - return actions; -} - -static bool animationHasStepsTimingFunction(const KeyframeValueList& valueList, const Animation* anim) -{ - if (anim->timingFunction()->isStepsTimingFunction()) - return true; - - for (unsigned i = 0; i < valueList.size(); ++i) { - const TimingFunction* timingFunction = valueList.at(i)->timingFunction(); - if (timingFunction && timingFunction->isStepsTimingFunction()) - return true; - } - - return false; -} - -PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client) -{ - return new GraphicsLayerMac(client); -} - -GraphicsLayerMac::GraphicsLayerMac(GraphicsLayerClient* client) - : GraphicsLayer(client) - , m_contentsLayerPurpose(NoContentsLayer) - , m_contentsLayerHasBackgroundColor(false) - , m_uncommittedChanges(NoChange) -{ - BEGIN_BLOCK_OBJC_EXCEPTIONS - m_layer.adoptNS([[WebLayer alloc] init]); - [m_layer.get() setLayerOwner:this]; - -#if !HAVE_MODERN_QUARTZCORE - setContentsOrientation(defaultContentsOrientation()); -#endif - - updateDebugIndicators(); - - m_animationDelegate.adoptNS([[WebAnimationDelegate alloc] init]); - [m_animationDelegate.get() setLayer:this]; - - END_BLOCK_OBJC_EXCEPTIONS -} - -GraphicsLayerMac::~GraphicsLayerMac() -{ - // We release our references to the CALayers here, but do not actively unparent them, - // since that will cause a commit and break our batched commit model. The layers will - // get released when the rootmost modified GraphicsLayerMac rebuilds its child layers. - - BEGIN_BLOCK_OBJC_EXCEPTIONS - - // Clean up the WK layer. - if (m_layer) { - WebLayer* layer = m_layer.get(); - [layer setLayerOwner:nil]; - } - - if (m_contentsLayer) { - if ([m_contentsLayer.get() respondsToSelector:@selector(setLayerOwner:)]) - [(id)m_contentsLayer.get() setLayerOwner:nil]; - } - - // animationDidStart: can fire after this, so we need to clear out the layer on the delegate. - [m_animationDelegate.get() setLayer:0]; - - // Release the clone layers inside the exception-handling block. - removeCloneLayers(); - - END_BLOCK_OBJC_EXCEPTIONS -} - -void GraphicsLayerMac::setName(const String& name) -{ - String longName = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + name; - GraphicsLayer::setName(longName); - noteLayerPropertyChanged(NameChanged); -} - -NativeLayer GraphicsLayerMac::nativeLayer() const -{ - return m_layer.get(); -} - -bool GraphicsLayerMac::setChildren(const Vector<GraphicsLayer*>& children) -{ - bool childrenChanged = GraphicsLayer::setChildren(children); - if (childrenChanged) - noteSublayersChanged(); - - return childrenChanged; -} - -void GraphicsLayerMac::addChild(GraphicsLayer* childLayer) -{ - GraphicsLayer::addChild(childLayer); - noteSublayersChanged(); -} - -void GraphicsLayerMac::addChildAtIndex(GraphicsLayer* childLayer, int index) -{ - GraphicsLayer::addChildAtIndex(childLayer, index); - noteSublayersChanged(); -} - -void GraphicsLayerMac::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling) -{ - GraphicsLayer::addChildBelow(childLayer, sibling); - noteSublayersChanged(); -} - -void GraphicsLayerMac::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling) -{ - GraphicsLayer::addChildAbove(childLayer, sibling); - noteSublayersChanged(); -} - -bool GraphicsLayerMac::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild) -{ - if (GraphicsLayer::replaceChild(oldChild, newChild)) { - noteSublayersChanged(); - return true; - } - return false; -} - -void GraphicsLayerMac::removeFromParent() -{ - if (m_parent) - static_cast<GraphicsLayerMac*>(m_parent)->noteSublayersChanged(); - GraphicsLayer::removeFromParent(); -} - -void GraphicsLayerMac::setMaskLayer(GraphicsLayer* layer) -{ - if (layer == m_maskLayer) - return; - - GraphicsLayer::setMaskLayer(layer); - noteLayerPropertyChanged(MaskLayerChanged); - - propagateLayerChangeToReplicas(); - - if (m_replicatedLayer) - static_cast<GraphicsLayerMac*>(m_replicatedLayer)->propagateLayerChangeToReplicas(); -} - -void GraphicsLayerMac::setReplicatedLayer(GraphicsLayer* layer) -{ - if (layer == m_replicatedLayer) - return; - - GraphicsLayer::setReplicatedLayer(layer); - noteLayerPropertyChanged(ReplicatedLayerChanged); -} - -void GraphicsLayerMac::setReplicatedByLayer(GraphicsLayer* layer) -{ - if (layer == m_replicaLayer) - return; - - GraphicsLayer::setReplicatedByLayer(layer); - noteSublayersChanged(); - noteLayerPropertyChanged(ReplicatedLayerChanged); -} - -void GraphicsLayerMac::setPosition(const FloatPoint& point) -{ - if (point == m_position) - return; - - GraphicsLayer::setPosition(point); - noteLayerPropertyChanged(PositionChanged); -} - -void GraphicsLayerMac::setAnchorPoint(const FloatPoint3D& point) -{ - if (point == m_anchorPoint) - return; - - GraphicsLayer::setAnchorPoint(point); - noteLayerPropertyChanged(AnchorPointChanged); -} - -void GraphicsLayerMac::setSize(const FloatSize& size) -{ - if (size == m_size) - return; - - GraphicsLayer::setSize(size); - noteLayerPropertyChanged(SizeChanged); -} - -void GraphicsLayerMac::setTransform(const TransformationMatrix& t) -{ - if (t == m_transform) - return; - - GraphicsLayer::setTransform(t); - noteLayerPropertyChanged(TransformChanged); -} - -void GraphicsLayerMac::setChildrenTransform(const TransformationMatrix& t) -{ - if (t == m_childrenTransform) - return; - - GraphicsLayer::setChildrenTransform(t); - noteLayerPropertyChanged(ChildrenTransformChanged); -} - -void GraphicsLayerMac::moveOrCopyLayerAnimation(MoveOrCopy operation, const String& animationIdentifier, CALayer *fromLayer, CALayer *toLayer) -{ - NSString *animationID = animationIdentifier; - CAAnimation *anim = [fromLayer animationForKey:animationID]; - if (!anim) - return; - - switch (operation) { - case Move: - [anim retain]; - [fromLayer removeAnimationForKey:animationID]; - [toLayer addAnimation:anim forKey:animationID]; - [anim release]; - break; - - case Copy: - [toLayer addAnimation:anim forKey:animationID]; - break; - } -} - -void GraphicsLayerMac::moveOrCopyAnimationsForProperty(MoveOrCopy operation, AnimatedPropertyID property, CALayer *fromLayer, CALayer *toLayer) -{ - // Look for running animations affecting this property. - AnimationsMap::const_iterator end = m_runningAnimations.end(); - for (AnimationsMap::const_iterator it = m_runningAnimations.begin(); it != end; ++it) { - const Vector<LayerPropertyAnimation>& propertyAnimations = it->second; - size_t numAnimations = propertyAnimations.size(); - for (size_t i = 0; i < numAnimations; ++i) { - const LayerPropertyAnimation& currAnimation = propertyAnimations[i]; - if (currAnimation.m_property == property) - moveOrCopyLayerAnimation(operation, animationIdentifier(currAnimation.m_name, currAnimation.m_property, currAnimation.m_index), fromLayer, toLayer); - } - } -} - -void GraphicsLayerMac::setPreserves3D(bool preserves3D) -{ - if (preserves3D == m_preserves3D) - return; - - GraphicsLayer::setPreserves3D(preserves3D); - noteLayerPropertyChanged(Preserves3DChanged); -} - -void GraphicsLayerMac::setMasksToBounds(bool masksToBounds) -{ - if (masksToBounds == m_masksToBounds) - return; - - GraphicsLayer::setMasksToBounds(masksToBounds); - noteLayerPropertyChanged(MasksToBoundsChanged); -} - -void GraphicsLayerMac::setDrawsContent(bool drawsContent) -{ - if (drawsContent == m_drawsContent) - return; - - GraphicsLayer::setDrawsContent(drawsContent); - noteLayerPropertyChanged(DrawsContentChanged); -} - -void GraphicsLayerMac::setBackgroundColor(const Color& color) -{ - if (m_backgroundColorSet && m_backgroundColor == color) - return; - - GraphicsLayer::setBackgroundColor(color); - - m_contentsLayerHasBackgroundColor = true; - noteLayerPropertyChanged(BackgroundColorChanged); -} - -void GraphicsLayerMac::clearBackgroundColor() -{ - if (!m_backgroundColorSet) - return; - - GraphicsLayer::clearBackgroundColor(); - m_contentsLayerHasBackgroundColor = false; - noteLayerPropertyChanged(BackgroundColorChanged); -} - -void GraphicsLayerMac::setContentsOpaque(bool opaque) -{ - if (m_contentsOpaque == opaque) - return; - - GraphicsLayer::setContentsOpaque(opaque); - noteLayerPropertyChanged(ContentsOpaqueChanged); -} - -void GraphicsLayerMac::setBackfaceVisibility(bool visible) -{ - if (m_backfaceVisibility == visible) - return; - - GraphicsLayer::setBackfaceVisibility(visible); - noteLayerPropertyChanged(BackfaceVisibilityChanged); -} - -void GraphicsLayerMac::setOpacity(float opacity) -{ - float clampedOpacity = max(0.0f, min(opacity, 1.0f)); - - if (clampedOpacity == m_opacity) - return; - - GraphicsLayer::setOpacity(clampedOpacity); - noteLayerPropertyChanged(OpacityChanged); -} - -void GraphicsLayerMac::setNeedsDisplay() -{ - FloatRect hugeRect(-numeric_limits<float>::max() / 2, -numeric_limits<float>::max() / 2, - numeric_limits<float>::max(), numeric_limits<float>::max()); - - setNeedsDisplayInRect(hugeRect); -} - -void GraphicsLayerMac::setNeedsDisplayInRect(const FloatRect& rect) -{ - if (!drawsContent()) - return; - - const size_t maxDirtyRects = 32; - - for (size_t i = 0; i < m_dirtyRects.size(); ++i) { - if (m_dirtyRects[i].contains(rect)) - return; - } - - if (m_dirtyRects.size() < maxDirtyRects) - m_dirtyRects.append(rect); - else - m_dirtyRects[0].unite(rect); - - noteLayerPropertyChanged(DirtyRectsChanged); -} - -void GraphicsLayerMac::setContentsNeedsDisplay() -{ - noteLayerPropertyChanged(ContentsNeedsDisplay); -} - -void GraphicsLayerMac::setContentsRect(const IntRect& rect) -{ - if (rect == m_contentsRect) - return; - - GraphicsLayer::setContentsRect(rect); - noteLayerPropertyChanged(ContentsRectChanged); -} - -bool GraphicsLayerMac::addAnimation(const KeyframeValueList& valueList, const IntSize& boxSize, const Animation* anim, const String& animationName, double timeOffset) -{ - ASSERT(!animationName.isEmpty()); - - if (forceSoftwareAnimation() || !anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2) - return false; - -#if !HAVE_MODERN_QUARTZCORE - // Older versions of QuartzCore do not handle opacity in transform layers properly, so we will - // always do software animation in that case. - if (valueList.property() == AnimatedPropertyOpacity) - return false; -#endif - - // CoreAnimation does not handle the steps() timing function. Fall back - // to software animation in that case. - if (animationHasStepsTimingFunction(valueList, anim)) - return false; - - bool createdAnimations = false; - if (valueList.property() == AnimatedPropertyWebkitTransform) - createdAnimations = createTransformAnimationsFromKeyframes(valueList, anim, animationName, timeOffset, boxSize); - else - createdAnimations = createAnimationFromKeyframes(valueList, anim, animationName, timeOffset); - - if (createdAnimations) - noteLayerPropertyChanged(AnimationChanged); - - return createdAnimations; -} - -void GraphicsLayerMac::pauseAnimation(const String& animationName, double timeOffset) -{ - if (!animationIsRunning(animationName)) - return; - - AnimationsToProcessMap::iterator it = m_animationsToProcess.find(animationName); - if (it != m_animationsToProcess.end()) { - AnimationProcessingAction& processingInfo = it->second; - // If an animation is scheduled to be removed, don't change the remove to a pause. - if (processingInfo.action != Remove) - processingInfo.action = Pause; - } else - m_animationsToProcess.add(animationName, AnimationProcessingAction(Pause, timeOffset)); - - noteLayerPropertyChanged(AnimationChanged); -} - -void GraphicsLayerMac::removeAnimation(const String& animationName) -{ - if (!animationIsRunning(animationName)) - return; - - m_animationsToProcess.add(animationName, AnimationProcessingAction(Remove)); - noteLayerPropertyChanged(AnimationChanged); -} - -void GraphicsLayerMac::animationDidStart(CAAnimation* caAnimation) -{ - bool hadNonZeroBeginTime = [[caAnimation valueForKey:WebKitAnimationBeginTimeSetKey] boolValue]; - - double startTime; - if (hadNonZeroBeginTime) { - // We don't know what time CA used to commit the animation, so just use the current time - // (even though this will be slightly off). - startTime = WebCore::mediaTimeToCurrentTime(CACurrentMediaTime()); - } else - startTime = WebCore::mediaTimeToCurrentTime([caAnimation beginTime]); - - if (m_client) - m_client->notifyAnimationStarted(this, startTime); -} - -void GraphicsLayerMac::setContentsToImage(Image* image) -{ - if (image) { - CGImageRef newImage = image->nativeImageForCurrentFrame(); - if (!newImage) - return; - - // Check to see if the image changed; we have to do this because the call to - // CGImageCreateCopyWithColorSpace() below can create a new image every time. - if (m_uncorrectedContentsImage && m_uncorrectedContentsImage.get() == newImage) - return; - - m_uncorrectedContentsImage = newImage; - m_pendingContentsImage = newImage; - CGColorSpaceRef colorSpace = CGImageGetColorSpace(m_pendingContentsImage.get()); - - static CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB(); - if (colorSpace && CFEqual(colorSpace, deviceRGB)) { - // CoreGraphics renders images tagged with DeviceRGB using the color space of the main display. When we hand such - // images to CA we need to tag them similarly so CA rendering matches CG rendering. - static CGColorSpaceRef genericRGB = CGDisplayCopyColorSpace(kCGDirectMainDisplay); - m_pendingContentsImage.adoptCF(CGImageCreateCopyWithColorSpace(m_pendingContentsImage.get(), genericRGB)); - } - m_contentsLayerPurpose = ContentsLayerForImage; - if (!m_contentsLayer) - noteSublayersChanged(); - } else { - m_uncorrectedContentsImage = 0; - m_pendingContentsImage = 0; - m_contentsLayerPurpose = NoContentsLayer; - if (m_contentsLayer) - noteSublayersChanged(); - } - - noteLayerPropertyChanged(ContentsImageChanged); -} - -void GraphicsLayerMac::setContentsToMedia(PlatformLayer* mediaLayer) -{ - if (mediaLayer == m_contentsLayer) - return; - - m_contentsLayer = mediaLayer; - m_contentsLayerPurpose = mediaLayer ? ContentsLayerForMedia : NoContentsLayer; - - noteSublayersChanged(); - noteLayerPropertyChanged(ContentsMediaLayerChanged); -} - -void GraphicsLayerMac::didDisplay(PlatformLayer* layer) -{ - CALayer* sourceLayer; - LayerMap* layerCloneMap; - - if (layer == m_layer) { - sourceLayer = m_layer.get(); - layerCloneMap = m_layerClones.get(); - } else if (layer == m_contentsLayer) { - sourceLayer = m_contentsLayer.get(); - layerCloneMap = m_contentsLayerClones.get(); - } else - return; - - if (layerCloneMap) { - LayerMap::const_iterator end = layerCloneMap->end(); - for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { - CALayer *currClone = it->second.get(); - if (!currClone) - continue; - - if ([currClone contents] != [sourceLayer contents]) - [currClone setContents:[sourceLayer contents]]; - else - [currClone setContentsChanged]; - } - } -} - -void GraphicsLayerMac::syncCompositingState() -{ - recursiveCommitChanges(); -} - -void GraphicsLayerMac::syncCompositingStateForThisLayerOnly() -{ - commitLayerChangesBeforeSublayers(); - commitLayerChangesAfterSublayers(); -} - -void GraphicsLayerMac::recursiveCommitChanges() -{ - commitLayerChangesBeforeSublayers(); - - if (m_maskLayer) - static_cast<GraphicsLayerMac*>(m_maskLayer)->commitLayerChangesBeforeSublayers(); - - const Vector<GraphicsLayer*>& childLayers = children(); - size_t numChildren = childLayers.size(); - for (size_t i = 0; i < numChildren; ++i) { - GraphicsLayerMac* curChild = static_cast<GraphicsLayerMac*>(childLayers[i]); - curChild->recursiveCommitChanges(); - } - - if (m_replicaLayer) - static_cast<GraphicsLayerMac*>(m_replicaLayer)->recursiveCommitChanges(); - - if (m_maskLayer) - static_cast<GraphicsLayerMac*>(m_maskLayer)->commitLayerChangesAfterSublayers(); - - commitLayerChangesAfterSublayers(); -} - -void GraphicsLayerMac::commitLayerChangesBeforeSublayers() -{ - if (!m_uncommittedChanges) - return; - - BEGIN_BLOCK_OBJC_EXCEPTIONS - - // Need to handle Preserves3DChanged first, because it affects which layers subsequent properties are applied to - if (m_uncommittedChanges & (Preserves3DChanged | ReplicatedLayerChanged)) - updateStructuralLayer(); - - if (m_uncommittedChanges & NameChanged) - updateLayerNames(); - - if (m_uncommittedChanges & ContentsImageChanged) // Needs to happen before ChildrenChanged - updateContentsImage(); - - if (m_uncommittedChanges & ContentsMediaLayerChanged) // Needs to happen before ChildrenChanged - updateContentsMediaLayer(); - - if (m_uncommittedChanges & ContentsCanvasLayerChanged) // Needs to happen before ChildrenChanged - updateContentsCanvasLayer(); - - if (m_uncommittedChanges & BackgroundColorChanged) // Needs to happen before ChildrenChanged, and after updating image or video - updateLayerBackgroundColor(); - - if (m_uncommittedChanges & ChildrenChanged) - updateSublayerList(); - - if (m_uncommittedChanges & PositionChanged) - updateLayerPosition(); - - if (m_uncommittedChanges & AnchorPointChanged) - updateAnchorPoint(); - - if (m_uncommittedChanges & SizeChanged) - updateLayerSize(); - - if (m_uncommittedChanges & TransformChanged) - updateTransform(); - - if (m_uncommittedChanges & ChildrenTransformChanged) - updateChildrenTransform(); - - if (m_uncommittedChanges & MasksToBoundsChanged) - updateMasksToBounds(); - - if (m_uncommittedChanges & DrawsContentChanged) - updateLayerDrawsContent(); - - if (m_uncommittedChanges & ContentsOpaqueChanged) - updateContentsOpaque(); - - if (m_uncommittedChanges & BackfaceVisibilityChanged) - updateBackfaceVisibility(); - - if (m_uncommittedChanges & OpacityChanged) - updateOpacityOnLayer(); - - if (m_uncommittedChanges & AnimationChanged) - updateLayerAnimations(); - - if (m_uncommittedChanges & DirtyRectsChanged) - repaintLayerDirtyRects(); - - if (m_uncommittedChanges & ContentsRectChanged) - updateContentsRect(); - - if (m_uncommittedChanges & MaskLayerChanged) - updateMaskLayer(); - - if (m_uncommittedChanges & ContentsNeedsDisplay) - updateContentsNeedsDisplay(); - - END_BLOCK_OBJC_EXCEPTIONS -} - -void GraphicsLayerMac::commitLayerChangesAfterSublayers() -{ - if (!m_uncommittedChanges) - return; - - BEGIN_BLOCK_OBJC_EXCEPTIONS - - if (m_uncommittedChanges & ReplicatedLayerChanged) - updateReplicatedLayers(); - - m_uncommittedChanges = NoChange; - END_BLOCK_OBJC_EXCEPTIONS -} - -void GraphicsLayerMac::updateLayerNames() -{ - switch (structuralLayerPurpose()) { - case StructuralLayerForPreserves3D: - [m_structuralLayer.get() setName:("Transform layer " + name())]; - break; - case StructuralLayerForReplicaFlattening: - [m_structuralLayer.get() setName:("Replica flattening layer " + name())]; - break; - case NoStructuralLayer: - break; - } - [m_layer.get() setName:name()]; -} - -void GraphicsLayerMac::updateSublayerList() -{ - NSMutableArray* newSublayers = nil; - - const Vector<GraphicsLayer*>& childLayers = children(); - - if (m_structuralLayer || m_contentsLayer || childLayers.size() > 0) { - newSublayers = [[NSMutableArray alloc] init]; - - if (m_structuralLayer) { - // Add the replica layer first. - if (m_replicaLayer) - [newSublayers addObject:static_cast<GraphicsLayerMac*>(m_replicaLayer)->primaryLayer()]; - // Add the primary layer. Even if we have negative z-order children, the primary layer always comes behind. - [newSublayers addObject:m_layer.get()]; - } else if (m_contentsLayer) { - // FIXME: add the contents layer in the correct order with negative z-order children. - // This does not cause visible rendering issues because currently contents layers are only used - // for replaced elements that don't have children. - [newSublayers addObject:m_contentsLayer.get()]; - } - - size_t numChildren = childLayers.size(); - for (size_t i = 0; i < numChildren; ++i) { - GraphicsLayerMac* curChild = static_cast<GraphicsLayerMac*>(childLayers[i]); - CALayer *childLayer = curChild->layerForSuperlayer(); - [newSublayers addObject:childLayer]; - } - - [newSublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)]; - } - - if (m_structuralLayer) { - safeSetSublayers(m_structuralLayer.get(), newSublayers); - - if (m_contentsLayer) { - // If we have a transform layer, then the contents layer is parented in the - // primary layer (which is itself a child of the transform layer). - safeSetSublayers(m_layer.get(), nil); - [m_layer.get() addSublayer:m_contentsLayer.get()]; - } - } else - safeSetSublayers(m_layer.get(), newSublayers); - - [newSublayers release]; -} - -void GraphicsLayerMac::updateLayerPosition() -{ - FloatSize usedSize = m_usingTiledLayer ? constrainedSize() : m_size; - - // Position is offset on the layer by the layer anchor point. - CGPoint posPoint = CGPointMake(m_position.x() + m_anchorPoint.x() * usedSize.width(), - m_position.y() + m_anchorPoint.y() * usedSize.height()); - - [primaryLayer() setPosition:posPoint]; - - if (LayerMap* layerCloneMap = primaryLayerClones()) { - LayerMap::const_iterator end = layerCloneMap->end(); - for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { - CGPoint clonePosition = posPoint; - if (m_replicaLayer && isReplicatedRootClone(it->first)) { - // Maintain the special-case position for the root of a clone subtree, - // which we set up in replicatedLayerRoot(). - clonePosition = positionForCloneRootLayer(); - } - CALayer *currLayer = it->second.get(); - [currLayer setPosition:clonePosition]; - } - } -} - -void GraphicsLayerMac::updateLayerSize() -{ - CGRect rect = CGRectMake(0, 0, m_size.width(), m_size.height()); - if (m_structuralLayer) { - [m_structuralLayer.get() setBounds:rect]; - - if (LayerMap* layerCloneMap = m_structuralLayerClones.get()) { - LayerMap::const_iterator end = layerCloneMap->end(); - for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) - [it->second.get() setBounds:rect]; - } - - // The anchor of the contents layer is always at 0.5, 0.5, so the position is center-relative. - CGPoint centerPoint = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f); - [m_layer.get() setPosition:centerPoint]; - - if (LayerMap* layerCloneMap = m_layerClones.get()) { - LayerMap::const_iterator end = layerCloneMap->end(); - for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) - [it->second.get() setPosition:centerPoint]; - } - } - - bool needTiledLayer = requiresTiledLayer(m_size); - if (needTiledLayer != m_usingTiledLayer) - swapFromOrToTiledLayer(needTiledLayer); - - if (m_usingTiledLayer) { - FloatSize sizeToUse = constrainedSize(); - rect = CGRectMake(0, 0, sizeToUse.width(), sizeToUse.height()); - } - - [m_layer.get() setBounds:rect]; - if (LayerMap* layerCloneMap = m_layerClones.get()) { - LayerMap::const_iterator end = layerCloneMap->end(); - for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) - [it->second.get() setBounds:rect]; - } - - // Contents transform may depend on height. - updateContentsTransform(); - - // Note that we don't resize m_contentsLayer. It's up the caller to do that. - - // if we've changed the bounds, we need to recalculate the position - // of the layer, taking anchor point into account. - updateLayerPosition(); -} - -void GraphicsLayerMac::updateAnchorPoint() -{ - [primaryLayer() setAnchorPoint:FloatPoint(m_anchorPoint.x(), m_anchorPoint.y())]; -#if HAVE_MODERN_QUARTZCORE - [primaryLayer() setAnchorPointZ:m_anchorPoint.z()]; -#endif - - if (LayerMap* layerCloneMap = primaryLayerClones()) { - LayerMap::const_iterator end = layerCloneMap->end(); - for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { - CALayer *currLayer = it->second.get(); - [currLayer setAnchorPoint:FloatPoint(m_anchorPoint.x(), m_anchorPoint.y())]; -#if HAVE_MODERN_QUARTZCORE - [currLayer setAnchorPointZ:m_anchorPoint.z()]; -#endif - } - } - - updateLayerPosition(); -} - -void GraphicsLayerMac::updateTransform() -{ - CATransform3D transform; - copyTransform(transform, m_transform); - [primaryLayer() setTransform:transform]; - - if (LayerMap* layerCloneMap = primaryLayerClones()) { - LayerMap::const_iterator end = layerCloneMap->end(); - for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { - CALayer *currLayer = it->second.get(); - if (m_replicaLayer && isReplicatedRootClone(it->first)) { - // Maintain the special-case transform for the root of a clone subtree, - // which we set up in replicatedLayerRoot(). - [currLayer setTransform:CATransform3DIdentity]; - } else - [currLayer setTransform:transform]; - } - } -} - -void GraphicsLayerMac::updateChildrenTransform() -{ - CATransform3D transform; - copyTransform(transform, m_childrenTransform); - [primaryLayer() setSublayerTransform:transform]; - - if (LayerMap* layerCloneMap = primaryLayerClones()) { - LayerMap::const_iterator end = layerCloneMap->end(); - for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { - CALayer *currLayer = it->second.get(); - [currLayer setSublayerTransform:transform]; - } - } -} - -void GraphicsLayerMac::updateMasksToBounds() -{ - [m_layer.get() setMasksToBounds:m_masksToBounds]; - - if (LayerMap* layerCloneMap = m_layerClones.get()) { - LayerMap::const_iterator end = layerCloneMap->end(); - for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { - CALayer *currLayer = it->second.get(); - [currLayer setMasksToBounds:m_masksToBounds]; - } - } - - updateDebugIndicators(); -} - -void GraphicsLayerMac::updateContentsOpaque() -{ - [m_layer.get() setOpaque:m_contentsOpaque]; - - if (LayerMap* layerCloneMap = m_layerClones.get()) { - LayerMap::const_iterator end = layerCloneMap->end(); - for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { - CALayer *currLayer = it->second.get(); - [currLayer setOpaque:m_contentsOpaque]; - } - } -} - -void GraphicsLayerMac::updateBackfaceVisibility() -{ - if (m_structuralLayer && structuralLayerPurpose() == StructuralLayerForReplicaFlattening) { - [m_structuralLayer.get() setDoubleSided:m_backfaceVisibility]; - - if (LayerMap* layerCloneMap = m_structuralLayerClones.get()) { - LayerMap::const_iterator end = layerCloneMap->end(); - for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { - CALayer *currLayer = it->second.get(); - [currLayer setDoubleSided:m_backfaceVisibility]; - } - } - } - - [m_layer.get() setDoubleSided:m_backfaceVisibility]; - - if (LayerMap* layerCloneMap = m_layerClones.get()) { - LayerMap::const_iterator end = layerCloneMap->end(); - for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { - CALayer *currLayer = it->second.get(); - [currLayer setDoubleSided:m_backfaceVisibility]; - } - } -} - -void GraphicsLayerMac::updateStructuralLayer() -{ - ensureStructuralLayer(structuralLayerPurpose()); -} - -void GraphicsLayerMac::ensureStructuralLayer(StructuralLayerPurpose purpose) -{ - if (purpose == NoStructuralLayer) { - if (m_structuralLayer) { - // Replace the transformLayer in the parent with this layer. - [m_layer.get() removeFromSuperlayer]; - [[m_structuralLayer.get() superlayer] replaceSublayer:m_structuralLayer.get() with:m_layer.get()]; - - moveOrCopyAnimationsForProperty(Move, AnimatedPropertyWebkitTransform, m_structuralLayer.get(), m_layer.get()); - moveOrCopyAnimationsForProperty(Move, AnimatedPropertyOpacity, m_structuralLayer.get(), m_layer.get()); - - // Release the structural layer. - m_structuralLayer = 0; - - // Update the properties of m_layer now that we no longer have a structural layer. - updateLayerPosition(); - updateLayerSize(); - updateAnchorPoint(); - updateTransform(); - updateChildrenTransform(); - - updateSublayerList(); - updateOpacityOnLayer(); - } - return; - } - - bool structuralLayerChanged = false; - - if (purpose == StructuralLayerForPreserves3D) { - Class transformLayerClass = NSClassFromString(@"CATransformLayer"); - if (!transformLayerClass) - return; - - if (m_structuralLayer && ![m_structuralLayer.get() isKindOfClass:transformLayerClass]) - m_structuralLayer = 0; - - if (!m_structuralLayer) { - m_structuralLayer.adoptNS([[transformLayerClass alloc] init]); - structuralLayerChanged = true; - } - } else { - if (m_structuralLayer && ![m_structuralLayer.get() isMemberOfClass:[CALayer self]]) - m_structuralLayer = 0; - - if (!m_structuralLayer) { - m_structuralLayer.adoptNS([[CALayer alloc] init]); - structuralLayerChanged = true; - } - } - - if (!structuralLayerChanged) - return; - - // Turn off default animations. - [m_structuralLayer.get() setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]]; - - updateLayerNames(); - - // Update the properties of the structural layer. - updateLayerPosition(); - updateLayerSize(); - updateAnchorPoint(); - updateTransform(); - updateChildrenTransform(); - updateBackfaceVisibility(); - - // Set properties of m_layer to their default values, since these are expressed on on the structural layer. - CGPoint point = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f); - [m_layer.get() setPosition:point]; - [m_layer.get() setAnchorPoint:CGPointMake(0.5f, 0.5f)]; - [m_layer.get() setTransform:CATransform3DIdentity]; - [m_layer.get() setOpacity:1]; - - // Move this layer to be a child of the transform layer. - [[m_layer.get() superlayer] replaceSublayer:m_layer.get() with:m_structuralLayer.get()]; - [m_structuralLayer.get() addSublayer:m_layer.get()]; - - moveOrCopyAnimationsForProperty(Move, AnimatedPropertyWebkitTransform, m_layer.get(), m_structuralLayer.get()); - moveOrCopyAnimationsForProperty(Move, AnimatedPropertyOpacity, m_layer.get(), m_structuralLayer.get()); - - updateSublayerList(); - updateOpacityOnLayer(); -} - -GraphicsLayerMac::StructuralLayerPurpose GraphicsLayerMac::structuralLayerPurpose() const -{ - if (preserves3D()) - return StructuralLayerForPreserves3D; - - if (isReplicated()) - return StructuralLayerForReplicaFlattening; - - return NoStructuralLayer; -} - -void GraphicsLayerMac::updateLayerDrawsContent() -{ - bool needTiledLayer = requiresTiledLayer(m_size); - if (needTiledLayer != m_usingTiledLayer) - swapFromOrToTiledLayer(needTiledLayer); - - if (m_drawsContent) - [m_layer.get() setNeedsDisplay]; - else - [m_layer.get() setContents:nil]; - - updateDebugIndicators(); -} - -void GraphicsLayerMac::updateLayerBackgroundColor() -{ - if (!m_contentsLayer) - return; - - // We never create the contents layer just for background color yet. - if (m_backgroundColorSet) - setLayerBackgroundColor(m_contentsLayer.get(), m_backgroundColor); - else - clearLayerBackgroundColor(m_contentsLayer.get()); -} - -void GraphicsLayerMac::updateContentsImage() -{ - if (m_pendingContentsImage) { - if (!m_contentsLayer.get()) { - WebLayer* imageLayer = [WebLayer layer]; -#ifndef NDEBUG - [imageLayer setName:@"Image Layer"]; -#endif - setupContentsLayer(imageLayer); - m_contentsLayer.adoptNS([imageLayer retain]); - // m_contentsLayer will be parented by updateSublayerList - } - - // FIXME: maybe only do trilinear if the image is being scaled down, - // but then what if the layer size changes? -#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) - [m_contentsLayer.get() setMinificationFilter:kCAFilterTrilinear]; -#endif - [m_contentsLayer.get() setContents:(id)m_pendingContentsImage.get()]; - m_pendingContentsImage = 0; - - if (m_contentsLayerClones) { - LayerMap::const_iterator end = m_contentsLayerClones->end(); - for (LayerMap::const_iterator it = m_contentsLayerClones->begin(); it != end; ++it) - [it->second.get() setContents:[m_contentsLayer.get() contents]]; - } - - updateContentsRect(); - } else { - // No image. - // m_contentsLayer will be removed via updateSublayerList. - m_contentsLayer = 0; - } -} - -void GraphicsLayerMac::updateContentsMediaLayer() -{ - // Video layer was set as m_contentsLayer, and will get parented in updateSublayerList(). - if (m_contentsLayer) { - setupContentsLayer(m_contentsLayer.get()); - updateContentsRect(); - } -} - -void GraphicsLayerMac::updateContentsCanvasLayer() -{ - // CanvasLayer was set as m_contentsLayer, and will get parented in updateSublayerList(). - if (m_contentsLayer) { - setupContentsLayer(m_contentsLayer.get()); - [m_contentsLayer.get() setNeedsDisplay]; - updateContentsRect(); - } -} - -void GraphicsLayerMac::updateContentsRect() -{ - if (!m_contentsLayer) - return; - - CGPoint point = CGPointMake(m_contentsRect.x(), - m_contentsRect.y()); - CGRect rect = CGRectMake(0.0f, - 0.0f, - m_contentsRect.width(), - m_contentsRect.height()); - - [m_contentsLayer.get() setPosition:point]; - [m_contentsLayer.get() setBounds:rect]; - - if (m_contentsLayerClones) { - LayerMap::const_iterator end = m_contentsLayerClones->end(); - for (LayerMap::const_iterator it = m_contentsLayerClones->begin(); it != end; ++it) { - CALayer *currLayer = it->second.get(); - [currLayer setPosition:point]; - [currLayer setBounds:rect]; - } - } -} - -void GraphicsLayerMac::updateMaskLayer() -{ - CALayer *maskCALayer = m_maskLayer ? m_maskLayer->platformLayer() : 0; - [m_layer.get() setMask:maskCALayer]; - - LayerMap* maskLayerCloneMap = m_maskLayer ? static_cast<GraphicsLayerMac*>(m_maskLayer)->primaryLayerClones() : 0; - - if (LayerMap* layerCloneMap = m_layerClones.get()) { - LayerMap::const_iterator end = layerCloneMap->end(); - for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { - CALayer *currLayer = it->second.get(); - - CALayer *maskClone = maskLayerCloneMap ? maskLayerCloneMap->get(it->first).get() : 0; - [currLayer setMask:maskClone]; - } - } -} - -void GraphicsLayerMac::updateReplicatedLayers() -{ - // Clone the descendants of the replicated layer, and parent under us. - ReplicaState replicaState(ReplicaState::ReplicaBranch); - - CALayer *replicaRoot = replicatedLayerRoot(replicaState); - if (!replicaRoot) - return; - - if (m_structuralLayer) - [m_structuralLayer.get() insertSublayer:replicaRoot atIndex:0]; - else - [m_layer.get() insertSublayer:replicaRoot atIndex:0]; -} - -// For now, this assumes that layers only ever have one replica, so replicaIndices contains only 0 and 1. -GraphicsLayerMac::CloneID GraphicsLayerMac::ReplicaState::cloneID() const -{ - size_t depth = m_replicaBranches.size(); - - const size_t bitsPerUChar = sizeof(UChar) * 8; - size_t vectorSize = (depth + bitsPerUChar - 1) / bitsPerUChar; - - Vector<UChar> result(vectorSize); - result.fill(0); - - // Create a string from the bit sequence which we can use to identify the clone. - // Note that the string may contain embedded nulls, but that's OK. - for (size_t i = 0; i < depth; ++i) { - UChar& currChar = result[i / bitsPerUChar]; - currChar = (currChar << 1) | m_replicaBranches[i]; - } - - return String::adopt(result); -} - -CALayer *GraphicsLayerMac::replicatedLayerRoot(ReplicaState& replicaState) -{ - // Limit replica nesting, to avoid 2^N explosion of replica layers. - if (!m_replicatedLayer || replicaState.replicaDepth() == ReplicaState::maxReplicaDepth) - return nil; - - GraphicsLayerMac* replicatedLayer = static_cast<GraphicsLayerMac*>(m_replicatedLayer); - - CALayer *clonedLayerRoot = replicatedLayer->fetchCloneLayers(this, replicaState, RootCloneLevel); - FloatPoint cloneRootPosition = replicatedLayer->positionForCloneRootLayer(); - - // Replica root has no offset or transform - [clonedLayerRoot setPosition:cloneRootPosition]; - [clonedLayerRoot setTransform:CATransform3DIdentity]; - - return clonedLayerRoot; -} - -void GraphicsLayerMac::updateLayerAnimations() -{ - if (m_animationsToProcess.size()) { - AnimationsToProcessMap::const_iterator end = m_animationsToProcess.end(); - for (AnimationsToProcessMap::const_iterator it = m_animationsToProcess.begin(); it != end; ++it) { - const String& currAnimationName = it->first; - AnimationsMap::iterator animationIt = m_runningAnimations.find(currAnimationName); - if (animationIt == m_runningAnimations.end()) - continue; - - const AnimationProcessingAction& processingInfo = it->second; - const Vector<LayerPropertyAnimation>& animations = animationIt->second; - for (size_t i = 0; i < animations.size(); ++i) { - const LayerPropertyAnimation& currAnimation = animations[i]; - switch (processingInfo.action) { - case Remove: - removeCAAnimationFromLayer(currAnimation.m_property, currAnimationName, currAnimation.m_index); - break; - case Pause: - pauseCAAnimationOnLayer(currAnimation.m_property, currAnimationName, currAnimation.m_index, processingInfo.timeOffset); - break; - } - } - - if (processingInfo.action == Remove) - m_runningAnimations.remove(currAnimationName); - } - - m_animationsToProcess.clear(); - } - - size_t numAnimations; - if ((numAnimations = m_uncomittedAnimations.size())) { - for (size_t i = 0; i < numAnimations; ++i) { - const LayerPropertyAnimation& pendingAnimation = m_uncomittedAnimations[i]; - setCAAnimationOnLayer(pendingAnimation.m_animation.get(), pendingAnimation.m_property, pendingAnimation.m_name, pendingAnimation.m_index, pendingAnimation.m_timeOffset); - - AnimationsMap::iterator it = m_runningAnimations.find(pendingAnimation.m_name); - if (it == m_runningAnimations.end()) { - Vector<LayerPropertyAnimation> animations; - animations.append(pendingAnimation); - m_runningAnimations.add(pendingAnimation.m_name, animations); - } else { - Vector<LayerPropertyAnimation>& animations = it->second; - animations.append(pendingAnimation); - } - } - - m_uncomittedAnimations.clear(); - } -} - -void GraphicsLayerMac::setCAAnimationOnLayer(CAPropertyAnimation* caAnim, AnimatedPropertyID property, const String& animationName, int index, double timeOffset) -{ - PlatformLayer* layer = animatedLayer(property); - - if (timeOffset) { - [caAnim setBeginTime:CACurrentMediaTime() - timeOffset]; - [caAnim setValue:[NSNumber numberWithBool:YES] forKey:WebKitAnimationBeginTimeSetKey]; - } - - NSString *animationID = animationIdentifier(animationName, property, index); - - [layer removeAnimationForKey:animationID]; - [layer addAnimation:caAnim forKey:animationID]; - - if (LayerMap* layerCloneMap = animatedLayerClones(property)) { - LayerMap::const_iterator end = layerCloneMap->end(); - for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { - // Skip immediate replicas, since they move with the original. - if (m_replicaLayer && isReplicatedRootClone(it->first)) - continue; - CALayer *currLayer = it->second.get(); - [currLayer removeAnimationForKey:animationID]; - [currLayer addAnimation:caAnim forKey:animationID]; - } - } -} - -// Workaround for <rdar://problem/7311367> -static void bug7311367Workaround(CALayer* transformLayer, const TransformationMatrix& transform) -{ - if (!transformLayer) - return; - - CATransform3D caTransform; - copyTransform(caTransform, transform); - caTransform.m41 += 1; - [transformLayer setTransform:caTransform]; - - caTransform.m41 -= 1; - [transformLayer setTransform:caTransform]; -} - -bool GraphicsLayerMac::removeCAAnimationFromLayer(AnimatedPropertyID property, const String& animationName, int index) -{ - PlatformLayer* layer = animatedLayer(property); - - NSString *animationID = animationIdentifier(animationName, property, index); - - if (![layer animationForKey:animationID]) - return false; - - [layer removeAnimationForKey:animationID]; - bug7311367Workaround(m_structuralLayer.get(), m_transform); - - if (LayerMap* layerCloneMap = animatedLayerClones(property)) { - LayerMap::const_iterator end = layerCloneMap->end(); - for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { - // Skip immediate replicas, since they move with the original. - if (m_replicaLayer && isReplicatedRootClone(it->first)) - continue; - - CALayer *currLayer = it->second.get(); - [currLayer removeAnimationForKey:animationID]; - } - } - return true; -} - -static void copyAnimationProperties(CAPropertyAnimation* from, CAPropertyAnimation* to) -{ - [to setBeginTime:[from beginTime]]; - [to setDuration:[from duration]]; - [to setRepeatCount:[from repeatCount]]; - [to setAutoreverses:[from autoreverses]]; - [to setFillMode:[from fillMode]]; - [to setRemovedOnCompletion:[from isRemovedOnCompletion]]; - [to setAdditive:[from isAdditive]]; - [to setTimingFunction:[from timingFunction]]; - -#if HAVE_MODERN_QUARTZCORE - [to setValueFunction:[from valueFunction]]; -#endif - - if (id object = [from valueForKey:WebKitAnimationBeginTimeSetKey]) - [to setValue:object forKey:WebKitAnimationBeginTimeSetKey]; -} - -void GraphicsLayerMac::pauseCAAnimationOnLayer(AnimatedPropertyID property, const String& animationName, int index, double timeOffset) -{ - PlatformLayer* layer = animatedLayer(property); - - NSString *animationID = animationIdentifier(animationName, property, index); - - CAAnimation *caAnim = [layer animationForKey:animationID]; - if (!caAnim) - return; - - // Animations on the layer are immutable, so we have to clone and modify. - CAPropertyAnimation* pausedAnim = nil; - if ([caAnim isKindOfClass:[CAKeyframeAnimation class]]) { - CAKeyframeAnimation* existingKeyframeAnim = static_cast<CAKeyframeAnimation*>(caAnim); - CAKeyframeAnimation* newAnim = [CAKeyframeAnimation animationWithKeyPath:[existingKeyframeAnim keyPath]]; - copyAnimationProperties(existingKeyframeAnim, newAnim); - [newAnim setValues:[existingKeyframeAnim values]]; - [newAnim setKeyTimes:[existingKeyframeAnim keyTimes]]; - [newAnim setTimingFunctions:[existingKeyframeAnim timingFunctions]]; - pausedAnim = newAnim; - } else if ([caAnim isKindOfClass:[CABasicAnimation class]]) { - CABasicAnimation* existingPropertyAnim = static_cast<CABasicAnimation*>(caAnim); - CABasicAnimation* newAnim = [CABasicAnimation animationWithKeyPath:[existingPropertyAnim keyPath]]; - copyAnimationProperties(existingPropertyAnim, newAnim); - [newAnim setFromValue:[existingPropertyAnim fromValue]]; - [newAnim setToValue:[existingPropertyAnim toValue]]; - pausedAnim = newAnim; - } - - // pausedAnim has the beginTime of caAnim already. - [pausedAnim setSpeed:0]; - [pausedAnim setTimeOffset:timeOffset]; - - [layer addAnimation:pausedAnim forKey:animationID]; // This will replace the running animation. - - // Pause the animations on the clones too. - if (LayerMap* layerCloneMap = animatedLayerClones(property)) { - LayerMap::const_iterator end = layerCloneMap->end(); - for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { - // Skip immediate replicas, since they move with the original. - if (m_replicaLayer && isReplicatedRootClone(it->first)) - continue; - CALayer *currLayer = it->second.get(); - [currLayer addAnimation:pausedAnim forKey:animationID]; - } - } -} - -void GraphicsLayerMac::setContentsToCanvas(PlatformLayer* canvasLayer) -{ - if (canvasLayer == m_contentsLayer) - return; - - m_contentsLayer = canvasLayer; - if (m_contentsLayer && [m_contentsLayer.get() respondsToSelector:@selector(setLayerOwner:)]) - [(id)m_contentsLayer.get() setLayerOwner:this]; - - m_contentsLayerPurpose = canvasLayer ? ContentsLayerForCanvas : NoContentsLayer; - - noteSublayersChanged(); - noteLayerPropertyChanged(ContentsCanvasLayerChanged); -} - -void GraphicsLayerMac::repaintLayerDirtyRects() -{ - if (!m_dirtyRects.size()) - return; - - for (size_t i = 0; i < m_dirtyRects.size(); ++i) - [m_layer.get() setNeedsDisplayInRect:m_dirtyRects[i]]; - - m_dirtyRects.clear(); -} - -void GraphicsLayerMac::updateContentsNeedsDisplay() -{ - if (m_contentsLayer) - [m_contentsLayer.get() setNeedsDisplay]; -} - -bool GraphicsLayerMac::createAnimationFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, double timeOffset) -{ - ASSERT(valueList.property() != AnimatedPropertyWebkitTransform); - - BEGIN_BLOCK_OBJC_EXCEPTIONS; - - bool isKeyframe = valueList.size() > 2; - bool valuesOK; - - bool additive = false; - int animationIndex = 0; - - CAPropertyAnimation* caAnimation; - if (isKeyframe) { - CAKeyframeAnimation* keyframeAnim = createKeyframeAnimation(animation, valueList.property(), additive); - valuesOK = setAnimationKeyframes(valueList, animation, keyframeAnim); - caAnimation = keyframeAnim; - } else { - CABasicAnimation* basicAnim = createBasicAnimation(animation, valueList.property(), additive); - valuesOK = setAnimationEndpoints(valueList, animation, basicAnim); - caAnimation = basicAnim; - } - - if (!valuesOK) - return false; - - m_uncomittedAnimations.append(LayerPropertyAnimation(caAnimation, animationName, valueList.property(), animationIndex, timeOffset)); - - END_BLOCK_OBJC_EXCEPTIONS; - - return true; -} - -bool GraphicsLayerMac::createTransformAnimationsFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, double timeOffset, const IntSize& boxSize) -{ - ASSERT(valueList.property() == AnimatedPropertyWebkitTransform); - - TransformOperationList functionList; - bool listsMatch, hasBigRotation; - fetchTransformOperationList(valueList, functionList, listsMatch, hasBigRotation); - - // We need to fall back to software animation if we don't have setValueFunction:, and - // we would need to animate each incoming transform function separately. This is the - // case if we have a rotation >= 180 or we have more than one transform function. - if ((hasBigRotation || functionList.size() > 1) && !caValueFunctionSupported()) - return false; - - bool validMatrices = true; - - BEGIN_BLOCK_OBJC_EXCEPTIONS; - - // If functionLists don't match we do a matrix animation, otherwise we do a component hardware animation. - // Also, we can't do component animation unless we have valueFunction, so we need to do matrix animation - // if that's not true as well. - bool isMatrixAnimation = !listsMatch || !caValueFunctionSupported(); - - size_t numAnimations = isMatrixAnimation ? 1 : functionList.size(); - bool isKeyframe = valueList.size() > 2; - - // Iterate through the transform functions, sending an animation for each one. - for (size_t animationIndex = 0; animationIndex < numAnimations; ++animationIndex) { - TransformOperation::OperationType transformOp = isMatrixAnimation ? TransformOperation::MATRIX_3D : functionList[animationIndex]; - CAPropertyAnimation* caAnimation; - -#if defined(BUILDING_ON_LEOPARD) || defined(BUILDING_ON_SNOW_LEOPARD) - // CA applies animations in reverse order (<rdar://problem/7095638>) so we need the last one we add (per property) - // to be non-additive. - bool additive = animationIndex < (numAnimations - 1); -#else - bool additive = animationIndex > 0; -#endif - if (isKeyframe) { - CAKeyframeAnimation* keyframeAnim = createKeyframeAnimation(animation, valueList.property(), additive); - validMatrices = setTransformAnimationKeyframes(valueList, animation, keyframeAnim, animationIndex, transformOp, isMatrixAnimation, boxSize); - caAnimation = keyframeAnim; - } else { - CABasicAnimation* basicAnim = createBasicAnimation(animation, valueList.property(), additive); - validMatrices = setTransformAnimationEndpoints(valueList, animation, basicAnim, animationIndex, transformOp, isMatrixAnimation, boxSize); - caAnimation = basicAnim; - } - - if (!validMatrices) - break; - - m_uncomittedAnimations.append(LayerPropertyAnimation(caAnimation, animationName, valueList.property(), animationIndex, timeOffset)); - } - - END_BLOCK_OBJC_EXCEPTIONS; - - return validMatrices; -} - -CABasicAnimation* GraphicsLayerMac::createBasicAnimation(const Animation* anim, AnimatedPropertyID property, bool additive) -{ - CABasicAnimation* basicAnim = [CABasicAnimation animationWithKeyPath:propertyIdToString(property)]; - setupAnimation(basicAnim, anim, additive); - return basicAnim; -} - -CAKeyframeAnimation* GraphicsLayerMac::createKeyframeAnimation(const Animation* anim, AnimatedPropertyID property, bool additive) -{ - CAKeyframeAnimation* keyframeAnim = [CAKeyframeAnimation animationWithKeyPath:propertyIdToString(property)]; - setupAnimation(keyframeAnim, anim, additive); - return keyframeAnim; -} - -void GraphicsLayerMac::setupAnimation(CAPropertyAnimation* propertyAnim, const Animation* anim, bool additive) -{ - double duration = anim->duration(); - if (duration <= 0) - duration = cAnimationAlmostZeroDuration; - - float repeatCount = anim->iterationCount(); - if (repeatCount == Animation::IterationCountInfinite) - repeatCount = FLT_MAX; - else if (anim->direction() == Animation::AnimationDirectionAlternate) - repeatCount /= 2; - - NSString *fillMode = 0; - switch (anim->fillMode()) { - case AnimationFillModeNone: - fillMode = kCAFillModeForwards; // Use "forwards" rather than "removed" because the style system will remove the animation when it is finished. This avoids a flash. - break; - case AnimationFillModeBackwards: - fillMode = kCAFillModeBoth; // Use "both" rather than "backwards" because the style system will remove the animation when it is finished. This avoids a flash. - break; - case AnimationFillModeForwards: - fillMode = kCAFillModeForwards; - break; - case AnimationFillModeBoth: - fillMode = kCAFillModeBoth; - break; - } - - [propertyAnim setDuration:duration]; - [propertyAnim setRepeatCount:repeatCount]; - [propertyAnim setAutoreverses:anim->direction()]; - [propertyAnim setRemovedOnCompletion:NO]; - [propertyAnim setAdditive:additive]; - [propertyAnim setFillMode:fillMode]; - - [propertyAnim setDelegate:m_animationDelegate.get()]; -} - -CAMediaTimingFunction* GraphicsLayerMac::timingFunctionForAnimationValue(const AnimationValue* animValue, const Animation* anim) -{ - const TimingFunction* tf = 0; - if (animValue->timingFunction()) - tf = animValue->timingFunction(); - else if (anim->isTimingFunctionSet()) - tf = anim->timingFunction().get(); - - return getCAMediaTimingFunction(tf ? tf : CubicBezierTimingFunction::create().get()); -} - -bool GraphicsLayerMac::setAnimationEndpoints(const KeyframeValueList& valueList, const Animation* anim, CABasicAnimation* basicAnim) -{ - id fromValue = nil; - id toValue = nil; - - switch (valueList.property()) { - case AnimatedPropertyOpacity: { - const FloatAnimationValue* startVal = static_cast<const FloatAnimationValue*>(valueList.at(0)); - const FloatAnimationValue* endVal = static_cast<const FloatAnimationValue*>(valueList.at(1)); - fromValue = [NSNumber numberWithFloat:startVal->value()]; - toValue = [NSNumber numberWithFloat:endVal->value()]; - break; - } - default: - ASSERT_NOT_REACHED(); // we don't animate color yet - break; - } - - // This codepath is used for 2-keyframe animations, so we still need to look in the start - // for a timing function. - CAMediaTimingFunction* timingFunction = timingFunctionForAnimationValue(valueList.at(0), anim); - [basicAnim setTimingFunction:timingFunction]; - - [basicAnim setFromValue:fromValue]; - [basicAnim setToValue:toValue]; - - return true; -} - -bool GraphicsLayerMac::setAnimationKeyframes(const KeyframeValueList& valueList, const Animation* anim, CAKeyframeAnimation* keyframeAnim) -{ - RetainPtr<NSMutableArray> keyTimes(AdoptNS, [[NSMutableArray alloc] init]); - RetainPtr<NSMutableArray> values(AdoptNS, [[NSMutableArray alloc] init]); - RetainPtr<NSMutableArray> timingFunctions(AdoptNS, [[NSMutableArray alloc] init]); - - for (unsigned i = 0; i < valueList.size(); ++i) { - const AnimationValue* curValue = valueList.at(i); - [keyTimes.get() addObject:[NSNumber numberWithFloat:curValue->keyTime()]]; - - switch (valueList.property()) { - case AnimatedPropertyOpacity: { - const FloatAnimationValue* floatValue = static_cast<const FloatAnimationValue*>(curValue); - [values.get() addObject:[NSNumber numberWithFloat:floatValue->value()]]; - break; - } - default: - ASSERT_NOT_REACHED(); // we don't animate color yet - break; - } - - CAMediaTimingFunction* timingFunction = timingFunctionForAnimationValue(curValue, anim); - [timingFunctions.get() addObject:timingFunction]; - } - - // We toss the last tfArray value because it has to one shorter than the others. - [timingFunctions.get() removeLastObject]; - - [keyframeAnim setKeyTimes:keyTimes.get()]; - [keyframeAnim setValues:values.get()]; - [keyframeAnim setTimingFunctions:timingFunctions.get()]; - - return true; -} - -bool GraphicsLayerMac::setTransformAnimationEndpoints(const KeyframeValueList& valueList, const Animation* anim, CABasicAnimation* basicAnim, int functionIndex, TransformOperation::OperationType transformOp, bool isMatrixAnimation, const IntSize& boxSize) -{ - id fromValue; - id toValue; - - ASSERT(valueList.size() == 2); - const TransformAnimationValue* startValue = static_cast<const TransformAnimationValue*>(valueList.at(0)); - const TransformAnimationValue* endValue = static_cast<const TransformAnimationValue*>(valueList.at(1)); - - if (isMatrixAnimation) { - TransformationMatrix fromTransform, toTransform; - startValue->value()->apply(boxSize, fromTransform); - endValue->value()->apply(boxSize, toTransform); - - // If any matrix is singular, CA won't animate it correctly. So fall back to software animation - if (!fromTransform.isInvertible() || !toTransform.isInvertible()) - return false; - - CATransform3D caTransform; - copyTransform(caTransform, fromTransform); - fromValue = [NSValue valueWithCATransform3D:caTransform]; - - copyTransform(caTransform, toTransform); - toValue = [NSValue valueWithCATransform3D:caTransform]; - } else { - fromValue = getTransformFunctionValue(startValue->value()->at(functionIndex), transformOp, boxSize); - toValue = getTransformFunctionValue(endValue->value()->at(functionIndex), transformOp, boxSize); - } - - // This codepath is used for 2-keyframe animations, so we still need to look in the start - // for a timing function. - CAMediaTimingFunction* timingFunction = timingFunctionForAnimationValue(valueList.at(0), anim); - [basicAnim setTimingFunction:timingFunction]; - - [basicAnim setFromValue:fromValue]; - [basicAnim setToValue:toValue]; - -#if HAVE_MODERN_QUARTZCORE - if (NSString *valueFunctionName = getValueFunctionNameForTransformOperation(transformOp)) - [basicAnim setValueFunction:[CAValueFunction functionWithName:valueFunctionName]]; -#endif - - return true; -} - -bool GraphicsLayerMac::setTransformAnimationKeyframes(const KeyframeValueList& valueList, const Animation* animation, CAKeyframeAnimation* keyframeAnim, int functionIndex, TransformOperation::OperationType transformOpType, bool isMatrixAnimation, const IntSize& boxSize) -{ - RetainPtr<NSMutableArray> keyTimes(AdoptNS, [[NSMutableArray alloc] init]); - RetainPtr<NSMutableArray> values(AdoptNS, [[NSMutableArray alloc] init]); - RetainPtr<NSMutableArray> timingFunctions(AdoptNS, [[NSMutableArray alloc] init]); - - for (unsigned i = 0; i < valueList.size(); ++i) { - const TransformAnimationValue* curValue = static_cast<const TransformAnimationValue*>(valueList.at(i)); - [keyTimes.get() addObject:[NSNumber numberWithFloat:curValue->keyTime()]]; - - if (isMatrixAnimation) { - TransformationMatrix transform; - curValue->value()->apply(boxSize, transform); - - // If any matrix is singular, CA won't animate it correctly. So fall back to software animation - if (!transform.isInvertible()) - return false; - - CATransform3D caTransform; - copyTransform(caTransform, transform); - [values.get() addObject:[NSValue valueWithCATransform3D:caTransform]]; - } else { - const TransformOperation* transformOp = curValue->value()->at(functionIndex); - [values.get() addObject:getTransformFunctionValue(transformOp, transformOpType, boxSize)]; - } - - CAMediaTimingFunction* timingFunction = timingFunctionForAnimationValue(curValue, animation); - [timingFunctions.get() addObject:timingFunction]; - } - - // We toss the last tfArray value because it has to one shorter than the others. - [timingFunctions.get() removeLastObject]; - - [keyframeAnim setKeyTimes:keyTimes.get()]; - [keyframeAnim setValues:values.get()]; - [keyframeAnim setTimingFunctions:timingFunctions.get()]; - -#if HAVE_MODERN_QUARTZCORE - if (NSString *valueFunctionName = getValueFunctionNameForTransformOperation(transformOpType)) - [keyframeAnim setValueFunction:[CAValueFunction functionWithName:valueFunctionName]]; -#endif - return true; -} - -void GraphicsLayerMac::suspendAnimations(double time) -{ - double t = currentTimeToMediaTime(time ? time : currentTime()); - [primaryLayer() setSpeed:0]; - [primaryLayer() setTimeOffset:t]; - - // Suspend the animations on the clones too. - if (LayerMap* layerCloneMap = primaryLayerClones()) { - LayerMap::const_iterator end = layerCloneMap->end(); - for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { - CALayer *currLayer = it->second.get(); - [currLayer setSpeed:0]; - [currLayer setTimeOffset:t]; - } - } -} - -void GraphicsLayerMac::resumeAnimations() -{ - [primaryLayer() setSpeed:1]; - [primaryLayer() setTimeOffset:0]; - - // Resume the animations on the clones too. - if (LayerMap* layerCloneMap = primaryLayerClones()) { - LayerMap::const_iterator end = layerCloneMap->end(); - for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { - CALayer *currLayer = it->second.get(); - [currLayer setSpeed:1]; - [currLayer setTimeOffset:0]; - } - } -} - -CALayer* GraphicsLayerMac::hostLayerForSublayers() const -{ - return m_structuralLayer.get() ? m_structuralLayer.get() : m_layer.get(); -} - -CALayer* GraphicsLayerMac::layerForSuperlayer() const -{ - return m_structuralLayer ? m_structuralLayer.get() : m_layer.get(); -} - -CALayer* GraphicsLayerMac::animatedLayer(AnimatedPropertyID property) const -{ - return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayer.get() : primaryLayer(); -} - -GraphicsLayerMac::LayerMap* GraphicsLayerMac::animatedLayerClones(AnimatedPropertyID property) const -{ - return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayerClones.get() : primaryLayerClones(); -} - -PlatformLayer* GraphicsLayerMac::platformLayer() const -{ - return primaryLayer(); -} - -void GraphicsLayerMac::setDebugBackgroundColor(const Color& color) -{ - BEGIN_BLOCK_OBJC_EXCEPTIONS - - if (color.isValid()) - setLayerBackgroundColor(m_layer.get(), color); - else - clearLayerBackgroundColor(m_layer.get()); - - END_BLOCK_OBJC_EXCEPTIONS -} - -void GraphicsLayerMac::setDebugBorder(const Color& color, float borderWidth) -{ - BEGIN_BLOCK_OBJC_EXCEPTIONS - - if (color.isValid()) { - setLayerBorderColor(m_layer.get(), color); - [m_layer.get() setBorderWidth:borderWidth]; - } else { - clearBorderColor(m_layer.get()); - [m_layer.get() setBorderWidth:0]; - } - - END_BLOCK_OBJC_EXCEPTIONS -} - -FloatSize GraphicsLayerMac::constrainedSize() const -{ - float tileColumns = ceilf(m_size.width() / cTiledLayerTileSize); - float tileRows = ceilf(m_size.height() / cTiledLayerTileSize); - double numTiles = tileColumns * tileRows; - - FloatSize constrainedSize = m_size; - const unsigned cMaxTileCount = 512; - while (numTiles > cMaxTileCount) { - // Constrain the wider dimension. - if (constrainedSize.width() >= constrainedSize.height()) { - tileColumns = max(floorf(cMaxTileCount / tileRows), 1.0f); - constrainedSize.setWidth(tileColumns * cTiledLayerTileSize); - } else { - tileRows = max(floorf(cMaxTileCount / tileColumns), 1.0f); - constrainedSize.setHeight(tileRows * cTiledLayerTileSize); - } - numTiles = tileColumns * tileRows; - } - - return constrainedSize; -} - -bool GraphicsLayerMac::requiresTiledLayer(const FloatSize& size) const -{ - if (!m_drawsContent) - return false; - - // FIXME: catch zero-size height or width here (or earlier)? - return size.width() > cMaxPixelDimension || size.height() > cMaxPixelDimension; -} - -void GraphicsLayerMac::swapFromOrToTiledLayer(bool useTiledLayer) -{ - if (useTiledLayer == m_usingTiledLayer) - return; - - CGSize tileSize = CGSizeMake(cTiledLayerTileSize, cTiledLayerTileSize); - - RetainPtr<CALayer> oldLayer = m_layer.get(); - - Class layerClass = useTiledLayer ? [WebTiledLayer self] : [WebLayer self]; - m_layer.adoptNS([[layerClass alloc] init]); - - m_usingTiledLayer = useTiledLayer; - - if (useTiledLayer) { - WebTiledLayer* tiledLayer = (WebTiledLayer*)m_layer.get(); - [tiledLayer setTileSize:tileSize]; - [tiledLayer setLevelsOfDetail:1]; - [tiledLayer setLevelsOfDetailBias:0]; - [tiledLayer setContentsGravity:@"bottomLeft"]; - -#if !HAVE_MODERN_QUARTZCORE - // Tiled layer has issues with flipped coordinates. - setContentsOrientation(CompositingCoordinatesTopDown); -#endif - } else { -#if !HAVE_MODERN_QUARTZCORE - setContentsOrientation(defaultContentsOrientation()); -#endif - } - - [m_layer.get() setLayerOwner:this]; - safeSetSublayers(m_layer.get(), [oldLayer.get() sublayers]); - - [[oldLayer.get() superlayer] replaceSublayer:oldLayer.get() with:m_layer.get()]; - - updateContentsTransform(); - - updateLayerPosition(); - updateLayerSize(); - updateAnchorPoint(); - updateTransform(); - updateChildrenTransform(); - updateMasksToBounds(); - updateContentsOpaque(); - updateBackfaceVisibility(); - updateLayerBackgroundColor(); - - updateOpacityOnLayer(); - -#ifndef NDEBUG - String name = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + m_name; - [m_layer.get() setName:name]; -#endif - - // move over animations - moveOrCopyAnimationsForProperty(Move, AnimatedPropertyWebkitTransform, oldLayer.get(), m_layer.get()); - moveOrCopyAnimationsForProperty(Move, AnimatedPropertyOpacity, oldLayer.get(), m_layer.get()); - moveOrCopyAnimationsForProperty(Move, AnimatedPropertyBackgroundColor, oldLayer.get(), m_layer.get()); - - // need to tell new layer to draw itself - setNeedsDisplay(); - - updateDebugIndicators(); -} - -GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayerMac::defaultContentsOrientation() const -{ -#if !HAVE_MODERN_QUARTZCORE - // Older QuartzCore does not support -geometryFlipped, so we manually flip the root - // layer geometry, and then flip the contents of each layer back so that the CTM for CG - // is unflipped, allowing it to do the correct font auto-hinting. - return CompositingCoordinatesBottomUp; -#else - return CompositingCoordinatesTopDown; -#endif -} - -void GraphicsLayerMac::updateContentsTransform() -{ -#if !HAVE_MODERN_QUARTZCORE - if (contentsOrientation() == CompositingCoordinatesBottomUp) { - CGAffineTransform contentsTransform = CGAffineTransformMakeScale(1, -1); - contentsTransform = CGAffineTransformTranslate(contentsTransform, 0, -[m_layer.get() bounds].size.height); - [m_layer.get() setContentsTransform:contentsTransform]; - } -#endif -} - -void GraphicsLayerMac::setupContentsLayer(CALayer* contentsLayer) -{ - // Turn off implicit animations on the inner layer. - [contentsLayer setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]]; - [contentsLayer setMasksToBounds:YES]; - - if (defaultContentsOrientation() == CompositingCoordinatesBottomUp) { - CATransform3D flipper = { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, -1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f}; - [contentsLayer setTransform:flipper]; - [contentsLayer setAnchorPoint:CGPointMake(0.0f, 1.0f)]; - } else - [contentsLayer setAnchorPoint:CGPointZero]; - - if (showDebugBorders()) { - setLayerBorderColor(contentsLayer, Color(0, 0, 128, 180)); - [contentsLayer setBorderWidth:1.0f]; - } -} - -CALayer *GraphicsLayerMac::findOrMakeClone(CloneID cloneID, CALayer *sourceLayer, LayerMap* clones, CloneLevel cloneLevel) -{ - if (!sourceLayer) - return 0; - - CALayer *resultLayer; - - // Add with a dummy value to get an iterator for the insertion position, and a boolean that tells - // us whether there's an item there. This technique avoids two hash lookups. - RetainPtr<CALayer> dummy; - pair<LayerMap::iterator, bool> addResult = clones->add(cloneID, dummy); - if (!addResult.second) { - // Value was not added, so it exists already. - resultLayer = addResult.first->second.get(); - } else { - resultLayer = cloneLayer(sourceLayer, cloneLevel); -#ifndef NDEBUG - [resultLayer setName:[NSString stringWithFormat:@"Clone %d of layer %@", cloneID[0U], sourceLayer]]; -#endif - addResult.first->second = resultLayer; - } - - return resultLayer; -} - -void GraphicsLayerMac::ensureCloneLayers(CloneID cloneID, CALayer *& primaryLayer, CALayer *& structuralLayer, CALayer *& contentsLayer, CloneLevel cloneLevel) -{ - structuralLayer = nil; - contentsLayer = nil; - - if (!m_layerClones) - m_layerClones = new LayerMap; - - if (!m_structuralLayerClones && m_structuralLayer) - m_structuralLayerClones = new LayerMap; - - if (!m_contentsLayerClones && m_contentsLayer) - m_contentsLayerClones = new LayerMap; - - primaryLayer = findOrMakeClone(cloneID, m_layer.get(), m_layerClones.get(), cloneLevel); - structuralLayer = findOrMakeClone(cloneID, m_structuralLayer.get(), m_structuralLayerClones.get(), cloneLevel); - contentsLayer = findOrMakeClone(cloneID, m_contentsLayer.get(), m_contentsLayerClones.get(), cloneLevel); -} - -void GraphicsLayerMac::removeCloneLayers() -{ - m_layerClones = 0; - m_structuralLayerClones = 0; - m_contentsLayerClones = 0; -} - -FloatPoint GraphicsLayerMac::positionForCloneRootLayer() const -{ - // This can get called during a sync when we've just removed the m_replicaLayer. - if (!m_replicaLayer) - return FloatPoint(); - - FloatPoint replicaPosition = m_replicaLayer->replicatedLayerPosition(); - return FloatPoint(replicaPosition.x() + m_anchorPoint.x() * m_size.width(), - replicaPosition.y() + m_anchorPoint.y() * m_size.height()); -} - -void GraphicsLayerMac::propagateLayerChangeToReplicas() -{ - for (GraphicsLayer* currLayer = this; currLayer; currLayer = currLayer->parent()) { - GraphicsLayerMac* currLayerCA = static_cast<GraphicsLayerMac*>(currLayer); - if (!currLayerCA->hasCloneLayers()) - break; - - if (currLayerCA->replicaLayer()) - static_cast<GraphicsLayerMac*>(currLayerCA->replicaLayer())->noteLayerPropertyChanged(ReplicatedLayerChanged); - } -} - -CALayer *GraphicsLayerMac::fetchCloneLayers(GraphicsLayer* replicaRoot, ReplicaState& replicaState, CloneLevel cloneLevel) -{ - CALayer *primaryLayer; - CALayer *structuralLayer; - CALayer *contentsLayer; - ensureCloneLayers(replicaState.cloneID(), primaryLayer, structuralLayer, contentsLayer, cloneLevel); - - if (m_maskLayer) { - CALayer *maskClone = static_cast<GraphicsLayerMac*>(m_maskLayer)->fetchCloneLayers(replicaRoot, replicaState, IntermediateCloneLevel); - [primaryLayer setMask:maskClone]; - } - - if (m_replicatedLayer) { - // We are a replica being asked for clones of our layers. - CALayer *replicaRoot = replicatedLayerRoot(replicaState); - if (!replicaRoot) - return nil; - - if (structuralLayer) { - [structuralLayer insertSublayer:replicaRoot atIndex:0]; - return structuralLayer; - } - - [primaryLayer insertSublayer:replicaRoot atIndex:0]; - return primaryLayer; - } - - const Vector<GraphicsLayer*>& childLayers = children(); - NSMutableArray* clonalSublayers = nil; - - CALayer *replicaLayer = nil; - if (m_replicaLayer && m_replicaLayer != replicaRoot) { - // We have nested replicas. Ask the replica layer for a clone of its contents. - replicaState.setBranchType(ReplicaState::ReplicaBranch); - replicaLayer = static_cast<GraphicsLayerMac*>(m_replicaLayer)->fetchCloneLayers(replicaRoot, replicaState, RootCloneLevel); - replicaState.setBranchType(ReplicaState::ChildBranch); - } - - if (replicaLayer || structuralLayer || contentsLayer || childLayers.size() > 0) { - clonalSublayers = [[NSMutableArray alloc] init]; - - if (structuralLayer) { - // Replicas render behind the actual layer content. - if (replicaLayer) - [clonalSublayers addObject:replicaLayer]; - - // Add the primary layer next. Even if we have negative z-order children, the primary layer always comes behind. - [clonalSublayers addObject:primaryLayer]; - } else if (contentsLayer) { - // FIXME: add the contents layer in the correct order with negative z-order children. - // This does not cause visible rendering issues because currently contents layers are only used - // for replaced elements that don't have children. - [clonalSublayers addObject:contentsLayer]; - } - - replicaState.push(ReplicaState::ChildBranch); - - size_t numChildren = childLayers.size(); - for (size_t i = 0; i < numChildren; ++i) { - GraphicsLayerMac* curChild = static_cast<GraphicsLayerMac*>(childLayers[i]); - - CALayer *childLayer = curChild->fetchCloneLayers(replicaRoot, replicaState, IntermediateCloneLevel); - if (childLayer) - [clonalSublayers addObject:childLayer]; - } - - replicaState.pop(); - - [clonalSublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)]; - } - - CALayer *result; - if (structuralLayer) { - [structuralLayer setSublayers:clonalSublayers]; - - if (contentsLayer) { - // If we have a transform layer, then the contents layer is parented in the - // primary layer (which is itself a child of the transform layer). - [primaryLayer setSublayers:nil]; - [primaryLayer addSublayer:contentsLayer]; - } - - result = structuralLayer; - } else { - [primaryLayer setSublayers:clonalSublayers]; - result = primaryLayer; - } - - [clonalSublayers release]; - return result; -} - -CALayer *GraphicsLayerMac::cloneLayer(CALayer *layer, CloneLevel cloneLevel) -{ - static Class transformLayerClass = NSClassFromString(@"CATransformLayer"); - CALayer *newLayer = nil; - if ([layer isKindOfClass:transformLayerClass]) - newLayer = [transformLayerClass layer]; - else - newLayer = [CALayer layer]; - - [newLayer setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]]; - - [newLayer setPosition:[layer position]]; - [newLayer setBounds:[layer bounds]]; - [newLayer setAnchorPoint:[layer anchorPoint]]; -#if HAVE_MODERN_QUARTZCORE - [newLayer setAnchorPointZ:[layer anchorPointZ]]; -#endif - [newLayer setTransform:[layer transform]]; - [newLayer setSublayerTransform:[layer sublayerTransform]]; - [newLayer setContents:[layer contents]]; - [newLayer setMasksToBounds:[layer masksToBounds]]; - [newLayer setDoubleSided:[layer isDoubleSided]]; - [newLayer setOpaque:[layer isOpaque]]; - [newLayer setBackgroundColor:[layer backgroundColor]]; - - if (cloneLevel == IntermediateCloneLevel) { - [newLayer setOpacity:[layer opacity]]; - moveOrCopyAnimationsForProperty(Copy, AnimatedPropertyWebkitTransform, layer, newLayer); - moveOrCopyAnimationsForProperty(Copy, AnimatedPropertyOpacity, layer, newLayer); - } - - if (showDebugBorders()) { - setLayerBorderColor(newLayer, Color(255, 122, 251)); - [newLayer setBorderWidth:2]; - } - - return newLayer; -} - -void GraphicsLayerMac::setOpacityInternal(float accumulatedOpacity) -{ - LayerMap* layerCloneMap = 0; - - if (preserves3D()) { - [m_layer.get() setOpacity:accumulatedOpacity]; - layerCloneMap = m_layerClones.get(); - } else { - [primaryLayer() setOpacity:accumulatedOpacity]; - layerCloneMap = primaryLayerClones(); - } - - if (layerCloneMap) { - LayerMap::const_iterator end = layerCloneMap->end(); - for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { - if (m_replicaLayer && isReplicatedRootClone(it->first)) - continue; - CALayer *currLayer = it->second.get(); - [currLayer setOpacity:m_opacity]; - } - } -} - -void GraphicsLayerMac::updateOpacityOnLayer() -{ -#if !HAVE_MODERN_QUARTZCORE - // Distribute opacity either to our own layer or to our children. We pass in the - // contribution from our parent(s). - distributeOpacity(parent() ? parent()->accumulatedOpacity() : 1); -#else - [primaryLayer() setOpacity:m_opacity]; - - if (LayerMap* layerCloneMap = primaryLayerClones()) { - LayerMap::const_iterator end = layerCloneMap->end(); - for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { - if (m_replicaLayer && isReplicatedRootClone(it->first)) - continue; - - CALayer *currLayer = it->second.get(); - [currLayer setOpacity:m_opacity]; - } - - } -#endif -} - -void GraphicsLayerMac::noteSublayersChanged() -{ - noteLayerPropertyChanged(ChildrenChanged); - propagateLayerChangeToReplicas(); -} - -void GraphicsLayerMac::noteLayerPropertyChanged(LayerChangeFlags flags) -{ - if (!m_uncommittedChanges && m_client) - m_client->notifySyncRequired(this); - - m_uncommittedChanges |= flags; -} - -} // namespace WebCore - -#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm index 1538e07..2361f6a 100644 --- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm +++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm @@ -255,7 +255,7 @@ void MediaPlayerPrivateQTKit::createQTMovie(const String& url) #endif nil]; -#if defined(BUILDING_ON_SNOW_LEOPARD) +#if !defined(BUILDING_ON_LEOPARD) CFDictionaryRef proxySettings = CFNetworkCopySystemProxySettings(); CFArrayRef proxiesForURL = CFNetworkCopyProxiesForURL((CFURLRef)cocoaURL, proxySettings); BOOL willUseProxy = YES; @@ -623,7 +623,7 @@ void MediaPlayerPrivateQTKit::resumeLoad() { m_delayingLoad = false; - if (m_movieURL) + if (!m_movieURL.isNull()) loadInternal(m_movieURL); } diff --git a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm index e1d3f43..92585c6 100644 --- a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm +++ b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm @@ -357,9 +357,13 @@ void SimpleFontData::platformCharWidthInit() void SimpleFontData::platformDestroy() { - if (m_smallCapsFontData && !isCustomFont()) { - fontCache()->releaseFontData(m_smallCapsFontData); - m_smallCapsFontData = 0; + if (!isCustomFont() && m_derivedFontData) { + // These come from the cache. + if (m_derivedFontData->smallCaps) + fontCache()->releaseFontData(m_derivedFontData->smallCaps.leakPtr()); + + if (m_derivedFontData->emphasisMark) + fontCache()->releaseFontData(m_derivedFontData->emphasisMark.leakPtr()); } #ifdef BUILDING_ON_TIGER @@ -373,41 +377,60 @@ void SimpleFontData::platformDestroy() #endif } -SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const +SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const { - if (!m_smallCapsFontData) { - if (isCustomFont()) { - FontPlatformData smallCapsFontData(m_platformData); - smallCapsFontData.m_size = smallCapsFontData.m_size * smallCapsFontSizeMultiplier; - m_smallCapsFontData = new SimpleFontData(smallCapsFontData, true, false); - } else { - BEGIN_BLOCK_OBJC_EXCEPTIONS; - float size = m_platformData.size() * smallCapsFontSizeMultiplier; - FontPlatformData smallCapsFont([[NSFontManager sharedFontManager] convertFont:m_platformData.font() toSize:size], size); - - // AppKit resets the type information (screen/printer) when you convert a font to a different size. - // We have to fix up the font that we're handed back. - smallCapsFont.setFont(fontDescription.usePrinterFont() ? [smallCapsFont.font() printerFont] : [smallCapsFont.font() screenFont]); - - if (smallCapsFont.font()) { - NSFontManager *fontManager = [NSFontManager sharedFontManager]; - NSFontTraitMask fontTraits = [fontManager traitsOfFont:m_platformData.font()]; - - if (m_platformData.m_syntheticBold) - fontTraits |= NSBoldFontMask; - if (m_platformData.m_syntheticOblique) - fontTraits |= NSItalicFontMask; - - NSFontTraitMask smallCapsFontTraits = [fontManager traitsOfFont:smallCapsFont.font()]; - smallCapsFont.m_syntheticBold = (fontTraits & NSBoldFontMask) && !(smallCapsFontTraits & NSBoldFontMask); - smallCapsFont.m_syntheticOblique = (fontTraits & NSItalicFontMask) && !(smallCapsFontTraits & NSItalicFontMask); - - m_smallCapsFontData = fontCache()->getCachedFontData(&smallCapsFont); - } - END_BLOCK_OBJC_EXCEPTIONS; - } + if (isCustomFont()) { + FontPlatformData scaledFontData(m_platformData); + scaledFontData.m_size = scaledFontData.m_size * scaleFactor; + return new SimpleFontData(scaledFontData, true, false); + } + + BEGIN_BLOCK_OBJC_EXCEPTIONS; + float size = m_platformData.size() * scaleFactor; + FontPlatformData scaledFontData([[NSFontManager sharedFontManager] convertFont:m_platformData.font() toSize:size], size); + + // AppKit resets the type information (screen/printer) when you convert a font to a different size. + // We have to fix up the font that we're handed back. + scaledFontData.setFont(fontDescription.usePrinterFont() ? [scaledFontData.font() printerFont] : [scaledFontData.font() screenFont]); + + if (scaledFontData.font()) { + NSFontManager *fontManager = [NSFontManager sharedFontManager]; + NSFontTraitMask fontTraits = [fontManager traitsOfFont:m_platformData.font()]; + + if (m_platformData.m_syntheticBold) + fontTraits |= NSBoldFontMask; + if (m_platformData.m_syntheticOblique) + fontTraits |= NSItalicFontMask; + + NSFontTraitMask scaledFontTraits = [fontManager traitsOfFont:scaledFontData.font()]; + scaledFontData.m_syntheticBold = (fontTraits & NSBoldFontMask) && !(scaledFontTraits & NSBoldFontMask); + scaledFontData.m_syntheticOblique = (fontTraits & NSItalicFontMask) && !(scaledFontTraits & NSItalicFontMask); + + return fontCache()->getCachedFontData(&scaledFontData); } - return m_smallCapsFontData; + END_BLOCK_OBJC_EXCEPTIONS; + + return 0; +} + +SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const +{ + if (!m_derivedFontData) + m_derivedFontData = DerivedFontData::create(isCustomFont()); + if (!m_derivedFontData->smallCaps) + m_derivedFontData->smallCaps = scaledFontData(fontDescription, smallCapsFontSizeMultiplier); + + return m_derivedFontData->smallCaps.get(); +} + +SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const +{ + if (!m_derivedFontData) + m_derivedFontData = DerivedFontData::create(isCustomFont()); + if (!m_derivedFontData->emphasisMark) + m_derivedFontData->emphasisMark = scaledFontData(fontDescription, .5f); + + return m_derivedFontData->emphasisMark.get(); } bool SimpleFontData::containsCharacters(const UChar* characters, int length) const diff --git a/WebCore/platform/graphics/mac/WebLayer.h b/WebCore/platform/graphics/mac/WebLayer.h index 3a91f04..62d69fc 100644 --- a/WebCore/platform/graphics/mac/WebLayer.h +++ b/WebCore/platform/graphics/mac/WebLayer.h @@ -34,14 +34,6 @@ namespace WebCore { class GraphicsLayer; } -// Category implemented by WebLayer and WebTiledLayer. -@interface CALayer(WebLayerAdditions) - -- (void)setLayerOwner:(WebCore::GraphicsLayer*)layer; -- (WebCore::GraphicsLayer*)layerOwner; - -@end - #if defined(BUILDING_ON_LEOPARD) @interface CALayer(WebLayerInternal) - (CGAffineTransform)contentsTransform; @@ -51,7 +43,6 @@ namespace WebCore { @interface WebLayer : CALayer { - WebCore::GraphicsLayer* m_layerOwner; } @end diff --git a/WebCore/platform/graphics/mac/WebLayer.mm b/WebCore/platform/graphics/mac/WebLayer.mm index 9bb8212..128e63b 100644 --- a/WebCore/platform/graphics/mac/WebLayer.mm +++ b/WebCore/platform/graphics/mac/WebLayer.mm @@ -30,7 +30,8 @@ #import "WebLayer.h" #import "GraphicsContext.h" -#import "GraphicsLayer.h" +#import "GraphicsLayerCA.h" +#import "PlatformCALayer.h" #import <objc/objc-runtime.h> #import <QuartzCore/QuartzCore.h> #import <wtf/UnusedParam.h> @@ -62,6 +63,11 @@ void drawLayerContents(CGContextRef context, CALayer *layer, WebCore::GraphicsLa GraphicsContext graphicsContext(context); + if (!layerContents->contentsOpaque()) { + // Turn off font smoothing to improve the appearance of text rendered onto a transparent background. + graphicsContext.setShouldSmoothFonts(false); + } + // It's important to get the clip from the context, because it may be significantly // smaller than the layer bounds (e.g. tiled layers) CGRect clipBounds = CGContextGetClipBoundingBox(context); @@ -146,58 +152,39 @@ void setLayerNeedsDisplayInRect(CALayer *layer, WebCore::GraphicsLayer* layerCon return nil; } -// Implement this so presentationLayer can get our custom attributes -- (id)initWithLayer:(id)layer -{ - if ((self = [super initWithLayer:layer])) - m_layerOwner = [(WebLayer*)layer layerOwner]; - - return self; -} - - (void)setNeedsDisplay { - if (m_layerOwner && m_layerOwner->client() && m_layerOwner->drawsContent()) + PlatformCALayer* layer = PlatformCALayer::platformCALayer(self); + if (layer && layer->owner() && layer->owner()->client() && layer->owner()->drawsContent()) [super setNeedsDisplay]; } - (void)setNeedsDisplayInRect:(CGRect)dirtyRect { - setLayerNeedsDisplayInRect(self, m_layerOwner, dirtyRect); + PlatformCALayer* layer = PlatformCALayer::platformCALayer(self); + if (layer) + setLayerNeedsDisplayInRect(self, layer->owner(), dirtyRect); } - (void)display { [super display]; - if (m_layerOwner) - m_layerOwner->didDisplay(self); + PlatformCALayer* layer = PlatformCALayer::platformCALayer(self); + if (layer && layer->owner()) + layer->owner()->didDisplay(self); } - (void)drawInContext:(CGContextRef)context { - drawLayerContents(context, self, m_layerOwner); + PlatformCALayer* layer = PlatformCALayer::platformCALayer(self); + if (layer) + drawLayerContents(context, self, layer->owner()); } @end // implementation WebLayer #pragma mark - -@implementation WebLayer(WebLayerAdditions) - -- (void)setLayerOwner:(GraphicsLayer*)aLayer -{ - m_layerOwner = aLayer; -} - -- (GraphicsLayer*)layerOwner -{ - return m_layerOwner; -} - -@end - -#pragma mark - - #ifndef NDEBUG @implementation CALayer(ExtendedDescription) diff --git a/WebCore/platform/graphics/mac/WebTiledLayer.h b/WebCore/platform/graphics/mac/WebTiledLayer.h index 1c9144d..6f559e3 100644 --- a/WebCore/platform/graphics/mac/WebTiledLayer.h +++ b/WebCore/platform/graphics/mac/WebTiledLayer.h @@ -32,7 +32,6 @@ @interface WebTiledLayer : CATiledLayer { - WebCore::GraphicsLayer* m_layerOwner; } // implements WebLayerAdditions diff --git a/WebCore/platform/graphics/mac/WebTiledLayer.mm b/WebCore/platform/graphics/mac/WebTiledLayer.mm index 72128ad..bf35431 100644 --- a/WebCore/platform/graphics/mac/WebTiledLayer.mm +++ b/WebCore/platform/graphics/mac/WebTiledLayer.mm @@ -30,7 +30,8 @@ #import "WebTiledLayer.h" #import "GraphicsContext.h" -#import "GraphicsLayer.h" +#import "GraphicsLayerCA.h" +#import "PlatformCALayer.h" #import <wtf/UnusedParam.h> using namespace WebCore; @@ -56,54 +57,35 @@ using namespace WebCore; return nil; } -// Implement this so presentationLayer can get our custom attributes -- (id)initWithLayer:(id)layer -{ - if ((self = [super initWithLayer:layer])) - m_layerOwner = [(WebLayer*)layer layerOwner]; - - return self; -} - - (void)setNeedsDisplay { - if (m_layerOwner && m_layerOwner->client() && m_layerOwner->drawsContent()) + PlatformCALayer* layer = PlatformCALayer::platformCALayer(self); + if (layer && layer->owner() && layer->owner()->client() && layer->owner()->drawsContent()) [super setNeedsDisplay]; } - (void)setNeedsDisplayInRect:(CGRect)dirtyRect { - setLayerNeedsDisplayInRect(self, m_layerOwner, dirtyRect); + PlatformCALayer* layer = PlatformCALayer::platformCALayer(self); + if (layer) + setLayerNeedsDisplayInRect(self, layer->owner(), dirtyRect); } - (void)display { [super display]; - if (m_layerOwner) - m_layerOwner->didDisplay(self); + PlatformCALayer* layer = PlatformCALayer::platformCALayer(self); + if (layer && layer->owner()) + layer->owner()->didDisplay(self); } - (void)drawInContext:(CGContextRef)context { - drawLayerContents(context, self, m_layerOwner); + PlatformCALayer* layer = PlatformCALayer::platformCALayer(self); + if (layer) + drawLayerContents(context, self, layer->owner()); } @end // implementation WebTiledLayer -#pragma mark - - -@implementation WebTiledLayer(LayerMacAdditions) - -- (void)setLayerOwner:(GraphicsLayer*)aLayer -{ - m_layerOwner = aLayer; -} - -- (GraphicsLayer*)layerOwner -{ - return m_layerOwner; -} - -@end - #endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp b/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp index a6fa5d9..4215d12 100644 --- a/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp +++ b/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp @@ -76,10 +76,20 @@ bool Extensions3DOpenGL::supports(const String& name) return m_availableExtensions.contains("GL_EXT_framebuffer_blit"); if (name == "GL_ANGLE_framebuffer_multisample") return m_availableExtensions.contains("GL_EXT_framebuffer_multisample"); - + + // If GL_ARB_texture_float is available then we report GL_OES_texture_float and + // GL_OES_texture_half_float as available. + if (name == "GL_OES_texture_float" || name == "GL_OES_texture_half_float") + return m_availableExtensions.contains("GL_ARB_texture_float"); + return m_availableExtensions.contains(name); } +void Extensions3DOpenGL::ensureEnabled(const String& name) +{ + ASSERT_UNUSED(name, supports(name)); +} + int Extensions3DOpenGL::getGraphicsResetStatusARB() { return GraphicsContext3D::NO_ERROR; diff --git a/WebCore/platform/graphics/opengl/Extensions3DOpenGL.h b/WebCore/platform/graphics/opengl/Extensions3DOpenGL.h index 0fbe022..59f8180 100644 --- a/WebCore/platform/graphics/opengl/Extensions3DOpenGL.h +++ b/WebCore/platform/graphics/opengl/Extensions3DOpenGL.h @@ -40,6 +40,7 @@ public: // Extensions3D methods. virtual bool supports(const String&); + virtual void ensureEnabled(const String&); virtual int getGraphicsResetStatusARB(); virtual void blitFramebuffer(long srcX0, long srcY0, long srcX1, long srcY1, long dstX0, long dstY0, long dstX1, long dstY1, unsigned long mask, unsigned long filter); virtual void renderbufferStorageMultisample(unsigned long target, unsigned long samples, unsigned long internalformat, unsigned long width, unsigned long height); diff --git a/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp b/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp index d295abb..aa3b60e 100644 --- a/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp +++ b/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp @@ -125,7 +125,10 @@ void GraphicsContext3D::paintRenderingResultsToCanvas(CanvasRenderingContext* co void GraphicsContext3D::reshape(int width, int height) { - if (width == m_currentWidth && height == m_currentHeight || !m_contextObj) + if (!m_contextObj) + return; + + if (width == m_currentWidth && height == m_currentHeight) return; m_currentWidth = width; @@ -1324,9 +1327,20 @@ long GraphicsContext3D::getVertexAttribOffset(unsigned long index, unsigned long int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, void* pixels) { + if (width && height && !pixels) { + synthesizeGLError(INVALID_VALUE); + return 1; + } makeContextCurrent(); + unsigned openGLInternalFormat = internalformat; + if (type == GL_FLOAT) { + if (format == GL_RGBA) + openGLInternalFormat = GL_RGBA32F_ARB; + else if (format == GL_RGB) + openGLInternalFormat = GL_RGB32F_ARB; + } - ::glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + ::glTexImage2D(target, level, openGLInternalFormat, width, height, border, format, type, pixels); return 0; } diff --git a/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp b/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp index 0d16d4d..633ca75 100644 --- a/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp +++ b/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp @@ -21,7 +21,6 @@ #include "GraphicsContext.h" #include "AffineTransform.h" -#include "GraphicsContextPrivate.h" #include "KURL.h" #include "NotImplemented.h" #include "PainterOpenVG.h" @@ -49,16 +48,14 @@ public: } }; -GraphicsContext::GraphicsContext(SurfaceOpenVG* surface) - : m_common(createGraphicsContextPrivate()) - , m_data(surface ? new GraphicsContextPlatformPrivate(surface) : 0) +void GraphicsContext::platformInit(SurfaceOpenVG* surface) { + m_data = surface ? new GraphicsContextPlatformPrivate(surface) : 0; setPaintingDisabled(!surface); } -GraphicsContext::~GraphicsContext() +void GraphicsContext::platformDestroy() { - destroyGraphicsContextPrivate(m_common); delete m_data; } @@ -139,28 +136,20 @@ void GraphicsContext::drawConvexPolygon(size_t numPoints, const FloatPoint* poin UNUSED_PARAM(shouldAntialias); // FIXME } -void GraphicsContext::fillPath() +void GraphicsContext::fillPath(const Path& path) { if (paintingDisabled()) return; - m_data->drawPath(VG_FILL_PATH, m_common->state.fillRule); + m_data->drawPath(path, VG_FILL_PATH, m_state.fillRule); } -void GraphicsContext::strokePath() +void GraphicsContext::strokePath(const Path& path) { if (paintingDisabled()) return; - m_data->drawPath(VG_STROKE_PATH, m_common->state.fillRule); -} - -void GraphicsContext::drawPath() -{ - if (paintingDisabled()) - return; - - m_data->drawPath(VG_FILL_PATH | VG_STROKE_PATH, m_common->state.fillRule); + m_data->drawPath(path, VG_STROKE_PATH, m_state.fillRule); } void GraphicsContext::fillRect(const FloatRect& rect) @@ -197,22 +186,6 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef UNUSED_PARAM(colorSpace); // FIXME } -void GraphicsContext::beginPath() -{ - if (paintingDisabled()) - return; - - m_data->beginPath(); -} - -void GraphicsContext::addPath(const Path& path) -{ - if (paintingDisabled()) - return; - - m_data->addPath(path); -} - void GraphicsContext::clip(const FloatRect& rect) { if (paintingDisabled()) @@ -221,12 +194,12 @@ void GraphicsContext::clip(const FloatRect& rect) m_data->intersectClipRect(rect); } -void GraphicsContext::clipPath(WindRule clipRule) +void GraphicsContext::clipPath(const Path& path, WindRule clipRule) { if (paintingDisabled()) return; - m_data->clipPath(*(m_data->currentPath()), PainterOpenVG::IntersectClip, clipRule); + m_data->clipPath(path, PainterOpenVG::IntersectClip, clipRule); } void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color) @@ -391,7 +364,7 @@ void GraphicsContext::setAlpha(float opacity) m_data->setOpacity(opacity); } -void GraphicsContext::setCompositeOperation(CompositeOperator op) +void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op) { if (paintingDisabled()) return; @@ -404,7 +377,7 @@ void GraphicsContext::clip(const Path& path) if (paintingDisabled()) return; - m_data->clipPath(path, PainterOpenVG::IntersectClip, m_common->state.fillRule); + m_data->clipPath(path, PainterOpenVG::IntersectClip, m_state.fillRule); } void GraphicsContext::canvasClip(const Path& path) @@ -417,7 +390,7 @@ void GraphicsContext::clipOut(const Path& path) if (paintingDisabled()) return; - m_data->clipPath(path, PainterOpenVG::SubtractClip, m_common->state.fillRule); + m_data->clipPath(path, PainterOpenVG::SubtractClip, m_state.fillRule); } void GraphicsContext::scale(const FloatSize& scaleFactors) @@ -451,7 +424,7 @@ void GraphicsContext::clipOut(const IntRect& rect) Path path; path.addRect(rect); - m_data->clipPath(path, PainterOpenVG::SubtractClip, m_common->state.fillRule); + m_data->clipPath(path, PainterOpenVG::SubtractClip, m_state.fillRule); } void GraphicsContext::clipToImageBuffer(const FloatRect& rect, const ImageBuffer* imageBuffer) @@ -474,7 +447,7 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness path.addEllipse(FloatRect(rect.x() + thickness, rect.y() + thickness, rect.width() - (thickness * 2), rect.height() - (thickness * 2))); - m_data->clipPath(path, PainterOpenVG::IntersectClip, m_common->state.fillRule); + m_data->clipPath(path, PainterOpenVG::IntersectClip, m_state.fillRule); } void GraphicsContext::concatCTM(const AffineTransform& transformation) diff --git a/WebCore/platform/graphics/openvg/PainterOpenVG.cpp b/WebCore/platform/graphics/openvg/PainterOpenVG.cpp index b2f2302..54937a4 100644 --- a/WebCore/platform/graphics/openvg/PainterOpenVG.cpp +++ b/WebCore/platform/graphics/openvg/PainterOpenVG.cpp @@ -123,7 +123,7 @@ struct PlatformPainterState { DashArray strokeDashArray; float strokeDashOffset; - int textDrawingMode; + TextDrawingModeFlags textDrawingMode; bool antialiasingEnabled; PlatformPainterState() @@ -141,7 +141,7 @@ struct PlatformPainterState { , strokeLineJoin(MiterJoin) , strokeMiterLimit(4.0) , strokeDashOffset(0.0) - , textDrawingMode(cTextFill) + , textDrawingMode(TextModeFill) , antialiasingEnabled(true) { } @@ -399,14 +399,12 @@ struct PlatformPainterState { PainterOpenVG::PainterOpenVG() : m_state(0) , m_surface(0) - , m_currentPath(0) { } PainterOpenVG::PainterOpenVG(SurfaceOpenVG* surface) : m_state(0) , m_surface(0) - , m_currentPath(0) { ASSERT(surface); begin(surface); @@ -415,7 +413,6 @@ PainterOpenVG::PainterOpenVG(SurfaceOpenVG* surface) PainterOpenVG::~PainterOpenVG() { end(); - delete m_currentPath; } void PainterOpenVG::begin(SurfaceOpenVG* surface) @@ -656,13 +653,13 @@ void PainterOpenVG::setFillColor(const Color& color) setVGSolidColor(VG_FILL_PATH, color); } -int PainterOpenVG::textDrawingMode() const +TextDrawingModeFlags PainterOpenVG::textDrawingMode() const { ASSERT(m_state); return m_state->textDrawingMode; } -void PainterOpenVG::setTextDrawingMode(int mode) +void PainterOpenVG::setTextDrawingMode(TextDrawingModeFlags mode) { ASSERT(m_state); m_state->textDrawingMode = mode; @@ -717,26 +714,7 @@ void PainterOpenVG::translate(float dx, float dy) setTransformation(transformation); } -void PainterOpenVG::beginPath() -{ - delete m_currentPath; - m_currentPath = new Path(); -} - -void PainterOpenVG::addPath(const Path& path) -{ - m_currentPath->platformPath()->makeCompatibleContextCurrent(); - - vgAppendPath(m_currentPath->platformPath()->vgPath(), path.platformPath()->vgPath()); - ASSERT_VG_NO_ERROR(); -} - -Path* PainterOpenVG::currentPath() const -{ - return m_currentPath; -} - -void PainterOpenVG::drawPath(VGbitfield specifiedPaintModes, WindRule fillRule) +void PainterOpenVG::drawPath(const Path& path, VGbitfield specifiedPaintModes, WindRule fillRule) { ASSERT(m_state); @@ -754,7 +732,7 @@ void PainterOpenVG::drawPath(VGbitfield specifiedPaintModes, WindRule fillRule) m_surface->makeCurrent(); vgSeti(VG_FILL_RULE, toVGFillRule(fillRule)); - vgDrawPath(m_currentPath->platformPath()->vgPath(), paintModes); + vgDrawPath(path.platformPath()->vgPath(), paintModes); ASSERT_VG_NO_ERROR(); } @@ -1136,11 +1114,11 @@ void PainterOpenVG::drawText(VGFont vgFont, Vector<VGuint>& characters, VGfloat* VGbitfield paintModes = 0; - if (m_state->textDrawingMode & cTextClip) + if (m_state->textDrawingMode & TextModeClip) return; // unsupported for every port except CG at the time of writing - if (m_state->textDrawingMode & cTextFill && !m_state->fillDisabled()) + if (m_state->textDrawingMode & TextModeFill && !m_state->fillDisabled()) paintModes |= VG_FILL_PATH; - if (m_state->textDrawingMode & cTextStroke && !m_state->strokeDisabled()) + if (m_state->textDrawingMode & TextModeStroke && !m_state->strokeDisabled()) paintModes |= VG_STROKE_PATH; m_surface->makeCurrent(); diff --git a/WebCore/platform/graphics/openvg/PainterOpenVG.h b/WebCore/platform/graphics/openvg/PainterOpenVG.h index e4c6688..24fd8a0 100644 --- a/WebCore/platform/graphics/openvg/PainterOpenVG.h +++ b/WebCore/platform/graphics/openvg/PainterOpenVG.h @@ -111,10 +111,7 @@ public: void rotate(float radians); void translate(float dx, float dy); - void beginPath(); - void addPath(const Path&); - Path* currentPath() const; - void drawPath(VGbitfield paintModes = (VG_STROKE_PATH | VG_FILL_PATH), WindRule fillRule = RULE_NONZERO); + void drawPath(const Path&, VGbitfield paintModes = (VG_STROKE_PATH | VG_FILL_PATH), WindRule fillRule = RULE_NONZERO); void intersectClipRect(const FloatRect&); void clipPath(const Path&, PainterOpenVG::ClipOperation, WindRule clipRule = RULE_NONZERO); @@ -137,7 +134,6 @@ private: Vector<PlatformPainterState*> m_stateStack; PlatformPainterState* m_state; SurfaceOpenVG* m_surface; - Path* m_currentPath; }; } diff --git a/WebCore/platform/graphics/pango/SimpleFontDataPango.cpp b/WebCore/platform/graphics/pango/SimpleFontDataPango.cpp index bdfe237..d0bf836 100644 --- a/WebCore/platform/graphics/pango/SimpleFontDataPango.cpp +++ b/WebCore/platform/graphics/pango/SimpleFontDataPango.cpp @@ -76,19 +76,34 @@ void SimpleFontData::platformCharWidthInit() void SimpleFontData::platformDestroy() { - delete m_smallCapsFontData; - m_smallCapsFontData = 0; +} + +SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const +{ + FontDescription desc = FontDescription(fontDescription); + desc.setSpecifiedSize(scaleFactor * fontDescription.computedSize()); + FontPlatformData platformData(desc, desc.family().family()); + return new SimpleFontData(platformData); } SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const { - if (!m_smallCapsFontData) { - FontDescription desc = FontDescription(fontDescription); - desc.setSpecifiedSize(0.70f * fontDescription.computedSize()); - FontPlatformData platformData(desc, desc.family().family()); - m_smallCapsFontData = new SimpleFontData(platformData); - } - return m_smallCapsFontData; + if (!m_derivedFontData) + m_derivedFontData = DerivedFontData::create(isCustomFont()); + if (!m_derivedFontData->smallCaps) + m_derivedFontData->smallCaps = scaledFontData(fontDescription, .7); + + return m_derivedFontData->smallCaps.get(); +} + +SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const +{ + if (!m_derivedFontData) + m_derivedFontData = DerivedFontData::create(isCustomFont()); + if (!m_derivedFontData->emphasisMark) + m_derivedFontData->emphasisMark = scaledFontData(fontDescription, .5); + + return m_derivedFontData->emphasisMark.get(); } bool SimpleFontData::containsCharacters(const UChar* characters, int length) const diff --git a/WebCore/platform/graphics/qt/ContextShadowQt.cpp b/WebCore/platform/graphics/qt/ContextShadowQt.cpp index f7c70f6..cb53b24 100644 --- a/WebCore/platform/graphics/qt/ContextShadowQt.cpp +++ b/WebCore/platform/graphics/qt/ContextShadowQt.cpp @@ -100,10 +100,20 @@ void ShadowBuffer::timerEvent(QTimerEvent* event) QObject::timerEvent(event); } +TransformationMatrix ContextShadow::getTransformationMatrixFromContext(PlatformContext context) +{ + const QTransform& transform = context->transform(); + return TransformationMatrix(transform.m11(), transform.m12(), transform.m21(), + transform.m22(), transform.dx(), transform.dy()); +} + Q_GLOBAL_STATIC(ShadowBuffer, scratchShadowBuffer) PlatformContext ContextShadow::beginShadowLayer(PlatformContext p, const FloatRect& layerArea) { + // Set m_blurDistance. + adjustBlurDistance(p); + QRect clipRect; if (p->hasClipping()) #if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0) @@ -114,25 +124,22 @@ PlatformContext ContextShadow::beginShadowLayer(PlatformContext p, const FloatRe else clipRect = p->transform().inverted().mapRect(p->window()); - m_unscaledLayerRect = layerArea; - calculateLayerBoundingRect(layerArea, IntRect(clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height())); + // Set m_layerOrigin, m_layerContextTranslation, m_sourceRect. + IntRect clip(clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height()); + IntRect layerRect = calculateLayerBoundingRect(p, layerArea, clip); // Don't paint if we are totally outside the clip region. - if (m_layerRect.isEmpty()) + if (layerRect.isEmpty()) return 0; ShadowBuffer* shadowBuffer = scratchShadowBuffer(); - QImage* shadowImage = shadowBuffer->scratchImage(m_layerRect.size()); + QImage* shadowImage = shadowBuffer->scratchImage(layerRect.size()); m_layerImage = QImage(*shadowImage); m_layerContext = new QPainter; m_layerContext->begin(&m_layerImage); m_layerContext->setFont(p->font()); - m_layerContext->translate(m_offset.width(), m_offset.height()); - - // The origin is now the top left corner of the scratch image. - m_layerContext->translate(-m_layerRect.x(), -m_layerRect.y()); - + m_layerContext->translate(m_layerContextTranslation); return m_layerContext; } @@ -155,13 +162,7 @@ void ContextShadow::endShadowLayer(PlatformContext p) p.end(); } - const QTransform transform = p->transform(); - if (transform.isScaling()) { - qreal x = m_unscaledLayerRect.x() + m_offset.width() / transform.m11() - m_blurDistance; - qreal y = m_unscaledLayerRect.y() + m_offset.height() / transform.m22() - m_blurDistance; - p->drawImage(QPointF(x, y), m_layerImage); - } else - p->drawImage(m_layerRect.topLeft(), m_layerImage); + p->drawImage(m_layerOrigin, m_layerImage, m_sourceRect); scratchShadowBuffer()->schedulePurge(); } diff --git a/WebCore/platform/graphics/qt/Extensions3DQt.cpp b/WebCore/platform/graphics/qt/Extensions3DQt.cpp index 6a34671..cd28f0e 100644 --- a/WebCore/platform/graphics/qt/Extensions3DQt.cpp +++ b/WebCore/platform/graphics/qt/Extensions3DQt.cpp @@ -46,6 +46,11 @@ bool Extensions3DQt::supports(const String&) return false; } +void Extensions3DQt::ensureEnabled(const String& name) +{ + ASSERT(supports(name)); +} + int Extensions3DQt::getGraphicsResetStatusARB() { return GraphicsContext3D::NO_ERROR; diff --git a/WebCore/platform/graphics/qt/Extensions3DQt.h b/WebCore/platform/graphics/qt/Extensions3DQt.h index 29209ba..ae4b375 100644 --- a/WebCore/platform/graphics/qt/Extensions3DQt.h +++ b/WebCore/platform/graphics/qt/Extensions3DQt.h @@ -36,6 +36,7 @@ public: // Extensions3D methods. virtual bool supports(const String&); + virtual void ensureEnabled(const String&); virtual int getGraphicsResetStatusARB(); private: diff --git a/WebCore/platform/graphics/qt/FontPlatformData.h b/WebCore/platform/graphics/qt/FontPlatformData.h index 2201f18..1c57e29 100644 --- a/WebCore/platform/graphics/qt/FontPlatformData.h +++ b/WebCore/platform/graphics/qt/FontPlatformData.h @@ -36,7 +36,7 @@ class FontPlatformDataPrivate : public Noncopyable { public: FontPlatformDataPrivate() : refCount(1) - , size(font.pointSizeF()) + , size(font.pixelSize()) , bold(font.bold()) , oblique(false) {} @@ -49,7 +49,7 @@ public: FontPlatformDataPrivate(const QFont& font) : refCount(1) , font(font) - , size(font.pointSizeF()) + , size(font.pixelSize()) , bold(font.bold()) , oblique(false) {} @@ -150,8 +150,12 @@ public: int pixelSize() const { Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)); - if (m_data) + if (m_data) { + // WebKit allows font size zero but QFont does not. + if (!m_data->size) + return m_data->size; return m_data->font.pixelSize(); + } return 0; } diff --git a/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp index 35e9e0c..4c9eb32 100644 --- a/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp +++ b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp @@ -50,8 +50,9 @@ FontPlatformData::FontPlatformData(const FontDescription& description, const Ato : m_data(new FontPlatformDataPrivate()) { QFont& font = m_data->font; + int requestedSize = qRound(description.computedPixelSize()); font.setFamily(familyName); - font.setPixelSize(qRound(description.computedSize())); + font.setPixelSize(qRound(requestedSize)); font.setItalic(description.italic()); font.setWeight(toQFontWeight(description.weight())); font.setWordSpacing(wordSpacing); @@ -63,7 +64,10 @@ FontPlatformData::FontPlatformData(const FontDescription& description, const Ato #endif m_data->bold = font.bold(); - m_data->size = font.pointSizeF(); + // WebKit allows font size zero but QFont does not. We will return + // m_data->size if a font size of zero is requested and pixelSize() + // otherwise. + m_data->size = (!requestedSize) ? requestedSize : font.pixelSize(); } FontPlatformData::~FontPlatformData() diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp index 89dfd00..131ae93 100644 --- a/WebCore/platform/graphics/qt/FontQt.cpp +++ b/WebCore/platform/graphics/qt/FontQt.cpp @@ -29,6 +29,7 @@ #include "FontSelector.h" #include "Gradient.h" #include "GraphicsContext.h" +#include "NotImplemented.h" #include "Pattern.h" #include <QBrush> @@ -79,7 +80,7 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float QPainter *p = ctx->platformContext(); QPen textFillPen; - if (ctx->textDrawingMode() & cTextFill) { + if (ctx->textDrawingMode() & TextModeFill) { if (ctx->fillGradient()) { QBrush brush(*ctx->fillGradient()->platformGradient()); brush.setTransform(ctx->fillGradient()->gradientSpaceTransform()); @@ -92,7 +93,7 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float } QPen textStrokePen; - if (ctx->textDrawingMode() & cTextStroke) { + if (ctx->textDrawingMode() & TextModeStroke) { if (ctx->strokeGradient()) { QBrush brush(*ctx->strokeGradient()->platformGradient()); brush.setTransform(ctx->strokeGradient()->gradientSpaceTransform()); @@ -145,7 +146,7 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float if (ctxShadow->m_type != ContextShadow::NoShadow) { ContextShadow* ctxShadow = ctx->contextShadow(); - if (ctxShadow->m_type != ContextShadow::BlurShadow) { + if (!ctxShadow->mustUseContextShadow(p)) { p->save(); p->setPen(ctxShadow->m_color); p->translate(ctxShadow->offset()); @@ -179,17 +180,17 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float 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() & cTextStroke)) + if (!isComplexText && !(ctx->textDrawingMode() & TextModeStroke)) flags |= Qt::TextBypassShaping; #endif QPainterPath textStrokePath; - if (ctx->textDrawingMode() & cTextStroke) + if (ctx->textDrawingMode() & TextModeStroke) textStrokePath.addText(pt, font, string); ContextShadow* ctxShadow = ctx->contextShadow(); if (ctxShadow->m_type != ContextShadow::NoShadow) { - if (ctx->textDrawingMode() & cTextFill) { + if (ctx->textDrawingMode() & TextModeFill) { if (ctxShadow->m_type != ContextShadow::BlurShadow) { p->save(); p->setPen(ctxShadow->m_color); @@ -212,7 +213,7 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float ctxShadow->endShadowLayer(p); } } - } else if (ctx->textDrawingMode() & cTextStroke) { + } else if (ctx->textDrawingMode() & TextModeStroke) { if (ctxShadow->m_type != ContextShadow::BlurShadow) { p->translate(ctxShadow->offset()); p->strokePath(textStrokePath, QPen(ctxShadow->m_color)); @@ -235,10 +236,10 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float } } - if (ctx->textDrawingMode() & cTextStroke) + if (ctx->textDrawingMode() & TextModeStroke) p->strokePath(textStrokePath, textStrokePen); - if (ctx->textDrawingMode() & cTextFill) { + if (ctx->textDrawingMode() & TextModeFill) { QPen previousPen = p->pen(); p->setPen(textFillPen); p->drawText(pt, string, flags, run.padding()); @@ -260,8 +261,39 @@ void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const Float drawTextCommon(ctx, run, point, from, to, font(), /* isComplexText = */true); } +int Font::emphasisMarkAscent(const AtomicString&) const +{ + notImplemented(); + return 0; +} + +int Font::emphasisMarkDescent(const AtomicString&) const +{ + notImplemented(); + return 0; +} + +int Font::emphasisMarkHeight(const AtomicString&) const +{ + notImplemented(); + return 0; +} + +void Font::drawEmphasisMarksForSimpleText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const +{ + notImplemented(); +} + +void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const +{ + notImplemented(); +} + float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { + if (!primaryFont()->platformData().size()) + return 0; + #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) if (!run.length()) return 0; @@ -278,12 +310,15 @@ float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer return w + run.padding(); #else Q_ASSERT(false); - return 0.0f; + return 0; #endif } float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*, GlyphOverflow*) const { + if (!primaryFont()->platformData().size()) + return 0; + if (!run.length()) return 0; diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp index b399f4e..9dd38aa 100644 --- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -46,16 +46,13 @@ #include "ContextShadow.h" #include "FloatConversion.h" #include "Font.h" -#include "GraphicsContextPrivate.h" #include "ImageBuffer.h" #include "NotImplemented.h" #include "Path.h" #include "Pattern.h" -#include "Pen.h" #include "TransparencyLayer.h" #include <QBrush> -#include <QDebug> #include <QGradient> #include <QPaintDevice> #include <QPaintEngine> @@ -200,9 +197,7 @@ public: QBrush solidColor; InterpolationQuality imageInterpolationQuality; - - // Only used by SVG for now. - QPainterPath currentPath; + bool initialSmoothPixmapTransformHint; ContextShadow shadow; QStack<ContextShadow> shadowStack; @@ -212,13 +207,6 @@ public: return shadow.m_type != ContextShadow::NoShadow; } - inline void clearCurrentPath() - { - if (!currentPath.elementCount()) - return; - currentPath = QPainterPath(); - } - QRectF clipBoundingRect() const { #if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0) @@ -235,12 +223,12 @@ private: bool platformContextIsOwned; }; - GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate(QPainter* p, const QColor& initialSolidColor) : antiAliasingForRectsAndLines(false) , layerCount(0) , solidColor(initialSolidColor) , imageInterpolationQuality(InterpolationDefault) + , initialSmoothPixmapTransformHint(false) , painter(p) , platformContextIsOwned(false) { @@ -250,7 +238,10 @@ GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate(QPainter* p, cons // Use the default the QPainter was constructed with. antiAliasingForRectsAndLines = painter->testRenderHint(QPainter::Antialiasing); - painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, true); + // Used for default image interpolation quality. + initialSmoothPixmapTransformHint = painter->testRenderHint(QPainter::SmoothPixmapTransform); + + painter->setRenderHint(QPainter::Antialiasing, true); } GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate() @@ -258,16 +249,16 @@ GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate() if (!platformContextIsOwned) return; - painter->end(); QPaintDevice* device = painter->device(); + painter->end(); delete painter; delete device; } -GraphicsContext::GraphicsContext(PlatformGraphicsContext* painter) - : m_common(createGraphicsContextPrivate()) - , m_data(new GraphicsContextPlatformPrivate(painter, fillColor())) +void GraphicsContext::platformInit(PlatformGraphicsContext* painter) { + m_data = new GraphicsContextPlatformPrivate(painter, fillColor()); + setPaintingDisabled(!painter); if (!painter) @@ -282,12 +273,11 @@ GraphicsContext::GraphicsContext(PlatformGraphicsContext* painter) painter->setPen(pen); } -GraphicsContext::~GraphicsContext() +void GraphicsContext::platformDestroy() { while (!m_data->layers.isEmpty()) endTransparencyLayer(); - destroyGraphicsContextPrivate(m_common); delete m_data; } @@ -319,11 +309,6 @@ void GraphicsContext::restorePlatformState() m_data->p()->restore(); - if (!m_data->currentPath.isEmpty() && m_common->state.pathTransform.isInvertible()) { - QTransform matrix = m_common->state.pathTransform; - m_data->currentPath = m_data->currentPath * matrix; - } - if (m_data->shadowStack.isEmpty()) m_data->shadow = ContextShadow(); else @@ -514,93 +499,88 @@ void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* poin p->setRenderHint(QPainter::Antialiasing, painterWasAntialiased); } -void GraphicsContext::fillPath() +void GraphicsContext::fillPath(const Path& path) { if (paintingDisabled()) return; QPainter* p = m_data->p(); - QPainterPath& path = m_data->currentPath; // Avoid detaching the QPainterPath - path.setFillRule(toQtFillRule(fillRule())); + QPainterPath platformPath = path.platformPath(); + platformPath.setFillRule(toQtFillRule(fillRule())); if (m_data->hasShadow()) { ContextShadow* shadow = contextShadow(); - if (shadow->m_type != ContextShadow::BlurShadow - && !m_common->state.fillPattern && !m_common->state.fillGradient) + if (shadow->mustUseContextShadow(p) || m_state.fillPattern || m_state.fillGradient) { - p->translate(m_data->shadow.offset()); - p->fillPath(path, QColor(m_data->shadow.m_color)); - p->translate(-m_data->shadow.offset()); - } else { - QPainter* shadowPainter = shadow->beginShadowLayer(p, path.controlPointRect()); + QPainter* shadowPainter = shadow->beginShadowLayer(p, platformPath.controlPointRect()); if (shadowPainter) { shadowPainter->setCompositionMode(QPainter::CompositionMode_Source); - shadowPainter->fillPath(path, QColor(m_data->shadow.m_color)); + shadowPainter->fillPath(platformPath, QColor(m_data->shadow.m_color)); shadow->endShadowLayer(p); } + } else { + QPointF offset = shadow->offset(); + p->translate(offset); + p->fillPath(platformPath, QColor(shadow->m_color)); + p->translate(-offset); } - } - if (m_common->state.fillPattern) { + if (m_state.fillPattern) { AffineTransform affine; - p->fillPath(path, QBrush(m_common->state.fillPattern->createPlatformPattern(affine))); - } else if (m_common->state.fillGradient) { - QBrush brush(*m_common->state.fillGradient->platformGradient()); - brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform()); - p->fillPath(path, brush); + p->fillPath(platformPath, QBrush(m_state.fillPattern->createPlatformPattern(affine))); + } else if (m_state.fillGradient) { + QBrush brush(*m_state.fillGradient->platformGradient()); + brush.setTransform(m_state.fillGradient->gradientSpaceTransform()); + p->fillPath(platformPath, brush); } else - p->fillPath(path, p->brush()); - - m_data->clearCurrentPath(); + p->fillPath(platformPath, p->brush()); } -void GraphicsContext::strokePath() +void GraphicsContext::strokePath(const Path& path) { if (paintingDisabled()) return; QPainter* p = m_data->p(); QPen pen(p->pen()); - QPainterPath& path = m_data->currentPath; // Avoid detaching the QPainterPath - path.setFillRule(toQtFillRule(fillRule())); + QPainterPath platformPath = path.platformPath(); + platformPath.setFillRule(toQtFillRule(fillRule())); if (m_data->hasShadow()) { ContextShadow* shadow = contextShadow(); - - if (shadow->m_type != ContextShadow::BlurShadow - && !m_common->state.strokePattern && !m_common->state.strokeGradient) + if (shadow->mustUseContextShadow(p) || m_state.strokePattern || m_state.strokeGradient) { - QPen shadowPen(pen); - shadowPen.setColor(m_data->shadow.m_color); - p->translate(m_data->shadow.offset()); - p->strokePath(path, shadowPen); - p->translate(-m_data->shadow.offset()); - } else { - FloatRect boundingRect = path.controlPointRect(); + FloatRect boundingRect = platformPath.controlPointRect(); boundingRect.inflate(pen.miterLimit() + pen.widthF()); QPainter* shadowPainter = shadow->beginShadowLayer(p, boundingRect); if (shadowPainter) { shadowPainter->setOpacity(static_cast<qreal>(m_data->shadow.m_color.alpha()) / 255); - shadowPainter->strokePath(path, pen); + shadowPainter->strokePath(platformPath, pen); shadow->endShadowLayer(p); } + } else { + QPen shadowPen(pen); + shadowPen.setColor(m_data->shadow.m_color); + QPointF offset = shadow->offset(); + p->translate(offset); + p->strokePath(platformPath, shadowPen); + p->translate(-offset); } } - if (m_common->state.strokePattern) { + if (m_state.strokePattern) { AffineTransform affine; - pen.setBrush(QBrush(m_common->state.strokePattern->createPlatformPattern(affine))); + pen.setBrush(QBrush(m_state.strokePattern->createPlatformPattern(affine))); p->setPen(pen); - p->strokePath(path, pen); - } else if (m_common->state.strokeGradient) { - QBrush brush(*m_common->state.strokeGradient->platformGradient()); - brush.setTransform(m_common->state.strokeGradient->gradientSpaceTransform()); + p->strokePath(platformPath, pen); + } else if (m_state.strokeGradient) { + QBrush brush(*m_state.strokeGradient->platformGradient()); + brush.setTransform(m_state.strokeGradient->gradientSpaceTransform()); pen.setBrush(brush); p->setPen(pen); - p->strokePath(path, pen); + p->strokePath(platformPath, pen); } else - p->strokePath(path, pen); - m_data->clearCurrentPath(); + p->strokePath(platformPath, pen); } static inline void drawRepeatPattern(QPainter* p, QPixmap* image, const FloatRect& rect, const bool repeatX, const bool repeatY) @@ -679,21 +659,21 @@ void GraphicsContext::fillRect(const FloatRect& rect) QRectF normalizedRect = rect.normalized(); ContextShadow* shadow = contextShadow(); - if (m_common->state.fillPattern) { + if (m_state.fillPattern) { AffineTransform affine; - QBrush brush(m_common->state.fillPattern->createPlatformPattern(affine)); - QPixmap* image = m_common->state.fillPattern->tileImage()->nativeImageForCurrentFrame(); + QBrush brush(m_state.fillPattern->createPlatformPattern(affine)); + QPixmap* image = m_state.fillPattern->tileImage()->nativeImageForCurrentFrame(); QPainter* shadowPainter = m_data->hasShadow() ? shadow->beginShadowLayer(p, normalizedRect) : 0; if (shadowPainter) { - drawRepeatPattern(shadowPainter, image, normalizedRect, m_common->state.fillPattern->repeatX(), m_common->state.fillPattern->repeatY()); + drawRepeatPattern(shadowPainter, image, normalizedRect, m_state.fillPattern->repeatX(), m_state.fillPattern->repeatY()); shadowPainter->setCompositionMode(QPainter::CompositionMode_SourceIn); shadowPainter->fillRect(normalizedRect, shadow->m_color); shadow->endShadowLayer(p); } - drawRepeatPattern(p, image, normalizedRect, m_common->state.fillPattern->repeatX(), m_common->state.fillPattern->repeatY()); - } else if (m_common->state.fillGradient) { - QBrush brush(*m_common->state.fillGradient->platformGradient()); - brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform()); + drawRepeatPattern(p, image, normalizedRect, m_state.fillPattern->repeatX(), m_state.fillPattern->repeatY()); + } else if (m_state.fillGradient) { + QBrush brush(*m_state.fillGradient->platformGradient()); + brush.setTransform(m_state.fillGradient->gradientSpaceTransform()); QPainter* shadowPainter = m_data->hasShadow() ? shadow->beginShadowLayer(p, normalizedRect) : 0; if (shadowPainter) { shadowPainter->fillRect(normalizedRect, brush); @@ -704,7 +684,7 @@ void GraphicsContext::fillRect(const FloatRect& rect) p->fillRect(normalizedRect, brush); } else { if (m_data->hasShadow()) { - if (shadow->m_type == ContextShadow::BlurShadow) { + if (shadow->mustUseContextShadow(p)) { QPainter* shadowPainter = shadow->beginShadowLayer(p, normalizedRect); if (shadowPainter) { shadowPainter->setOpacity(static_cast<qreal>(shadow->m_color.alpha()) / 255); @@ -712,17 +692,11 @@ void GraphicsContext::fillRect(const FloatRect& rect) shadow->endShadowLayer(p); } } else { - // Solid rectangle fill with no blur shadow can be done faster - // without using the shadow layer at all. + // Solid rectangle fill with no blur shadow or transformations applied can be done + // faster without using the shadow layer at all. QColor shadowColor = shadow->m_color; shadowColor.setAlphaF(shadowColor.alphaF() * p->brush().color().alphaF()); - const QTransform transform = p->transform(); - if (transform.isScaling()) { - p->fillRect(normalizedRect.translated(static_cast<qreal>(shadow->offset().x()) / transform.m11(), - static_cast<qreal>(shadow->offset().y() / transform.m22())), - shadowColor); - } else - p->fillRect(normalizedRect.translated(shadow->offset()), shadowColor); + p->fillRect(normalizedRect.translated(shadow->offset()), shadowColor); } } @@ -742,18 +716,15 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorS if (m_data->hasShadow()) { ContextShadow* shadow = contextShadow(); - - if (shadow->m_type != ContextShadow::BlurShadow) { - // We do not need any layer for simple shadow. - p->fillRect(normalizedRect.translated(shadow->offset()), shadow->m_color); - } else { + if (shadow->mustUseContextShadow(p)) { QPainter* shadowPainter = shadow->beginShadowLayer(p, normalizedRect); if (shadowPainter) { shadowPainter->setCompositionMode(QPainter::CompositionMode_Source); shadowPainter->fillRect(normalizedRect, shadow->m_color); shadow->endShadowLayer(p); } - } + } else + p->fillRect(normalizedRect.translated(shadow->offset()), shadow->m_color); } p->fillRect(normalizedRect, m_data->solidColor); @@ -769,48 +740,27 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef QPainter* p = m_data->p(); if (m_data->hasShadow()) { ContextShadow* shadow = contextShadow(); - - if (shadow->m_type != ContextShadow::BlurShadow) { - // We do not need any layer for simple shadow. - p->translate(m_data->shadow.offset()); - p->fillPath(path.platformPath(), QColor(m_data->shadow.m_color)); - p->translate(-m_data->shadow.offset()); - } else { + if (shadow->mustUseContextShadow(p)) { QPainter* shadowPainter = shadow->beginShadowLayer(p, rect); if (shadowPainter) { shadowPainter->setCompositionMode(QPainter::CompositionMode_Source); shadowPainter->fillPath(path.platformPath(), QColor(m_data->shadow.m_color)); shadow->endShadowLayer(p); } + } else { + p->translate(m_data->shadow.offset()); + p->fillPath(path.platformPath(), QColor(m_data->shadow.m_color)); + p->translate(-m_data->shadow.offset()); } } p->fillPath(path.platformPath(), QColor(color)); } -void GraphicsContext::beginPath() -{ - m_data->clearCurrentPath(); -} - -void GraphicsContext::addPath(const Path& path) -{ - if (!m_data->currentPath.elementCount()) { - m_data->currentPath = path.platformPath(); - return; - } - m_data->currentPath.addPath(path.platformPath()); -} - bool GraphicsContext::inTransparencyLayer() const { return m_data->layerCount; } -PlatformPath* GraphicsContext::currentPath() -{ - return &m_data->currentPath; -} - ContextShadow* GraphicsContext::contextShadow() { return &m_data->shadow; @@ -824,47 +774,54 @@ void GraphicsContext::clip(const FloatRect& rect) m_data->p()->setClipRect(rect, Qt::IntersectClip); } -void GraphicsContext::clipPath(WindRule clipRule) +void GraphicsContext::clipPath(const Path& path, WindRule clipRule) { if (paintingDisabled()) return; QPainter* p = m_data->p(); - QPainterPath newPath = m_data->currentPath; - newPath.setFillRule(clipRule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill); - p->setClipPath(newPath, Qt::IntersectClip); + QPainterPath platformPath = path.platformPath(); + platformPath.setFillRule(clipRule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill); + p->setClipPath(platformPath, Qt::IntersectClip); } -void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color) +void drawFocusRingForPath(QPainter* p, const QPainterPath& path, int width, const Color& color, bool antiAliasing) { - // FIXME: Use 'width' and 'offset' for something? http://webkit.org/b/49909 - - if (paintingDisabled() || !color.isValid()) - return; - - QPainter* p = m_data->p(); const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); - p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines); + p->setRenderHint(QPainter::Antialiasing, antiAliasing); + const QPen oldPen = p->pen(); const QBrush oldBrush = p->brush(); QPen nPen = p->pen(); - nPen.setColor(color); + nPen.setColor(QColor(color.red(), color.green(), color.blue(), 127)); + nPen.setWidth(width); p->setBrush(Qt::NoBrush); - nPen.setStyle(Qt::DotLine); + nPen.setStyle(Qt::SolidLine); - p->strokePath(path.platformPath(), nPen); + p->strokePath(path, nPen); p->setBrush(oldBrush); + p->setPen(oldPen); p->setRenderHint(QPainter::Antialiasing, antiAlias); } +void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color) +{ + // FIXME: Use 'offset' for something? http://webkit.org/b/49909 + + if (paintingDisabled() || !color.isValid()) + return; + + drawFocusRingForPath(m_data->p(), path.platformPath(), width, color, m_data->antiAliasingForRectsAndLines); +} + /** * Focus ring handling for form controls is not handled here. Qt style in * RenderTheme handles drawing focus on widgets which * need it. It is still handled here for links. */ -void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int /* width */, int /* offset */, const Color& color) +void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color) { if (paintingDisabled() || !color.isValid()) return; @@ -874,34 +831,18 @@ void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int /* width * if (!rects.size()) return; - QPainter* p = m_data->p(); - const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); - p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines); - - const QPen oldPen = p->pen(); - const QBrush oldBrush = p->brush(); - - QPen nPen = p->pen(); - nPen.setColor(color); - p->setBrush(Qt::NoBrush); - nPen.setStyle(Qt::DotLine); - p->setPen(nPen); -#if 0 - // FIXME How do we do a bounding outline with Qt? + int radius = (width - 1) / 2; QPainterPath path; - for (int i = 0; i < rectCount; ++i) - path.addRect(QRectF(rects[i])); - QPainterPathStroker stroker; - QPainterPath newPath = stroker.createStroke(path); - p->strokePath(newPath, nPen); -#else - for (unsigned i = 0; i < rectCount; ++i) - p->drawRect(QRectF(rects[i])); -#endif - p->setPen(oldPen); - p->setBrush(oldBrush); + for (unsigned i = 0; i < rectCount; ++i) { + QRect rect = QRect((rects[i])).adjusted(-offset - radius, -offset - radius, offset + radius, offset + radius); + // This is not the most efficient way to add a rect to a path, but if we don't create the tmpPath, + // we will end up with ugly lines in between rows of text on anchors with multiple lines. + QPainterPath tmpPath; + tmpPath.addRoundedRect(rect, radius, radius); + path = path.united(tmpPath); + } - p->setRenderHint(QPainter::Antialiasing, antiAlias); + drawFocusRingForPath(m_data->p(), path, width, color, m_data->antiAliasingForRectsAndLines); } void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool) @@ -974,14 +915,15 @@ void GraphicsContext::setPlatformShadow(const FloatSize& size, float blur, const // Qt doesn't support shadows natively, they are drawn manually in the draw* // functions - if (m_common->state.shadowsIgnoreTransforms) { + if (m_state.shadowsIgnoreTransforms) { // Meaning that this graphics context is associated with a CanvasRenderingContext // We flip the height since CG and HTML5 Canvas have opposite Y axis - m_common->state.shadowOffset = FloatSize(size.width(), -size.height()); + m_state.shadowOffset = FloatSize(size.width(), -size.height()); m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), -size.height())); - } else { + } else m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), size.height())); - } + + m_data->shadow.setShadowsIgnoreTransforms(m_state.shadowsIgnoreTransforms); } void GraphicsContext::clearPlatformShadow() @@ -991,7 +933,8 @@ void GraphicsContext::clearPlatformShadow() void GraphicsContext::pushTransparencyLayerInternal(const QRect &rect, qreal opacity, QPixmap& alphaMask) { - m_data->layers.push(new TransparencyLayer(m_data->p(), m_data->p()->transform().mapRect(rect), 1.0, alphaMask)); + QPainter* p = m_data->p(); + m_data->layers.push(new TransparencyLayer(p, p->transform().mapRect(rect), 1.0, alphaMask)); } void GraphicsContext::beginTransparencyLayer(float opacity) @@ -1014,7 +957,7 @@ void GraphicsContext::beginTransparencyLayer(float opacity) h = int(qBound(qreal(0), deviceClip.height(), (qreal)h) + 2); QPixmap emptyAlphaMask; - m_data->layers.push(new TransparencyLayer(m_data->p(), QRect(x, y, w, h), opacity, emptyAlphaMask)); + m_data->layers.push(new TransparencyLayer(p, QRect(x, y, w, h), opacity, emptyAlphaMask)); ++m_data->layerCount; } @@ -1056,17 +999,23 @@ void GraphicsContext::clearRect(const FloatRect& rect) p->setCompositionMode(currentCompositionMode); } -void GraphicsContext::strokeRect(const FloatRect& rect, float width) +void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth) { if (paintingDisabled()) return; - QPainterPath path; + Path path; path.addRect(rect); - setStrokeThickness(width); - m_data->currentPath = path; - strokePath(); + float previousStrokeThickness = strokeThickness(); + + if (lineWidth != previousStrokeThickness) + setStrokeThickness(lineWidth); + + strokePath(path); + + if (lineWidth != previousStrokeThickness) + setStrokeThickness(previousStrokeThickness); } void GraphicsContext::setLineCap(LineCap lc) @@ -1132,24 +1081,20 @@ void GraphicsContext::setAlpha(float opacity) p->setOpacity(opacity); } -void GraphicsContext::setCompositeOperation(CompositeOperator op) +void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op) { if (paintingDisabled()) return; - if (m_data->p()->paintEngine()->hasFeature(QPaintEngine::PorterDuff)) - m_data->p()->setCompositionMode(toQtCompositionMode(op)); -} + QPainter* painter = m_data->p(); -void GraphicsContext::clip(const Path& path) -{ - if (paintingDisabled()) + if (!painter->paintEngine()->hasFeature(QPaintEngine::PorterDuff)) return; - m_data->p()->setClipPath(path.platformPath(), Qt::IntersectClip); + painter->setCompositionMode(toQtCompositionMode(op)); } -void GraphicsContext::canvasClip(const Path& path) +void GraphicsContext::clip(const Path& path) { if (paintingDisabled()) return; @@ -1159,6 +1104,11 @@ void GraphicsContext::canvasClip(const Path& path) m_data->p()->setClipPath(clipPath, Qt::IntersectClip); } +void GraphicsContext::canvasClip(const Path& path) +{ + clip(path); +} + void GraphicsContext::clipOut(const Path& path) { if (paintingDisabled()) @@ -1186,12 +1136,6 @@ void GraphicsContext::translate(float x, float y) return; m_data->p()->translate(x, y); - - if (!m_data->currentPath.isEmpty()) { - QTransform matrix; - m_data->currentPath = m_data->currentPath * matrix.translate(-x, -y); - m_common->state.pathTransform.translate(x, y); - } } void GraphicsContext::rotate(float radians) @@ -1200,12 +1144,6 @@ void GraphicsContext::rotate(float radians) return; m_data->p()->rotate(180 / M_PI*radians); - - if (!m_data->currentPath.isEmpty()) { - QTransform matrix; - m_data->currentPath = m_data->currentPath * matrix.rotate(-180 / M_PI*radians); - m_common->state.pathTransform.rotate(radians); - } } void GraphicsContext::scale(const FloatSize& s) @@ -1214,12 +1152,6 @@ void GraphicsContext::scale(const FloatSize& s) return; m_data->p()->scale(s.width(), s.height()); - - if (!m_data->currentPath.isEmpty()) { - QTransform matrix; - m_data->currentPath = m_data->currentPath * matrix.scale(1 / s.width(), 1 / s.height()); - m_common->state.pathTransform.scaleNonUniform(s.width(), s.height()); - } } void GraphicsContext::clipOut(const IntRect& rect) @@ -1276,15 +1208,6 @@ void GraphicsContext::concatCTM(const AffineTransform& transform) return; m_data->p()->setWorldTransform(transform, true); - - // Transformations to the context shouldn't transform the currentPath. - // We have to undo every change made to the context from the currentPath - // to avoid wrong drawings. - if (!m_data->currentPath.isEmpty() && transform.isInvertible()) { - QTransform matrix = transform.inverse(); - m_data->currentPath = m_data->currentPath * matrix; - m_common->state.pathTransform.multiply(transform.toTransformationMatrix()); - } } void GraphicsContext::setURLForRect(const KURL&, const IntRect&) @@ -1437,13 +1360,16 @@ void GraphicsContext::setImageInterpolationQuality(InterpolationQuality quality) m_data->p()->setRenderHint(QPainter::SmoothPixmapTransform, false); break; - case InterpolationDefault: case InterpolationMedium: case InterpolationHigh: - default: // use the filter m_data->p()->setRenderHint(QPainter::SmoothPixmapTransform, true); break; + + case InterpolationDefault: + default: + m_data->p()->setRenderHint(QPainter::SmoothPixmapTransform, m_data->initialSmoothPixmapTransformHint); + break; }; } diff --git a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp index 49387a2..f31844a 100644 --- a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp @@ -686,7 +686,7 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform // try to snatch that ownership. if (!m_layer->parent() && !parentItem()) setParentItem(0); - else if (m_layer && m_layer->parent() && m_layer->parent()->nativeLayer() != parentItem()) + else if (m_layer && m_layer->parent() && m_layer->parent()->platformLayer() != parentItem()) setParentItem(m_layer->parent()->platformLayer()); } @@ -1318,13 +1318,6 @@ void GraphicsLayerQt::syncCompositingStateForThisLayerOnly() } /* \reimp (GraphicsLayer.h) - */ -NativeLayer GraphicsLayerQt::nativeLayer() const -{ - return m_impl.get(); -} - -/* \reimp (GraphicsLayer.h) */ PlatformLayer* GraphicsLayerQt::platformLayer() const { diff --git a/WebCore/platform/graphics/qt/GraphicsLayerQt.h b/WebCore/platform/graphics/qt/GraphicsLayerQt.h index ed535eb..b1692d2 100644 --- a/WebCore/platform/graphics/qt/GraphicsLayerQt.h +++ b/WebCore/platform/graphics/qt/GraphicsLayerQt.h @@ -38,7 +38,6 @@ public: virtual ~GraphicsLayerQt(); // reimps from GraphicsLayer.h - virtual NativeLayer nativeLayer() const; virtual PlatformLayer* platformLayer() const; virtual void setNeedsDisplay(); virtual void setNeedsDisplayInRect(const FloatRect&); diff --git a/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/WebCore/platform/graphics/qt/ImageBufferQt.cpp index de23297..1652b5b 100644 --- a/WebCore/platform/graphics/qt/ImageBufferQt.cpp +++ b/WebCore/platform/graphics/qt/ImageBufferQt.cpp @@ -80,7 +80,7 @@ ImageBufferData::ImageBufferData(const IntSize& size) m_image = StillImage::createForRendering(&m_pixmap); } -ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, bool& success) +ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode, bool& success) : m_data(size) , m_size(size) { diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp index 2dd239f..2bbb9ce 100644 --- a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp @@ -37,17 +37,17 @@ namespace WebCore { -ImageDecoder* ImageDecoder::create(const SharedBuffer& data, bool premultiplyAlpha, bool ignoreGammaAndColorProfile) +ImageDecoder* ImageDecoder::create(const SharedBuffer& data, ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption) { // We need at least 4 bytes to figure out what kind of image we're dealing with. if (data.size() < 4) return 0; - return new ImageDecoderQt(premultiplyAlpha, ignoreGammaAndColorProfile); + return new ImageDecoderQt(alphaOption, gammaAndColorProfileOption); } -ImageDecoderQt::ImageDecoderQt(bool premultiplyAlpha, bool ignoreGammaAndColorProfile) - : ImageDecoder(premultiplyAlpha, ignoreGammaAndColorProfile) +ImageDecoderQt::ImageDecoderQt(ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption) + : ImageDecoder(alphaOption, gammaAndColorProfileOption) , m_repetitionCount(cAnimationNone) { } diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.h b/WebCore/platform/graphics/qt/ImageDecoderQt.h index 914c020..23fb79a 100644 --- a/WebCore/platform/graphics/qt/ImageDecoderQt.h +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.h @@ -41,7 +41,7 @@ namespace WebCore { class ImageDecoderQt : public ImageDecoder { public: - ImageDecoderQt(bool premultiplyAlpha, bool ignoreGammaAndColorProfile); + ImageDecoderQt(ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption); ~ImageDecoderQt(); virtual void setData(SharedBuffer* data, bool allDataReceived); diff --git a/WebCore/platform/graphics/qt/ImageQt.cpp b/WebCore/platform/graphics/qt/ImageQt.cpp index 3611308..f713d37 100644 --- a/WebCore/platform/graphics/qt/ImageQt.cpp +++ b/WebCore/platform/graphics/qt/ImageQt.cpp @@ -114,7 +114,7 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const if (tr.x() || tr.y() || tr.width() != pixmap.width() || tr.height() != pixmap.height()) pixmap = pixmap.copy(tr); - ctxt->save(); + CompositeOperator previousOperator = ctxt->compositeOperation(); ctxt->setCompositeOperation(op); QPainter* p = ctxt->platformContext(); @@ -130,7 +130,7 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const b.setTransform(transform); p->fillRect(dr, b); - ctxt->restore(); + ctxt->setCompositeOperation(previousOperator); if (imageObserver()) imageObserver()->didDraw(this); diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp index 962c931..dd4b6e6 100644 --- a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp @@ -25,6 +25,7 @@ #include "GraphicsContext.h" #include "HTMLMediaElement.h" #include "HTMLVideoElement.h" +#include "QtNAMThreadSafeProxy.h" #include "NetworkingContext.h" #include "NotImplemented.h" #include "RenderVideo.h" @@ -209,8 +210,8 @@ void MediaPlayerPrivateQt::commitLoad(const String& url) if (document && manager) { // Set the cookies - QNetworkCookieJar* jar = manager->cookieJar(); - QList<QNetworkCookie> cookies = jar->cookiesForUrl(rUrl); + QtNAMThreadSafeProxy managerProxy(manager); + QList<QNetworkCookie> cookies = managerProxy.cookiesForUrl(rUrl); // Don't set the header if there are no cookies. // This prevents a warning from being emitted. diff --git a/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp b/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp index f093d7d..47ddf02 100644 --- a/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp +++ b/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp @@ -40,6 +40,18 @@ bool SimpleFontData::containsCharacters(const UChar*, int) const void SimpleFontData::platformInit() { + if (!m_platformData.size()) { + m_ascent = 0; + m_descent = 0; + m_lineGap = 0; + m_lineSpacing = 0; + m_avgCharWidth = 0; + m_maxCharWidth = 0; + m_xHeight = 0; + m_unitsPerEm = 0; + return; + } + QFontMetrics fm(m_platformData.font()); m_ascent = fm.ascent(); @@ -52,6 +64,8 @@ void SimpleFontData::platformInit() void SimpleFontData::platformGlyphInit() { + if (!m_platformData.size()) + return; m_spaceGlyph = 0; m_adjustedSpaceWidth = m_spaceWidth; determinePitch(); @@ -61,6 +75,8 @@ void SimpleFontData::platformGlyphInit() void SimpleFontData::platformCharWidthInit() { + if (!m_platformData.size()) + return; QFontMetrics fm(m_platformData.font()); m_avgCharWidth = fm.averageCharWidth(); m_maxCharWidth = fm.maxWidth(); diff --git a/WebCore/platform/graphics/qt/StillImageQt.cpp b/WebCore/platform/graphics/qt/StillImageQt.cpp index 3038356..51c9499 100644 --- a/WebCore/platform/graphics/qt/StillImageQt.cpp +++ b/WebCore/platform/graphics/qt/StillImageQt.cpp @@ -28,6 +28,7 @@ #include "config.h" #include "StillImageQt.h" +#include "ContextShadow.h" #include "GraphicsContext.h" #include "IntSize.h" @@ -67,34 +68,26 @@ void StillImage::draw(GraphicsContext* ctxt, const FloatRect& dst, if (m_pixmap->isNull()) return; - FloatRect normalizedSrc = src.normalized(); FloatRect normalizedDst = dst.normalized(); - QPainter* painter = ctxt->platformContext(); - QPainter::CompositionMode oldCompositionMode = painter->compositionMode(); - + CompositeOperator previousOperator = ctxt->compositeOperation(); ctxt->setCompositeOperation(op); - FloatSize shadowOffset; - float shadowBlur; - Color shadowColor; - if (ctxt->getShadow(shadowOffset, shadowBlur, shadowColor)) { - FloatRect shadowImageRect(normalizedDst); - shadowImageRect.move(shadowOffset.width(), shadowOffset.height()); - - QImage shadowImage(QSize(static_cast<int>(normalizedSrc.width()), static_cast<int>(normalizedSrc.height())), QImage::Format_ARGB32_Premultiplied); - QPainter p(&shadowImage); - p.setCompositionMode(QPainter::CompositionMode_Source); - p.fillRect(shadowImage.rect(), shadowColor); - p.setCompositionMode(QPainter::CompositionMode_DestinationIn); - p.drawPixmap(QRect(0, 0, normalizedDst.width(), normalizedDst.height()), *m_pixmap, normalizedSrc); - p.end(); - painter->drawImage(shadowImageRect, shadowImage, normalizedSrc); + QPainter* painter = ctxt->platformContext(); + + ContextShadow* shadow = ctxt->contextShadow(); + if (shadow->m_type != ContextShadow::NoShadow) { + QPainter* shadowPainter = shadow->beginShadowLayer(painter, normalizedDst); + if (shadowPainter) { + shadowPainter->setOpacity(static_cast<qreal>(shadow->m_color.alpha()) / 255); + shadowPainter->drawPixmap(normalizedDst, *m_pixmap, normalizedSrc); + shadow->endShadowLayer(painter); + } } painter->drawPixmap(normalizedDst, *m_pixmap, normalizedSrc); - painter->setCompositionMode(oldCompositionMode); + ctxt->setCompositeOperation(previousOperator); } } diff --git a/WebCore/platform/graphics/qt/TransparencyLayer.h b/WebCore/platform/graphics/qt/TransparencyLayer.h index 6bdfb39..5b2f8b2 100644 --- a/WebCore/platform/graphics/qt/TransparencyLayer.h +++ b/WebCore/platform/graphics/qt/TransparencyLayer.h @@ -52,7 +52,7 @@ struct TransparencyLayer : FastAllocBase { offset = rect.topLeft(); pixmap.fill(Qt::transparent); painter.begin(&pixmap); - painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); + painter.setRenderHints(p->renderHints()); painter.translate(-offset); painter.setPen(p->pen()); painter.setBrush(p->brush()); diff --git a/WebCore/platform/graphics/skia/FontCustomPlatformData.cpp b/WebCore/platform/graphics/skia/FontCustomPlatformData.cpp index 2ea568b..161fee9 100644 --- a/WebCore/platform/graphics/skia/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/skia/FontCustomPlatformData.cpp @@ -65,7 +65,7 @@ FontCustomPlatformData::~FontCustomPlatformData() #endif } -FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontRenderingMode mode) +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation orientation, FontRenderingMode mode) { #if OS(WINDOWS) ASSERT(m_fontReference); @@ -102,7 +102,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()); + return FontPlatformData(m_fontReference, "", size, bold && !m_fontReference->isBold(), italic && !m_fontReference->isItalic(), orientation); #else notImplemented(); return FontPlatformData(); diff --git a/WebCore/platform/graphics/skia/GlyphPageTreeNodeSkia.cpp b/WebCore/platform/graphics/skia/GlyphPageTreeNodeSkia.cpp index 6024d43..66e6839 100644 --- a/WebCore/platform/graphics/skia/GlyphPageTreeNodeSkia.cpp +++ b/WebCore/platform/graphics/skia/GlyphPageTreeNodeSkia.cpp @@ -32,6 +32,7 @@ #include "GlyphPageTreeNode.h" #include "Font.h" +#include "HarfbuzzSkia.h" #include "SimpleFontData.h" #include "SkTemplates.h" @@ -40,6 +41,36 @@ namespace WebCore { +static int substituteWithVerticalGlyphs(const SimpleFontData* fontData, uint16_t* glyphs, unsigned bufferLength) +{ + HB_FaceRec_* hbFace = fontData->platformData().harfbuzzFace(); + if (!hbFace->gsub) { + // if there is no GSUB table, treat it as not covered + return 0Xffff; + } + + HB_Buffer buffer; + hb_buffer_new(&buffer); + for (unsigned i = 0; i < bufferLength; ++i) + hb_buffer_add_glyph(buffer, glyphs[i], 0, i); + + HB_UShort scriptIndex; + HB_UShort featureIndex; + + HB_GSUB_Select_Script(hbFace->gsub, HB_MAKE_TAG('D', 'F', 'L', 'T'), &scriptIndex); + HB_GSUB_Select_Feature(hbFace->gsub, HB_MAKE_TAG('v', 'e', 'r', 't'), scriptIndex, 0xffff, &featureIndex); + HB_GSUB_Add_Feature(hbFace->gsub, featureIndex, 1); + HB_GSUB_Select_Feature(hbFace->gsub, HB_MAKE_TAG('v', 'r', 't', '2'), scriptIndex, 0xffff, &featureIndex); + HB_GSUB_Add_Feature(hbFace->gsub, featureIndex, 1); + + int error = HB_GSUB_Apply_String(hbFace->gsub, buffer); + if (!error) { + for (unsigned i = 0; i < bufferLength; ++i) + glyphs[i] = static_cast<Glyph>(buffer->out_string[i].gindex); + } + return error; +} + bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) { if (SkUTF16_IsHighSurrogate(buffer[bufferLength-1])) { @@ -60,6 +91,18 @@ bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned b return false; } + if ((fontData->orientation() == Vertical) && (!fontData->isBrokenIdeographFont())) { + bool lookVariants = false; + for (unsigned i = 0; i < bufferLength; ++i) { + if (!Font::isCJKIdeograph(buffer[i])) { + lookVariants = true; + continue; + } + } + if (lookVariants) + substituteWithVerticalGlyphs(fontData, glyphs, bufferLength); + } + unsigned allGlyphs = 0; // track if any of the glyphIDs are non-zero for (unsigned i = 0; i < length; i++) { setGlyphDataForIndex(offset + i, glyphs[i], glyphs[i] ? fontData : NULL); diff --git a/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp index cbe6775..8b7ac86 100644 --- a/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp +++ b/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp @@ -53,7 +53,8 @@ bool GraphicsContext3D::getImageData(Image* image, NativeImageSkia* skiaImage = 0; AlphaOp neededAlphaOp = AlphaDoNothing; if (image->data()) { - ImageSource decoder(false, ignoreGammaAndColorProfile); + ImageSource decoder(ImageSource::AlphaNotPremultiplied, + ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied); decoder.setData(image->data(), true); if (!decoder.frameCount() || !decoder.frameIsCompleteAtIndex(0)) return false; diff --git a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp index 7c0bcd1..1b217ee 100644 --- a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp +++ b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp @@ -37,7 +37,6 @@ #include "GLES2Canvas.h" #include "Gradient.h" #include "GraphicsContextPlatformPrivate.h" -#include "GraphicsContextPrivate.h" #include "ImageBuffer.h" #include "IntRect.h" #include "NativeImageSkia.h" @@ -219,17 +218,15 @@ void addCornerArc(SkPath* path, const SkRect& rect, const IntSize& size, int sta // This may be called with a NULL pointer to create a graphics context that has // no painting. -GraphicsContext::GraphicsContext(PlatformGraphicsContext* gc) - : m_common(createGraphicsContextPrivate()) - , m_data(new GraphicsContextPlatformPrivate(gc)) +void GraphicsContext::platformInit(PlatformGraphicsContext* gc) { + m_data = new GraphicsContextPlatformPrivate(gc); setPaintingDisabled(!gc || !platformContext()->canvas()); } -GraphicsContext::~GraphicsContext() +void GraphicsContext::platformDestroy() { delete m_data; - this->destroyGraphicsContextPrivate(m_common); } PlatformGraphicsContext* GraphicsContext::platformContext() const @@ -420,11 +417,15 @@ void GraphicsContext::clipOut(const Path& p) platformContext()->canvas()->clipPath(path, SkRegion::kDifference_Op); } -void GraphicsContext::clipPath(WindRule clipRule) +void GraphicsContext::clipPath(const Path& pathToClip, WindRule clipRule) { if (paintingDisabled()) return; + // FIXME: Be smarter about this. + beginPath(); + addPath(pathToClip); + SkPath path = platformContext()->currentPathInLocalCoordinates(); if (!isPathSkiaSafe(getCTM(), path)) return; @@ -723,18 +724,22 @@ void GraphicsContext::drawRect(const IntRect& rect) platformContext()->drawRect(r); } -void GraphicsContext::fillPath() +void GraphicsContext::fillPath(const Path& pathToFill) { if (paintingDisabled()) return; + // FIXME: Be smarter about this. + beginPath(); + addPath(pathToFill); + SkPath path = platformContext()->currentPathInLocalCoordinates(); if (!isPathSkiaSafe(getCTM(), path)) return; platformContext()->prepareForSoftwareDraw(); - const GraphicsContextState& state = m_common->state; + const GraphicsContextState& state = m_state; path.setFillType(state.fillRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType); @@ -921,7 +926,7 @@ void GraphicsContext::setAlpha(float alpha) platformContext()->setAlpha(alpha); } -void GraphicsContext::setCompositeOperation(CompositeOperator op) +void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op) { if (paintingDisabled()) return; @@ -1061,13 +1066,15 @@ void GraphicsContext::setPlatformShadow(const FloatSize& size, double height = size.height(); double blur = blurFloat; - // TODO(tc): This still does not address the issue that shadows - // within canvas elements should ignore transforms. - if (m_common->state.shadowsIgnoreTransforms) { + SkBlurDrawLooper::BlurFlags blurFlags = SkBlurDrawLooper::kNone_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; + // CG uses natural orientation for Y axis, but the HTML5 canvas spec // does not. // So we now flip the height since it was flipped in @@ -1083,7 +1090,7 @@ void GraphicsContext::setPlatformShadow(const FloatSize& size, // TODO(tc): Should we have a max value for the blur? CG clamps at 1000.0 // for perf reasons. - SkDrawLooper* dl = new SkBlurDrawLooper(blur / 2, width, height, c); + SkDrawLooper* dl = new SkBlurDrawLooper(blur / 2, width, height, c, blurFlags); platformContext()->setDrawLooper(dl); dl->unref(); } @@ -1128,7 +1135,7 @@ void GraphicsContext::setPlatformStrokePattern(Pattern* pattern) platformContext()->setStrokeShader(pattern->platformPattern(getCTM())); } -void GraphicsContext::setPlatformTextDrawingMode(int mode) +void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode) { if (paintingDisabled()) return; @@ -1177,11 +1184,15 @@ void GraphicsContext::strokeArc(const IntRect& r, int startAngle, int angleSpan) platformContext()->canvas()->drawPath(path, paint); } -void GraphicsContext::strokePath() +void GraphicsContext::strokePath(const Path& pathToStroke) { if (paintingDisabled()) return; + // FIXME: Be smarter about this. + beginPath(); + addPath(pathToStroke); + SkPath path = platformContext()->currentPathInLocalCoordinates(); if (!isPathSkiaSafe(getCTM(), path)) return; diff --git a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp index adb732b..468ccda 100644 --- a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp +++ b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp @@ -40,6 +40,8 @@ #include "GLES2Canvas.h" #include "GraphicsContext.h" #include "ImageData.h" +#include "JPEGImageEncoder.h" +#include "MIMETypeRegistry.h" #include "PNGImageEncoder.h" #include "PlatformContextSkia.h" #include "SkColorPriv.h" @@ -60,7 +62,7 @@ ImageBufferData::ImageBufferData(const IntSize& size) { } -ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, bool& success) +ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode, bool& success) : m_data(size) , m_size(size) { @@ -244,14 +246,6 @@ PassRefPtr<ImageData> ImageBuffer::getPremultipliedImageData(const IntRect& rect return getImageData<Premultiplied>(rect, *context()->platformContext()->bitmap(), m_size); } -// This function does the equivalent of (a * b + 254) / 255, without an integer divide. -// Valid for a, b in the range [0..255]. -unsigned mulDiv255Ceil(unsigned a, unsigned b) -{ - unsigned value = a * b + 255; - return (value + (value >> 8)) >> 8; -} - template <Multiply multiplied> void putImageData(ImageData*& source, const IntRect& sourceRect, const IntPoint& destPoint, const SkBitmap& bitmap, const IntSize& size) @@ -295,9 +289,9 @@ void putImageData(ImageData*& source, const IntRect& sourceRect, const IntPoint& const unsigned char* srcPixel = &srcRow[x * 4]; if (multiplied == Unmultiplied) { unsigned char alpha = srcPixel[3]; - unsigned char r = mulDiv255Ceil(srcPixel[0], alpha); - unsigned char g = mulDiv255Ceil(srcPixel[1], alpha); - unsigned char b = mulDiv255Ceil(srcPixel[2], alpha); + unsigned char r = SkMulDiv255Ceiling(srcPixel[0], alpha); + unsigned char g = SkMulDiv255Ceiling(srcPixel[1], alpha); + unsigned char b = SkMulDiv255Ceiling(srcPixel[2], alpha); destRow[x] = SkPackARGB32(alpha, r, g, b); } else destRow[x] = SkPackARGB32(srcPixel[3], srcPixel[0], @@ -318,20 +312,27 @@ void ImageBuffer::putPremultipliedImageData(ImageData* source, const IntRect& so putImageData<Premultiplied>(source, sourceRect, destPoint, *context()->platformContext()->bitmap(), m_size); } -String ImageBuffer::toDataURL(const String&, const double*) const +String ImageBuffer::toDataURL(const String& mimeType, const double* quality) const { - // Encode the image into a vector. - Vector<unsigned char> pngEncodedData; - PNGImageEncoder::encode(*context()->platformContext()->bitmap(), &pngEncodedData); - - // Convert it into base64. - Vector<char> base64EncodedData; - base64Encode(*reinterpret_cast<Vector<char>*>(&pngEncodedData), base64EncodedData); - // Append with a \0 so that it's a valid string. - base64EncodedData.append('\0'); - - // And the resulting string. - return makeString("data:image/png;base64,", base64EncodedData.data()); + ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType)); + + 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(*context()->platformContext()->bitmap(), compressionQuality, &encodedImage)) + return "data:,"; + } else { + if (!PNGImageEncoder::encode(*context()->platformContext()->bitmap(), &encodedImage)) + return "data:,"; + ASSERT(mimeType == "image/png"); + } + + Vector<char> base64Data; + base64Encode(*reinterpret_cast<Vector<char>*>(&encodedImage), base64Data); + + return makeString("data:", mimeType, ";base64,", base64Data); } } // namespace WebCore diff --git a/WebCore/platform/graphics/skia/ImageSkia.cpp b/WebCore/platform/graphics/skia/ImageSkia.cpp index ae2653a..c7fa6f4 100644 --- a/WebCore/platform/graphics/skia/ImageSkia.cpp +++ b/WebCore/platform/graphics/skia/ImageSkia.cpp @@ -143,7 +143,9 @@ static ResamplingMode computeResamplingMode(PlatformContextSkia* platformContext // Everything else gets resampled. // If the platform context permits high quality interpolation, use it. - if (platformContext->interpolationQuality() == InterpolationHigh) + // High quality interpolation only enabled for scaling and translation. + if (platformContext->interpolationQuality() == InterpolationHigh + && !(platformContext->canvas()->getTotalMatrix().getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask))) return RESAMPLE_AWESOME; return RESAMPLE_LINEAR; @@ -178,17 +180,32 @@ static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeIm SkIRect resizedImageRect = // Represents the size of the resized image. { 0, 0, destRectRounded.width(), destRectRounded.height() }; - if (srcIsFull && bitmap.hasResizedBitmap(destRectRounded.width(), destRectRounded.height())) { + // Apply forward transform to destRect to estimate required size of + // re-sampled bitmap, and use only in calls required to resize, or that + // check for the required size. + SkRect destRectTransformed; + canvas.getTotalMatrix().mapRect(&destRectTransformed, destRect); + SkIRect destRectTransformedRounded; + destRectTransformed.round(&destRectTransformedRounded); + + if (srcIsFull && bitmap.hasResizedBitmap(destRectTransformedRounded.width(), destRectTransformedRounded.height())) { // Yay, this bitmap frame already has a resized version. - SkBitmap resampled = bitmap.resizedBitmap(destRectRounded.width(), destRectRounded.height()); + SkBitmap resampled = bitmap.resizedBitmap(destRectTransformedRounded.width(), destRectTransformedRounded.height()); canvas.drawBitmapRect(resampled, 0, destRect, &paint); return; } // Compute the visible portion of our rect. + // We also need to compute the transformed portion of the + // visible portion for use below. SkRect destBitmapSubsetSk; ClipRectToCanvas(canvas, destRect, &destBitmapSubsetSk); + SkRect destBitmapSubsetTransformed; + canvas.getTotalMatrix().mapRect(&destBitmapSubsetTransformed, destBitmapSubsetSk); destBitmapSubsetSk.offset(-destRect.fLeft, -destRect.fTop); + SkIRect destBitmapSubsetTransformedRounded; + destBitmapSubsetTransformed.round(&destBitmapSubsetTransformedRounded); + destBitmapSubsetTransformedRounded.offset(-destRectTransformedRounded.fLeft, -destRectTransformedRounded.fTop); // The matrix inverting, etc. could have introduced rounding error which // causes the bounds to be outside of the resized bitmap. We round outward @@ -207,27 +224,33 @@ static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeIm destBitmapSubsetSkI.height())) { // We're supposed to resize the entire image and cache it, even though // we don't need all of it. - SkBitmap resampled = bitmap.resizedBitmap(destRectRounded.width(), - destRectRounded.height()); + SkBitmap resampled = bitmap.resizedBitmap(destRectTransformedRounded.width(), + destRectTransformedRounded.height()); canvas.drawBitmapRect(resampled, 0, destRect, &paint); } else { // We should only resize the exposed part of the bitmap to do the // minimal possible work. // Resample the needed part of the image. - SkBitmap resampled = skia::ImageOperations::Resize(subset, - skia::ImageOperations::RESIZE_LANCZOS3, - destRectRounded.width(), destRectRounded.height(), - destBitmapSubsetSkI); - - // Compute where the new bitmap should be drawn. Since our new bitmap - // may be smaller than the original, we have to shift it over by the - // same amount that we cut off the top and left. - destBitmapSubsetSkI.offset(destRect.fLeft, destRect.fTop); - SkRect offsetDestRect; - offsetDestRect.set(destBitmapSubsetSkI); - - canvas.drawBitmapRect(resampled, 0, offsetDestRect, &paint); + // Transforms above plus rounding may cause destBitmapSubsetTransformedRounded + // to go outside the image, so need to clip to avoid problems. + if (destBitmapSubsetTransformedRounded.intersect(0, 0, + destRectTransformedRounded.width(), destRectTransformedRounded.height())) { + + SkBitmap resampled = skia::ImageOperations::Resize(subset, + skia::ImageOperations::RESIZE_LANCZOS3, + destRectTransformedRounded.width(), destRectTransformedRounded.height(), + destBitmapSubsetTransformedRounded); + + // Compute where the new bitmap should be drawn. Since our new bitmap + // may be smaller than the original, we have to shift it over by the + // same amount that we cut off the top and left. + destBitmapSubsetSkI.offset(destRect.fLeft, destRect.fTop); + SkRect offsetDestRect; + offsetDestRect.set(destBitmapSubsetSkI); + + canvas.drawBitmapRect(resampled, 0, offsetDestRect, &paint); + } } } diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp index d610c2a..d3c0e00 100644 --- a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp @@ -94,8 +94,8 @@ struct PlatformContextSkia::State { SkPaint::Join m_lineJoin; SkDashPathEffect* m_dash; - // Text. (See cTextFill & friends in GraphicsContext.h.) - int m_textDrawingMode; + // Text. (See TextModeFill & friends in GraphicsContext.h.) + TextDrawingModeFlags m_textDrawingMode; // Helper function for applying the state's alpha value to the given input // color to produce a new output color. @@ -137,7 +137,7 @@ PlatformContextSkia::State::State() , m_lineCap(SkPaint::kDefault_Cap) , m_lineJoin(SkPaint::kDefault_Join) , m_dash(0) - , m_textDrawingMode(cTextFill) + , m_textDrawingMode(TextModeFill) , m_interpolationQuality(InterpolationHigh) , m_canvasClipApplied(false) { @@ -299,6 +299,9 @@ void PlatformContextSkia::clipPathAntiAliased(const SkPath& clipPath) if (!haveLayerOutstanding) { SkRect bounds = clipPath.getBounds(); canvas()->saveLayerAlpha(&bounds, 255, static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag | SkCanvas::kClipToLayer_SaveFlag)); + // Guards state modification during clipped operations. + // The state is popped in applyAntiAliasedClipPaths(). + canvas()->save(); } } @@ -494,6 +497,9 @@ void PlatformContextSkia::setStrokeThickness(float thickness) void PlatformContextSkia::setStrokeShader(SkShader* strokeShader) { + if (strokeShader) + m_state->m_strokeColor = Color::black; + if (strokeShader != m_state->m_strokeShader) { SkSafeUnref(m_state->m_strokeShader); m_state->m_strokeShader = strokeShader; @@ -501,7 +507,7 @@ void PlatformContextSkia::setStrokeShader(SkShader* strokeShader) } } -int PlatformContextSkia::getTextDrawingMode() const +TextDrawingModeFlags PlatformContextSkia::getTextDrawingMode() const { return m_state->m_textDrawingMode; } @@ -521,11 +527,11 @@ int PlatformContextSkia::getNormalizedAlpha() const return alpha; } -void PlatformContextSkia::setTextDrawingMode(int mode) +void PlatformContextSkia::setTextDrawingMode(TextDrawingModeFlags mode) { - // cTextClip is never used, so we assert that it isn't set: + // TextModeClip is never used, so we assert that it isn't set: // https://bugs.webkit.org/show_bug.cgi?id=21898 - ASSERT(!(mode & cTextClip)); + ASSERT(!(mode & TextModeClip)); m_state->m_textDrawingMode = mode; } @@ -578,6 +584,9 @@ void PlatformContextSkia::setFillRule(SkPath::FillType fr) void PlatformContextSkia::setFillShader(SkShader* fillShader) { + if (fillShader) + m_state->m_fillColor = Color::black; + if (fillShader != m_state->m_fillShader) { SkSafeUnref(m_state->m_fillShader); m_state->m_fillShader = fillShader; @@ -675,6 +684,8 @@ void PlatformContextSkia::applyAntiAliasedClipPaths(WTF::Vector<SkPath>& paths) // When we call restore on the SkCanvas, the layer's bitmap is composed // into the layer below and we end up with correct, anti-aliased clipping. + m_canvas->restore(); + SkPaint paint; paint.setXfermodeMode(SkXfermode::kClear_Mode); paint.setAntiAlias(true); diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.h b/WebCore/platform/graphics/skia/PlatformContextSkia.h index 110085d..11b311a 100644 --- a/WebCore/platform/graphics/skia/PlatformContextSkia.h +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.h @@ -125,14 +125,14 @@ public: void setStrokeColor(SkColor); void setStrokeThickness(float thickness); void setStrokeShader(SkShader*); - void setTextDrawingMode(int mode); + void setTextDrawingMode(TextDrawingModeFlags mode); void setUseAntialiasing(bool enable); void setDashPathEffect(SkDashPathEffect*); SkDrawLooper* getDrawLooper() const; StrokeStyle getStrokeStyle() const; float getStrokeThickness() const; - int getTextDrawingMode() const; + TextDrawingModeFlags getTextDrawingMode() const; float getAlpha() const; int getNormalizedAlpha() const; diff --git a/WebCore/platform/graphics/skia/SkiaFontWin.cpp b/WebCore/platform/graphics/skia/SkiaFontWin.cpp index 6acfd35..5046c50 100644 --- a/WebCore/platform/graphics/skia/SkiaFontWin.cpp +++ b/WebCore/platform/graphics/skia/SkiaFontWin.cpp @@ -225,8 +225,9 @@ bool windowsCanHandleDrawTextShadow(GraphicsContext *context) FloatSize shadowOffset; float shadowBlur; Color shadowColor; + ColorSpace shadowColorSpace; - bool hasShadow = context->getShadow(shadowOffset, shadowBlur, shadowColor); + bool hasShadow = context->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace); return (hasShadow && (shadowBlur == 0) && (shadowColor.alpha() == 255) && (context->fillColor().alpha() == 255)); } @@ -242,7 +243,7 @@ bool windowsCanHandleTextDrawing(GraphicsContext* context) return false; // Check for stroke effects. - if (context->platformContext()->getTextDrawingMode() != cTextFill) + if (context->platformContext()->getTextDrawingMode() != TextModeFill) return false; // Check for gradients. @@ -307,7 +308,7 @@ bool paintSkiaText(GraphicsContext* context, HGDIOBJ oldFont = SelectObject(dc, hfont); PlatformContextSkia* platformContext = context->platformContext(); - int textMode = platformContext->getTextDrawingMode(); + TextDrawingModeFlags textMode = platformContext->getTextDrawingMode(); // Filling (if necessary). This is the common case. SkPaint paint; @@ -315,7 +316,7 @@ bool paintSkiaText(GraphicsContext* context, paint.setFlags(SkPaint::kAntiAlias_Flag); bool didFill = false; - if ((textMode & cTextFill) && SkColorGetA(paint.getColor())) { + if ((textMode & TextModeFill) && SkColorGetA(paint.getColor())) { if (!skiaDrawText(hfont, dc, platformContext->canvas(), *origin, &paint, &glyphs[0], &advances[0], &offsets[0], numGlyphs)) return false; @@ -323,7 +324,7 @@ bool paintSkiaText(GraphicsContext* context, } // Stroking on top (if necessary). - if ((textMode & cTextStroke) + if ((textMode & TextModeStroke) && platformContext->getStrokeStyle() != NoStroke && platformContext->getStrokeThickness() > 0) { diff --git a/WebCore/platform/graphics/skia/SkiaUtils.cpp b/WebCore/platform/graphics/skia/SkiaUtils.cpp index b16a344..da83793 100644 --- a/WebCore/platform/graphics/skia/SkiaUtils.cpp +++ b/WebCore/platform/graphics/skia/SkiaUtils.cpp @@ -108,7 +108,7 @@ SkXfermode::Mode WebCoreCompositeToSkiaComposite(CompositeOperator op) return (SkXfermode::Mode)table[i].m_xfermodeMode; } - SkDEBUGF(("GraphicsContext::setCompositeOperation uknown CompositeOperator %d\n", op)); + SkDEBUGF(("GraphicsContext::setPlatformCompositeOperation unknown CompositeOperator %d\n", op)); return SkXfermode::kSrcOver_Mode; // fall-back } diff --git a/WebCore/platform/graphics/texmap/TextureMapper.h b/WebCore/platform/graphics/texmap/TextureMapper.h index 250125b..589fda1 100644 --- a/WebCore/platform/graphics/texmap/TextureMapper.h +++ b/WebCore/platform/graphics/texmap/TextureMapper.h @@ -110,22 +110,22 @@ public: virtual PassRefPtr<BitmapTexture> createTexture() = 0; void setImageInterpolationQuality(InterpolationQuality quality) { m_interpolationQuality = quality; } - void setTextDrawingMode(int mode) { m_textDrawingMode = mode; } + void setTextDrawingMode(TextDrawingModeFlags mode) { m_textDrawingMode = mode; } InterpolationQuality imageInterpolationQuality() const { return m_interpolationQuality; } - int textDrawingMode() const { return m_textDrawingMode; } + TextDrawingModeFlags textDrawingMode() const { return m_textDrawingMode; } void setViewportSize(const IntSize&); protected: TextureMapper() : m_interpolationQuality(InterpolationDefault) - , m_textDrawingMode(cTextFill) + , m_textDrawingMode(TextModeFill) {} private: InterpolationQuality m_interpolationQuality; - int m_textDrawingMode; + TextDrawingModeFlags m_textDrawingMode; }; }; diff --git a/WebCore/platform/graphics/transforms/TransformationMatrix.h b/WebCore/platform/graphics/transforms/TransformationMatrix.h index 96b4baa..f13bcc1 100644 --- a/WebCore/platform/graphics/transforms/TransformationMatrix.h +++ b/WebCore/platform/graphics/transforms/TransformationMatrix.h @@ -32,6 +32,9 @@ #include <string.h> //for memcpy #include <wtf/FastAllocBase.h> +#if PLATFORM(CA) +#include <QuartzCore/CATransform3D.h> +#endif #if PLATFORM(CG) #include <CoreGraphics/CGAffineTransform.h> #elif PLATFORM(CAIRO) @@ -309,7 +312,12 @@ public: return result; } +#if PLATFORM(CA) + TransformationMatrix(const CATransform3D&); + operator CATransform3D() const; +#endif #if PLATFORM(CG) + TransformationMatrix(const CGAffineTransform&); operator CGAffineTransform() const; #elif PLATFORM(CAIRO) operator cairo_matrix_t() const; diff --git a/WebCore/platform/graphics/win/FontCGWin.cpp b/WebCore/platform/graphics/win/FontCGWin.cpp index 2f1fb41..8012722 100644 --- a/WebCore/platform/graphics/win/FontCGWin.cpp +++ b/WebCore/platform/graphics/win/FontCGWin.cpp @@ -133,8 +133,8 @@ static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData Color fillColor = graphicsContext->fillColor(); bool drawIntoBitmap = false; - int drawingMode = graphicsContext->textDrawingMode(); - if (drawingMode == cTextFill) { + TextDrawingModeFlags drawingMode = graphicsContext->textDrawingMode(); + if (drawingMode == TextModeFill) { if (!fillColor.alpha()) return; @@ -143,7 +143,9 @@ static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData FloatSize offset; float blur; Color color; - graphicsContext->getShadow(offset, blur, color); + ColorSpace shadowColorSpace; + + graphicsContext->getShadow(offset, blur, color, shadowColorSpace); drawIntoBitmap = offset.width() || offset.height() || blur; } } @@ -205,7 +207,7 @@ static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); } - if (drawingMode == cTextFill) { + if (drawingMode == TextModeFill) { XFORM xform; xform.eM11 = 1.0; xform.eM12 = 0; @@ -247,7 +249,7 @@ static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData CGContextSaveGState(cgContext); CGContextConcatCTM(cgContext, initialGlyphTransform); - if (drawingMode & cTextFill) { + if (drawingMode & TextModeFill) { CGContextAddPath(cgContext, glyphPath.get()); CGContextFillPath(cgContext); if (font->syntheticBoldOffset()) { @@ -257,7 +259,7 @@ static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData CGContextTranslateCTM(cgContext, -font->syntheticBoldOffset(), 0); } } - if (drawingMode & cTextStroke) { + if (drawingMode & TextModeStroke) { CGContextAddPath(cgContext, glyphPath.get()); CGContextStrokePath(cgContext); if (font->syntheticBoldOffset()) { @@ -352,16 +354,20 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo FloatSize shadowOffset; float shadowBlur; Color shadowColor; - graphicsContext->getShadow(shadowOffset, shadowBlur, shadowColor); + ColorSpace shadowColorSpace; + graphicsContext->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace); - bool hasSimpleShadow = graphicsContext->textDrawingMode() == cTextFill && shadowColor.isValid() && !shadowBlur; + bool hasSimpleShadow = graphicsContext->textDrawingMode() == TextModeFill && shadowColor.isValid() && !shadowBlur && (!graphicsContext->shadowsIgnoreTransforms() || graphicsContext->getCTM().isIdentityOrTranslationOrFlipped()); if (hasSimpleShadow) { // Paint simple shadows ourselves instead of relying on CG shadows, to avoid losing subpixel antialiasing. graphicsContext->clearShadow(); Color fillColor = graphicsContext->fillColor(); Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255); graphicsContext->setFillColor(shadowFillColor, ColorSpaceDeviceRGB); - CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowOffset.width(), point.y() + translation.height() + shadowOffset.height()); + float shadowTextX = point.x() + translation.width() + 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() + translation.height() + shadowOffset.height() * (graphicsContext->shadowsIgnoreTransforms() ? -1 : 1); + CGContextSetTextPosition(cgContext, shadowTextX, shadowTextY); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); if (font->syntheticBoldOffset()) { CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowOffset.width() + font->syntheticBoldOffset(), point.y() + translation.height() + shadowOffset.height()); diff --git a/WebCore/platform/graphics/win/FontWin.cpp b/WebCore/platform/graphics/win/FontWin.cpp index 97971dc..2170954 100644 --- a/WebCore/platform/graphics/win/FontWin.cpp +++ b/WebCore/platform/graphics/win/FontWin.cpp @@ -30,6 +30,7 @@ #include "GlyphBuffer.h" #include "GraphicsContext.h" #include "IntRect.h" +#include "Logging.h" #include "SimpleFontData.h" #include "UniscribeController.h" #include <wtf/MathExtras.h> @@ -62,33 +63,57 @@ FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h); } -void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, - int from, int to) const +float Font::getGlyphsAndAdvancesForComplexText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const { - // This glyph buffer holds our glyphs + advances + font data for each glyph. - GlyphBuffer glyphBuffer; + if (forTextEmphasis) { + // FIXME: Add forTextEmphasis paremeter to UniscribeController and use it. + LOG_ERROR("Not implemented for text emphasis."); + return 0; + } - float startX = point.x(); UniscribeController controller(this, run); controller.advance(from); float beforeWidth = controller.runWidthSoFar(); controller.advance(to, &glyphBuffer); - - // We couldn't generate any glyphs for the run. Give up. + if (glyphBuffer.isEmpty()) - return; - + return 0; + float afterWidth = controller.runWidthSoFar(); if (run.rtl()) { controller.advance(run.length()); - startX += controller.runWidthSoFar() - afterWidth; - } else - startX += beforeWidth; + return controller.runWidthSoFar() - afterWidth; + } + return beforeWidth; +} + +void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, + int from, int to) const +{ + // This glyph buffer holds our glyphs + advances + font data for each glyph. + GlyphBuffer glyphBuffer; + + float startX = point.x() + getGlyphsAndAdvancesForComplexText(run, from, to, glyphBuffer); + + // We couldn't generate any glyphs for the run. Give up. + if (glyphBuffer.isEmpty()) + return; // Draw the glyph buffer now at the starting point returned in startX. FloatPoint startPoint(startX, point.y()); - drawGlyphBuffer(context, glyphBuffer, run, startPoint); + drawGlyphBuffer(context, glyphBuffer, startPoint); +} + +void Font::drawEmphasisMarksForComplexText(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const +{ + GlyphBuffer glyphBuffer; + float initialAdvance = getGlyphsAndAdvancesForComplexText(run, from, to, glyphBuffer, ForTextEmphasis); + + if (glyphBuffer.isEmpty()) + return; + + drawEmphasisMarks(context, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y())); } float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const diff --git a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp index 1ad6bc1..b42e51c 100644 --- a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp +++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp @@ -62,9 +62,14 @@ static CGContextRef CGContextWithHDC(HDC hdc, bool hasAlpha) } GraphicsContext::GraphicsContext(HDC hdc, bool hasAlpha) - : m_common(createGraphicsContextPrivate()) - , m_data(new GraphicsContextPlatformPrivate(CGContextWithHDC(hdc, hasAlpha))) + : m_updatingControlTints(false) { + platformInit(hdc, hasAlpha); +} + +void GraphicsContext::platformInit(HDC hdc, bool hasAlpha) +{ + m_data = new GraphicsContextPlatformPrivate(CGContextWithHDC(hdc, hasAlpha)); CGContextRelease(m_data->m_cgContext.get()); m_data->m_hdc = hdc; setPaintingDisabled(!m_data->m_cgContext); diff --git a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp index a989c24..b2c702f 100644 --- a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp +++ b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp @@ -65,9 +65,15 @@ static cairo_t* createCairoContextWithHDC(HDC hdc, bool hasAlpha) } GraphicsContext::GraphicsContext(HDC dc, bool hasAlpha) - : m_common(createGraphicsContextPrivate()) - , m_data(new GraphicsContextPlatformPrivate) + : m_updatingControlTints(false) { + platformInit(dc, 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; diff --git a/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp b/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp index f7674db..984fd3f 100644 --- a/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp +++ b/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp @@ -153,11 +153,6 @@ void GraphicsLayerCACF::setName(const String& name) m_layer->setName(longName); } -NativeLayer GraphicsLayerCACF::nativeLayer() const -{ - return m_layer.get(); -} - bool GraphicsLayerCACF::setChildren(const Vector<GraphicsLayer*>& children) { bool childrenChanged = GraphicsLayer::setChildren(children); diff --git a/WebCore/platform/graphics/win/GraphicsLayerCACF.h b/WebCore/platform/graphics/win/GraphicsLayerCACF.h index c18a6e9..23f36b2 100644 --- a/WebCore/platform/graphics/win/GraphicsLayerCACF.h +++ b/WebCore/platform/graphics/win/GraphicsLayerCACF.h @@ -44,9 +44,6 @@ public: virtual void setName(const String& inName); - // for hosting this GraphicsLayer in a native layer hierarchy - virtual NativeLayer nativeLayer() const; - virtual bool setChildren(const Vector<GraphicsLayer*>&); virtual void addChild(GraphicsLayer *layer); virtual void addChildAtIndex(GraphicsLayer *layer, int index); diff --git a/WebCore/platform/graphics/win/SimpleFontDataWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp index 6d1d777..60afe6a 100644 --- a/WebCore/platform/graphics/win/SimpleFontDataWin.cpp +++ b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp @@ -110,24 +110,40 @@ void SimpleFontData::platformDestroy() delete m_scriptFontProperties; } -SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const +SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const { - if (!m_smallCapsFontData) { - float smallCapsHeight = cSmallCapsFontSizeMultiplier * m_platformData.size(); + float scaledSize = scaleFactor * m_platformData.size(); if (isCustomFont()) { - FontPlatformData smallCapsFontData(m_platformData); - smallCapsFontData.setSize(smallCapsHeight); - m_smallCapsFontData = new SimpleFontData(smallCapsFontData, true, false); - } else { - LOGFONT winfont; - GetObject(m_platformData.hfont(), sizeof(LOGFONT), &winfont); - winfont.lfHeight = -lroundf(smallCapsHeight * (m_platformData.useGDI() ? 1 : 32)); - HFONT hfont = CreateFontIndirect(&winfont); - m_smallCapsFontData = new SimpleFontData(FontPlatformData(hfont, smallCapsHeight, m_platformData.syntheticBold(), m_platformData.syntheticOblique(), m_platformData.useGDI()), - isCustomFont(), false); + FontPlatformData scaledFont(m_platformData); + scaledFont.setSize(scaledSize); + return new SimpleFontData(scaledFont, true, false); } - } - return m_smallCapsFontData; + + LOGFONT winfont; + GetObject(m_platformData.hfont(), sizeof(LOGFONT), &winfont); + winfont.lfHeight = -lroundf(scaledSize * (m_platformData.useGDI() ? 1 : 32)); + HFONT hfont = CreateFontIndirect(&winfont); + return new SimpleFontData(FontPlatformData(hfont, scaledSize, m_platformData.syntheticBold(), m_platformData.syntheticOblique(), m_platformData.useGDI()), isCustomFont(), false); +} + +SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const +{ + if (!m_derivedFontData) + m_derivedFontData = DerivedFontData::create(isCustomFont()); + if (!m_derivedFontData->smallCaps) + m_derivedFontData->smallCaps = scaledFontData(fontDescription, cSmallCapsFontSizeMultiplier); + + return m_derivedFontData->smallCaps.get(); +} + +SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const +{ + if (!m_derivedFontData) + m_derivedFontData = DerivedFontData::create(isCustomFont()); + if (!m_derivedFontData->emphasisMark) + m_derivedFontData->emphasisMark = scaledFontData(fontDescription, .5); + + return m_derivedFontData->emphasisMark.get(); } bool SimpleFontData::containsCharacters(const UChar* characters, int length) const diff --git a/WebCore/platform/graphics/win/UniscribeController.cpp b/WebCore/platform/graphics/win/UniscribeController.cpp index d0acac2..ab32150 100644 --- a/WebCore/platform/graphics/win/UniscribeController.cpp +++ b/WebCore/platform/graphics/win/UniscribeController.cpp @@ -145,7 +145,7 @@ void UniscribeController::advance(unsigned offset, GlyphBuffer* glyphBuffer) UChar c = *curr; bool forceSmallCaps = isSmallCaps && (U_GET_GC_MASK(c) & U_GC_M_MASK); - nextFontData = m_font.glyphDataForCharacter(*curr, false, forceSmallCaps).fontData; + nextFontData = m_font.glyphDataForCharacter(*curr, false, forceSmallCaps ? SmallCapsVariant : AutoVariant).fontData; if (m_font.isSmallCaps()) { nextIsSmallCaps = forceSmallCaps || (newC = u_toupper(c)) != c; if (nextIsSmallCaps) diff --git a/WebCore/platform/graphics/win/cairo/FontPlatformData.h b/WebCore/platform/graphics/win/cairo/FontPlatformData.h index 05f9eab..d8f538a 100644 --- a/WebCore/platform/graphics/win/cairo/FontPlatformData.h +++ b/WebCore/platform/graphics/win/cairo/FontPlatformData.h @@ -3,6 +3,7 @@ * 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 @@ -25,7 +26,7 @@ #ifndef FontPlatformDataCairoWin_h #define FontPlatformDataCairoWin_h -#include "FontDescription.h" +#include "FontOrientation.h" #include "GlyphBuffer.h" #include "RefCountedGDIHandle.h" #include "StringImpl.h" @@ -37,6 +38,8 @@ typedef struct HFONT__* HFONT; namespace WebCore { +class FontDescription; + class FontPlatformData { public: FontPlatformData(WTF::HashTableDeletedValueType) @@ -73,6 +76,9 @@ public: 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 diff --git a/WebCore/platform/graphics/wince/FontWinCE.cpp b/WebCore/platform/graphics/wince/FontWinCE.cpp index e2ff067..d636517 100644 --- a/WebCore/platform/graphics/wince/FontWinCE.cpp +++ b/WebCore/platform/graphics/wince/FontWinCE.cpp @@ -235,6 +235,11 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F } } +void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const +{ + notImplemented(); +} + float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { TextRunComponents components; diff --git a/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp b/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp index 0802826..1ea1a64 100644 --- a/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp +++ b/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp @@ -28,7 +28,6 @@ #include "GDIExtras.h" #include "GlyphBuffer.h" #include "Gradient.h" -#include "GraphicsContextPrivate.h" #include "NotImplemented.h" #include "Path.h" #include "PlatformPathWinCE.h" @@ -173,7 +172,6 @@ public: AffineTransform m_transform; float m_opacity; - Vector<Path> m_paths; }; enum AlphaPaintType { @@ -581,15 +579,13 @@ private: }; -GraphicsContext::GraphicsContext(PlatformGraphicsContext* dc) -: m_common(createGraphicsContextPrivate()) -, m_data(new GraphicsContextPlatformPrivate(dc)) +void GraphicsContext::platformInit(PlatformGraphicsContext* dc) { + m_data = new GraphicsContextPlatformPrivate(dc); } -GraphicsContext::~GraphicsContext() +void GraphicsContext::platformDestroy() { - destroyGraphicsContextPrivate(m_common); delete m_data; } @@ -1177,21 +1173,11 @@ void GraphicsContext::setAlpha(float alpha) m_data->m_opacity = alpha; } -void GraphicsContext::setCompositeOperation(CompositeOperator op) +void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op) { notImplemented(); } -void GraphicsContext::beginPath() -{ - m_data->m_paths.clear(); -} - -void GraphicsContext::addPath(const Path& path) -{ - m_data->m_paths.append(path); -} - void GraphicsContext::clip(const Path& path) { notImplemented(); @@ -1220,8 +1206,9 @@ void GraphicsContext::fillRoundedRect(const IntRect& fillRect, const IntSize& to FloatSize shadowOffset; float shadowBlur = 0; Color shadowColor; + ColorSpace shadowColorSpace; - getShadow(shadowOffset, shadowBlur, shadowColor); + getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace); IntRect dstRect = fillRect; @@ -1325,10 +1312,10 @@ Color gradientAverageColor(const Gradient* gradient) , (stop.alpha + lastStop.alpha) * 0.5f); } -void GraphicsContext::fillPath() +void GraphicsContext::fillPath(const Path& path) { - Color c = m_common->state.fillGradient - ? gradientAverageColor(m_common->state.fillGradient.get()) + Color c = m_state.fillGradient + ? gradientAverageColor(m_state.fillGradient.get()) : fillColor(); if (!c.alpha() || !m_data->m_opacity) @@ -1341,33 +1328,30 @@ void GraphicsContext::fillPath() OwnPtr<HBRUSH> brush = createBrush(c); if (m_data->m_opacity < 1.0f || m_data->hasAlpha()) { - for (Vector<Path>::const_iterator i = m_data->m_paths.begin(); i != m_data->m_paths.end(); ++i) { - IntRect trRect = enclosingIntRect(m_data->mapRect(i->boundingRect())); - trRect.inflate(1); - TransparentLayerDC transparentDC(m_data, trRect); - HDC dc = transparentDC.hdc(); - if (!dc) - continue; - - AffineTransform tr = m_data->m_transform; - tr.translate(transparentDC.toShift().width(), transparentDC.toShift().height()); - - SelectObject(dc, GetStockObject(NULL_PEN)); - HGDIOBJ oldBrush = SelectObject(dc, brush.get()); - i->platformPath()->fillPath(dc, &tr); - SelectObject(dc, oldBrush); - } + IntRect trRect = enclosingIntRect(m_data->mapRect(path.boundingRect())); + trRect.inflate(1); + TransparentLayerDC transparentDC(m_data, trRect); + HDC dc = transparentDC.hdc(); + if (!dc) + return; + + AffineTransform tr = m_data->m_transform; + tr.translate(transparentDC.toShift().width(), transparentDC.toShift().height()); + + SelectObject(dc, GetStockObject(NULL_PEN)); + HGDIOBJ oldBrush = SelectObject(dc, brush.get()); + path.platformPath()->fillPath(dc, &tr); + SelectObject(dc, oldBrush); } else { SelectObject(m_data->m_dc, GetStockObject(NULL_PEN)); HGDIOBJ oldBrush = SelectObject(m_data->m_dc, brush.get()); - for (Vector<Path>::const_iterator i = m_data->m_paths.begin(); i != m_data->m_paths.end(); ++i) - i->platformPath()->fillPath(m_data->m_dc, &m_data->m_transform); + path.platformPath()->fillPath(m_data->m_dc, &m_data->m_transform); SelectObject(m_data->m_dc, oldBrush); } } -void GraphicsContext::strokePath() +void GraphicsContext::strokePath(const Path& path) { if (!m_data->m_opacity) return; @@ -1379,27 +1363,24 @@ void GraphicsContext::strokePath() OwnPtr<HPEN> pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); if (m_data->m_opacity < 1.0f || m_data->hasAlpha()) { - for (Vector<Path>::const_iterator i = m_data->m_paths.begin(); i != m_data->m_paths.end(); ++i) { - IntRect trRect = enclosingIntRect(m_data->mapRect(i->boundingRect())); - trRect.inflate(1); - TransparentLayerDC transparentDC(m_data, trRect); - HDC dc = transparentDC.hdc(); - if (!dc) - continue; - - AffineTransform tr = m_data->m_transform; - tr.translate(transparentDC.toShift().width(), transparentDC.toShift().height()); - - SelectObject(dc, GetStockObject(NULL_BRUSH)); - HGDIOBJ oldPen = SelectObject(dc, pen.get()); - i->platformPath()->strokePath(dc, &tr); - SelectObject(dc, oldPen); - } + IntRect trRect = enclosingIntRect(m_data->mapRect(path.boundingRect())); + trRect.inflate(1); + TransparentLayerDC transparentDC(m_data, trRect); + HDC dc = transparentDC.hdc(); + if (!dc) + return; + + AffineTransform tr = m_data->m_transform; + tr.translate(transparentDC.toShift().width(), transparentDC.toShift().height()); + + SelectObject(dc, GetStockObject(NULL_BRUSH)); + HGDIOBJ oldPen = SelectObject(dc, pen.get()); + path.platformPath()->strokePath(dc, &tr); + SelectObject(dc, oldPen); } else { SelectObject(m_data->m_dc, GetStockObject(NULL_BRUSH)); HGDIOBJ oldPen = SelectObject(m_data->m_dc, pen.get()); - for (Vector<Path>::const_iterator i = m_data->m_paths.begin(); i != m_data->m_paths.end(); ++i) - i->platformPath()->strokePath(m_data->m_dc, &m_data->m_transform); + path.platformPath()->strokePath(m_data->m_dc, &m_data->m_transform); SelectObject(m_data->m_dc, oldPen); } } @@ -1504,8 +1485,8 @@ void GraphicsContext::fillRect(const FloatRect& rect) { savePlatformState(); - if (m_common->state.fillGradient) - fillRect(rect, m_common->state.fillGradient.get()); + if (m_state.fillGradient) + fillRect(rect, m_state.fillGradient.get()); else fillRect(rect, fillColor(), ColorSpaceDeviceRGB); @@ -1643,8 +1624,9 @@ void GraphicsContext::drawText(const SimpleFontData* fontData, const GlyphBuffer FloatSize shadowOffset; float shadowBlur = 0; Color shadowColor; - bool hasShadow = textDrawingMode() == cTextFill - && getShadow(shadowOffset, shadowBlur, shadowColor) + ColorSpace shadowColorSpace; + bool hasShadow = textDrawingMode() == TextModeFill + && getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace) && shadowColor.alpha(); COLORREF shadowRGBColor; FloatPoint trShadowPoint; @@ -1900,7 +1882,7 @@ void GraphicsContext::setLineDash(const DashArray&, float) notImplemented(); } -void GraphicsContext::clipPath(WindRule) +void GraphicsContext::clipPath(const Path&, WindRule) { notImplemented(); } diff --git a/WebCore/platform/graphics/wince/ImageBufferWinCE.cpp b/WebCore/platform/graphics/wince/ImageBufferWinCE.cpp index ec8517b..e6edb41 100644 --- a/WebCore/platform/graphics/wince/ImageBufferWinCE.cpp +++ b/WebCore/platform/graphics/wince/ImageBufferWinCE.cpp @@ -72,7 +72,7 @@ ImageBufferData::ImageBufferData(const IntSize& size) m_bitmap->setHasAlpha(true); } -ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace colorSpace, bool& success) +ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace colorSpace, RenderingMode, bool& success) : m_data(size) , m_size(size) { diff --git a/WebCore/platform/graphics/wince/SimpleFontDataWinCE.cpp b/WebCore/platform/graphics/wince/SimpleFontDataWinCE.cpp index c8c5474..27a021e 100644 --- a/WebCore/platform/graphics/wince/SimpleFontDataWinCE.cpp +++ b/WebCore/platform/graphics/wince/SimpleFontDataWinCE.cpp @@ -60,22 +60,36 @@ void SimpleFontData::platformInit() void SimpleFontData::platformDestroy() { - delete m_smallCapsFontData; - m_smallCapsFontData = 0; +} + +SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const +{ + FontDescription fontDesc(fontDescription); + fontDesc.setComputedSize(lroundf(scaleFactor * fontDesc.computedSize())); + fontDesc.setSpecifiedSize(lroundf(scaleFactor * fontDesc.specifiedSize())); + fontDesc.setKeywordSize(lroundf(scaleFactor * fontDesc.keywordSize())); + FontPlatformData* result = fontCache()->getCachedFontPlatformData(fontDesc, m_platformData.family()); + return result ? new SimpleFontData(*result) : 0; } SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const { - if (!m_smallCapsFontData) { - FontDescription fontDesc(fontDescription); - fontDesc.setComputedSize(lroundf(0.70f * fontDesc.computedSize())); - fontDesc.setSpecifiedSize(lroundf(0.70f * fontDesc.specifiedSize())); - fontDesc.setKeywordSize(lroundf(0.70f * fontDesc.keywordSize())); - FontPlatformData* result = fontCache()->getCachedFontPlatformData(fontDesc, m_platformData.family()); - if (result) - m_smallCapsFontData = new SimpleFontData(*result); - } - return m_smallCapsFontData; + if (!m_derivedFontData) + m_derivedFontData = DerivedFontData::create(isCustomFont()); + if (!m_derivedFontData->smallCaps) + m_derivedFontData->smallCaps = scaledFontData(fontDescription, .7); + + return m_derivedFontData->smallCaps.get(); +} + +SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const +{ + if (!m_derivedFontData) + m_derivedFontData = DerivedFontData::create(isCustomFont()); + if (!m_derivedFontData->emphasisMark) + m_derivedFontData->emphasisMark = scaledFontData(fontDescription, .5); + + return m_derivedFontData->emphasisMark.get(); } DWORD getKnownFontCodePages(const wchar_t* family); diff --git a/WebCore/platform/graphics/wx/FontWx.cpp b/WebCore/platform/graphics/wx/FontWx.cpp index cc45ab0..c01e249 100644 --- a/WebCore/platform/graphics/wx/FontWx.cpp +++ b/WebCore/platform/graphics/wx/FontWx.cpp @@ -98,6 +98,14 @@ FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint #endif } +float Font::getGlyphsAndAdvancesForComplexText(const TextRun& /* run */, int /* from */, int /* to */, GlyphBuffer& /* glyphBuffer */, ForTextEmphasisOrNot /* forTextEmphasis */) const +{ + // FIXME: Implement this by moving most of the drawComplexText() implementation in here. Set up the + // ComplexTextController according to forTextEmphasis. + notImplemented(); + return 0; +} + void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const { #if OS(WINDOWS) || OS(DARWIN) @@ -130,12 +138,22 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F // Draw the glyph buffer now at the starting point returned in startX. FloatPoint startPoint(startX, point.y()); - drawGlyphBuffer(context, glyphBuffer, run, startPoint); + drawGlyphBuffer(context, glyphBuffer, startPoint); #else notImplemented(); #endif } +void Font::drawEmphasisMarksForComplexText(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const +{ + GlyphBuffer glyphBuffer; + float initialAdvance = getGlyphsAndAdvancesForComplexText(run, from, to, glyphBuffer, ForTextEmphasis); + + if (glyphBuffer.isEmpty()) + return; + + drawEmphasisMarks(context, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y())); +} float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow*) const { diff --git a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp index 5007ffe..cee6aee 100644 --- a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp +++ b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp @@ -91,7 +91,6 @@ public: #if USE(WXGC) wxGCDC* context; - wxGraphicsPath currentPath; #else wxWindowDC* context; #endif @@ -113,11 +112,11 @@ GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate() } -GraphicsContext::GraphicsContext(PlatformGraphicsContext* context) - : m_common(createGraphicsContextPrivate()) - , m_data(new GraphicsContextPlatformPrivate) -{ +void GraphicsContext::platformInit(PlatformGraphicsContext* context) +{ + m_data = new GraphicsContextPlatformPrivate; setPaintingDisabled(!context); + if (context) { // Make sure the context starts in sync with our state. setPlatformFillColor(fillColor(), ColorSpaceDeviceRGB); @@ -125,17 +124,13 @@ GraphicsContext::GraphicsContext(PlatformGraphicsContext* context) } #if USE(WXGC) m_data->context = (wxGCDC*)context; - wxGraphicsContext* gc = m_data->context->GetGraphicsContext(); - if (gc) - m_data->currentPath = gc->CreatePath(); #else m_data->context = (wxWindowDC*)context; #endif } -GraphicsContext::~GraphicsContext() +void GraphicsContext::platformDestroy() { - destroyGraphicsContextPrivate(m_common); delete m_data; } @@ -337,7 +332,7 @@ void GraphicsContext::clipOut(const IntRect&) notImplemented(); } -void GraphicsContext::clipPath(WindRule) +void GraphicsContext::clipPath(const Path&, WindRule) { notImplemented(); } @@ -447,7 +442,7 @@ void GraphicsContext::setURLForRect(const KURL&, const IntRect&) notImplemented(); } -void GraphicsContext::setCompositeOperation(CompositeOperator op) +void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op) { if (m_data->context) { @@ -459,23 +454,6 @@ void GraphicsContext::setCompositeOperation(CompositeOperator op) } } -void GraphicsContext::beginPath() -{ -#if USE(WXGC) - wxGraphicsContext* gc = m_data->context->GetGraphicsContext(); - if (gc) - m_data->currentPath = gc->CreatePath(); -#endif -} - -void GraphicsContext::addPath(const Path& path) -{ -#if USE(WXGC) - if (path.platformPath()) - m_data->currentPath.AddPath(*path.platformPath()); -#endif -} - void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) @@ -533,30 +511,24 @@ InterpolationQuality GraphicsContext::imageInterpolationQuality() const return InterpolationDefault; } -void GraphicsContext::fillPath() +void GraphicsContext::fillPath(const Path& path) { #if USE(WXGC) wxGraphicsContext* gc = m_data->context->GetGraphicsContext(); if (gc) - gc->FillPath(m_data->currentPath); + gc->FillPath(path.platformPath()); #endif } -void GraphicsContext::strokePath() +void GraphicsContext::strokePath(const Path& path) { #if USE(WXGC) wxGraphicsContext* gc = m_data->context->GetGraphicsContext(); if (gc) - gc->StrokePath(m_data->currentPath); + gc->StrokePath(path.platformPath()); #endif } -void GraphicsContext::drawPath() -{ - fillPath(); - strokePath(); -} - void GraphicsContext::fillRect(const FloatRect& rect) { if (paintingDisabled()) diff --git a/WebCore/platform/graphics/wx/ImageBufferWx.cpp b/WebCore/platform/graphics/wx/ImageBufferWx.cpp index 2522cbd..74c9c39 100644 --- a/WebCore/platform/graphics/wx/ImageBufferWx.cpp +++ b/WebCore/platform/graphics/wx/ImageBufferWx.cpp @@ -37,7 +37,7 @@ ImageBufferData::ImageBufferData(const IntSize&) { } -ImageBuffer::ImageBuffer(const IntSize&, ImageColorSpace imageColorSpace, bool& success) : +ImageBuffer::ImageBuffer(const IntSize&, ColorSpace imageColorSpace, RenderingMode, bool& success) : m_data(IntSize()) { notImplemented(); diff --git a/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp b/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp index 96129f9..0e24bfc 100644 --- a/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp +++ b/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp @@ -90,15 +90,32 @@ void SimpleFontData::platformDestroy() #endif } +SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const +{ + FontDescription desc = FontDescription(fontDescription); + desc.setSpecifiedSize(scaleFactor * fontDescription.computedSize()); + FontPlatformData platformData(desc, desc.family().family()); + return new SimpleFontData(platformData, isCustomFont(), false); +} + SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const { - if (!m_smallCapsFontData){ - FontDescription desc = FontDescription(fontDescription); - desc.setSpecifiedSize(0.70f * fontDescription.computedSize()); - FontPlatformData platformData(desc, desc.family().family()); - m_smallCapsFontData = new SimpleFontData(platformData, isCustomFont(), false); - } - return m_smallCapsFontData; + if (!m_derivedFontData) + m_derivedFontData = DerivedFontData::create(isCustomFont()); + if (!m_derivedFontData->smallCaps) + m_derivedFontData->smallCaps = scaledFontData(fontDescription, .7); + + return m_derivedFontData->smallCaps.get(); +} + +SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const +{ + if (!m_derivedFontData) + m_derivedFontData = DerivedFontData::create(isCustomFont()); + if (!m_derivedFontData->emphasisMark) + m_derivedFontData->emphasisMark = scaledFontData(fontDescription, .5); + + return m_derivedFontData->emphasisMark.get(); } bool SimpleFontData::containsCharacters(const UChar* characters, int length) const diff --git a/WebCore/platform/gtk/ContextMenuGtk.cpp b/WebCore/platform/gtk/ContextMenuGtk.cpp index 210cfa6..423959a 100644 --- a/WebCore/platform/gtk/ContextMenuGtk.cpp +++ b/WebCore/platform/gtk/ContextMenuGtk.cpp @@ -19,23 +19,11 @@ #include "config.h" #include "ContextMenu.h" -#include "ContextMenuController.h" - #include <gtk/gtk.h> namespace WebCore { -// TODO: ref-counting correctness checking. -// See http://bugs.webkit.org/show_bug.cgi?id=16115 - -static void menuItemActivated(GtkMenuItem* item, ContextMenuController* controller) -{ - ContextMenuItem contextItem(item); - controller->contextMenuItemSelected(&contextItem); -} - -ContextMenu::ContextMenu(const HitTestResult& result) - : m_hitTestResult(result) +ContextMenu::ContextMenu() { m_platformDescription = GTK_MENU(gtk_menu_new()); @@ -51,15 +39,9 @@ ContextMenu::~ContextMenu() void ContextMenu::appendItem(ContextMenuItem& item) { ASSERT(m_platformDescription); - checkOrEnableIfNeeded(item); - ContextMenuItemType type = item.type(); - GtkMenuItem* platformItem = ContextMenuItem::createNativeMenuItem(item.releasePlatformDescription()); + GtkMenuItem* platformItem = item.releasePlatformDescription(); ASSERT(platformItem); - - if (type == ActionType || type == CheckableActionType) - g_signal_connect(platformItem, "activate", G_CALLBACK(menuItemActivated), controller()); - gtk_menu_shell_append(GTK_MENU_SHELL(m_platformDescription), GTK_WIDGET(platformItem)); gtk_widget_show(GTK_WIDGET(platformItem)); } diff --git a/WebCore/platform/gtk/ContextMenuItemGtk.cpp b/WebCore/platform/gtk/ContextMenuItemGtk.cpp index 68d0a9a..4d79f13 100644 --- a/WebCore/platform/gtk/ContextMenuItemGtk.cpp +++ b/WebCore/platform/gtk/ContextMenuItemGtk.cpp @@ -18,12 +18,14 @@ */ #include "config.h" -#include "ContextMenu.h" + #include "ContextMenuItem.h" -#include "NotImplemented.h" -#include <wtf/text/CString.h> +#include "ContextMenu.h" +#include "GOwnPtr.h" +#include "NotImplemented.h" #include <gtk/gtk.h> +#include <wtf/text/CString.h> #define WEBKIT_CONTEXT_MENU_ACTION "webkit-context-menu" @@ -114,30 +116,9 @@ static const char* gtkStockIDFromContextMenuAction(const ContextMenuAction& acti } // Extract the ActionType from the menu item -ContextMenuItem::ContextMenuItem(GtkMenuItem* item) - : m_platformDescription() +ContextMenuItem::ContextMenuItem(PlatformMenuItemDescription item) + : m_platformDescription(item) { - if (GTK_IS_SEPARATOR_MENU_ITEM(item)) - m_platformDescription.type = SeparatorType; - else if (gtk_menu_item_get_submenu(item)) - m_platformDescription.type = SubmenuType; - else if (GTK_IS_CHECK_MENU_ITEM(item)) { - m_platformDescription.type = CheckableActionType; - m_platformDescription.checked = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item)); - } else - m_platformDescription.type = ActionType; -#if GTK_CHECK_VERSION (2, 16, 0) - m_platformDescription.title = String::fromUTF8(gtk_menu_item_get_label(GTK_MENU_ITEM(item))); -#else - GtkWidget* label = gtk_bin_get_child(GTK_BIN(item)); - m_platformDescription.title = String::fromUTF8(gtk_label_get_label(GTK_LABEL(label))); -#endif - - m_platformDescription.action = *static_cast<ContextMenuAction*>(g_object_get_data(G_OBJECT(item), WEBKIT_CONTEXT_MENU_ACTION)); - - m_platformDescription.subMenu = GTK_MENU(gtk_menu_item_get_submenu(item)); - if (m_platformDescription.subMenu) - g_object_ref(m_platformDescription.subMenu); } ContextMenuItem::ContextMenuItem(ContextMenu*) @@ -147,114 +128,100 @@ ContextMenuItem::ContextMenuItem(ContextMenu*) ContextMenuItem::ContextMenuItem(ContextMenuItemType type, ContextMenuAction action, const String& title, ContextMenu* subMenu) { - m_platformDescription.type = type; - m_platformDescription.action = action; - m_platformDescription.title = title; + if (type == SeparatorType) { + m_platformDescription = GTK_MENU_ITEM(gtk_separator_menu_item_new()); + return; + } - setSubMenu(subMenu); -} + GOwnPtr<char> actionName(g_strdup_printf("context-menu-action-%d", action)); + GtkAction* platformAction = 0; -ContextMenuItem::~ContextMenuItem() -{ - if (m_platformDescription.subMenu) - g_object_unref(m_platformDescription.subMenu); -} - -GtkMenuItem* ContextMenuItem::createNativeMenuItem(const PlatformMenuItemDescription& menu) -{ - GtkMenuItem* item = 0; - if (menu.type == SeparatorType) - item = GTK_MENU_ITEM(gtk_separator_menu_item_new()); - else { - if (menu.type == CheckableActionType) { - item = GTK_MENU_ITEM(gtk_check_menu_item_new_with_mnemonic(menu.title.utf8().data())); - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), menu.checked); - } else { - if (const gchar* stockID = gtkStockIDFromContextMenuAction(menu.action)) { - item = GTK_MENU_ITEM(gtk_image_menu_item_new_with_mnemonic(menu.title.utf8().data())); - GtkWidget* image = gtk_image_new_from_stock(stockID, GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image); - } else - item = GTK_MENU_ITEM(gtk_menu_item_new_with_mnemonic(menu.title.utf8().data())); - } + if (type == CheckableActionType) + platformAction = GTK_ACTION(gtk_toggle_action_new(actionName.get(), title.utf8().data(), 0, gtkStockIDFromContextMenuAction(action))); + else + platformAction = gtk_action_new(actionName.get(), title.utf8().data(), 0, gtkStockIDFromContextMenuAction(action)); - ContextMenuAction* menuAction = static_cast<ContextMenuAction*>(malloc(sizeof(ContextMenuAction*))); - *menuAction = menu.action; - g_object_set_data(G_OBJECT(item), WEBKIT_CONTEXT_MENU_ACTION, menuAction); + m_platformDescription = GTK_MENU_ITEM(gtk_action_create_menu_item(platformAction)); + g_object_unref(platformAction); - gtk_widget_set_sensitive(GTK_WIDGET(item), menu.enabled); + g_object_set_data(G_OBJECT(m_platformDescription.get()), WEBKIT_CONTEXT_MENU_ACTION, GINT_TO_POINTER(action)); - if (menu.subMenu) - gtk_menu_item_set_submenu(item, GTK_WIDGET(menu.subMenu)); - } + if (subMenu) + setSubMenu(subMenu); +} - return item; +ContextMenuItem::~ContextMenuItem() +{ } PlatformMenuItemDescription ContextMenuItem::releasePlatformDescription() { - PlatformMenuItemDescription description = m_platformDescription; - m_platformDescription = PlatformMenuItemDescription(); - return description; + return m_platformDescription.leakRef(); } ContextMenuItemType ContextMenuItem::type() const { - return m_platformDescription.type; + if (GTK_IS_SEPARATOR_MENU_ITEM(m_platformDescription.get())) + return SeparatorType; + if (GTK_IS_CHECK_MENU_ITEM(m_platformDescription.get())) + return CheckableActionType; + if (gtk_menu_item_get_submenu(m_platformDescription.get())) + return SubmenuType; + return ActionType; } void ContextMenuItem::setType(ContextMenuItemType type) { - m_platformDescription.type = type; + if (type == SeparatorType) + m_platformDescription = GTK_MENU_ITEM(gtk_separator_menu_item_new()); } ContextMenuAction ContextMenuItem::action() const { - return m_platformDescription.action; + return static_cast<ContextMenuAction>(GPOINTER_TO_INT(g_object_get_data(G_OBJECT(m_platformDescription.get()), WEBKIT_CONTEXT_MENU_ACTION))); } void ContextMenuItem::setAction(ContextMenuAction action) { - m_platformDescription.action = action; + g_object_set_data(G_OBJECT(m_platformDescription.get()), WEBKIT_CONTEXT_MENU_ACTION, GINT_TO_POINTER(action)); } String ContextMenuItem::title() const { - return m_platformDescription.title; + GtkAction* action = gtk_activatable_get_related_action(GTK_ACTIVATABLE(m_platformDescription.get())); + return action ? String(gtk_action_get_label(action)) : String(); } void ContextMenuItem::setTitle(const String& title) { - m_platformDescription.title = title; + GtkAction* action = gtk_activatable_get_related_action(GTK_ACTIVATABLE(m_platformDescription.get())); + if (action) + gtk_action_set_label(action, title.utf8().data()); } PlatformMenuDescription ContextMenuItem::platformSubMenu() const { - return m_platformDescription.subMenu; + GtkWidget* subMenu = gtk_menu_item_get_submenu(m_platformDescription.get()); + return subMenu ? GTK_MENU(subMenu) : 0; } void ContextMenuItem::setSubMenu(ContextMenu* menu) { - if (m_platformDescription.subMenu) - g_object_unref(m_platformDescription.subMenu); - - if (!menu) - return; - - m_platformDescription.subMenu = menu->releasePlatformDescription(); - m_platformDescription.type = SubmenuType; - - g_object_ref_sink(G_OBJECT(m_platformDescription.subMenu)); + gtk_menu_item_set_submenu(m_platformDescription.get(), GTK_WIDGET(menu->platformDescription())); } void ContextMenuItem::setChecked(bool shouldCheck) { - m_platformDescription.checked = shouldCheck; + GtkAction* action = gtk_activatable_get_related_action(GTK_ACTIVATABLE(m_platformDescription.get())); + if (action && GTK_IS_TOGGLE_ACTION(action)) + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), shouldCheck); } void ContextMenuItem::setEnabled(bool shouldEnable) { - m_platformDescription.enabled = shouldEnable; + GtkAction* action = gtk_activatable_get_related_action(GTK_ACTIVATABLE(m_platformDescription.get())); + if (action) + gtk_action_set_sensitive(action, shouldEnable); } } diff --git a/WebCore/platform/gtk/GtkVersioning.h b/WebCore/platform/gtk/GtkVersioning.h index ea15a54..11d1f8a 100644 --- a/WebCore/platform/gtk/GtkVersioning.h +++ b/WebCore/platform/gtk/GtkVersioning.h @@ -31,7 +31,7 @@ G_BEGIN_DECLS // Macros to avoid deprecation checking churn #ifndef GTK_API_VERSION_2 -#define GDK_DISPLAY() (GDK_DISPLAY_XDISPLAY(gdk_display_get_default())) +#define GDK_WINDOW_XWINDOW(window) (gdk_x11_window_get_xid(window)) #else GdkPixbuf* gdk_pixbuf_get_from_surface(cairo_surface_t* surface, int srcX, int srcY, int width, int height); diff --git a/WebCore/platform/gtk/PasteboardHelper.cpp b/WebCore/platform/gtk/PasteboardHelper.cpp index 228d5e9..4428be0 100644 --- a/WebCore/platform/gtk/PasteboardHelper.cpp +++ b/WebCore/platform/gtk/PasteboardHelper.cpp @@ -34,11 +34,11 @@ namespace WebCore { -static GdkAtom textPlainAtom = gdk_atom_intern("text/plain;charset=utf-8", FALSE); -static GdkAtom markupAtom = gdk_atom_intern("text/html", FALSE); -static GdkAtom netscapeURLAtom = gdk_atom_intern("_NETSCAPE_URL", FALSE); -static GdkAtom uriListAtom = gdk_atom_intern("text/uri-list", FALSE); -static String gMarkupPrefix = "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">"; +static GdkAtom textPlainAtom; +static GdkAtom markupAtom; +static GdkAtom netscapeURLAtom; +static GdkAtom uriListAtom; +static String gMarkupPrefix; static void removeMarkupPrefix(String& markup) { @@ -49,9 +49,26 @@ static void removeMarkupPrefix(String& markup) markup.remove(0, gMarkupPrefix.length()); } +static void initGdkAtoms() +{ + static gboolean initialized = FALSE; + + if (initialized) + return; + + initialized = TRUE; + + textPlainAtom = gdk_atom_intern("text/plain;charset=utf-8", FALSE); + markupAtom = gdk_atom_intern("text/html", FALSE); + netscapeURLAtom = gdk_atom_intern("_NETSCAPE_URL", FALSE); + uriListAtom = gdk_atom_intern("text/uri-list", FALSE); + gMarkupPrefix = "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">"; +} + PasteboardHelper::PasteboardHelper() : m_targetList(gtk_target_list_new(0, 0)) { + initGdkAtoms(); } PasteboardHelper::~PasteboardHelper() diff --git a/WebCore/platform/gtk/PlatformScreenGtk.cpp b/WebCore/platform/gtk/PlatformScreenGtk.cpp index 9c70d0e..40b509e 100644 --- a/WebCore/platform/gtk/PlatformScreenGtk.cpp +++ b/WebCore/platform/gtk/PlatformScreenGtk.cpp @@ -121,7 +121,7 @@ FloatRect screenAvailableRect(Widget* widget) if (!gtk_widget_get_realized(container)) return screenRect(widget); - GdkDrawable* rootWindow = GDK_DRAWABLE(gtk_widget_get_root_window(container)); + GdkWindow* rootWindow = gtk_widget_get_root_window(container); GdkDisplay* display = gdk_window_get_display(rootWindow); Atom xproperty = gdk_x11_get_xatom_by_name_for_display(display, "_NET_WORKAREA"); diff --git a/WebCore/platform/gtk/PopupMenuGtk.cpp b/WebCore/platform/gtk/PopupMenuGtk.cpp index e7ff78e..b2466c5 100644 --- a/WebCore/platform/gtk/PopupMenuGtk.cpp +++ b/WebCore/platform/gtk/PopupMenuGtk.cpp @@ -5,6 +5,7 @@ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com * Copyright (C) 2008 Collabora Ltd. * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2010 Igalia S.L. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -27,16 +28,22 @@ #include "PopupMenuGtk.h" #include "FrameView.h" +#include "GOwnPtr.h" #include "GtkVersioning.h" #include "HostWindow.h" #include "PlatformString.h" -#include <wtf/text/CString.h> +#include <gdk/gdk.h> #include <gtk/gtk.h> +#include <wtf/text/CString.h> namespace WebCore { +static const uint32_t gSearchTimeoutMs = 1000; + PopupMenuGtk::PopupMenuGtk(PopupMenuClient* client) : m_popupClient(client) + , m_previousKeyEventCharacter(0) + , m_currentlySelectedMenuItem(0) { } @@ -54,12 +61,16 @@ void PopupMenuGtk::show(const IntRect& rect, FrameView* view, int index) if (!m_popup) { m_popup = GTK_MENU(gtk_menu_new()); - g_signal_connect(m_popup.get(), "unmap", G_CALLBACK(menuUnmapped), this); + g_signal_connect(m_popup.get(), "unmap", G_CALLBACK(PopupMenuGtk::menuUnmapped), this); + g_signal_connect(m_popup.get(), "key-press-event", G_CALLBACK(PopupMenuGtk::keyPressEventCallback), this); } else gtk_container_foreach(GTK_CONTAINER(m_popup.get()), reinterpret_cast<GtkCallback>(menuRemoveItem), this); - int x, y; - gdk_window_get_origin(gtk_widget_get_window(GTK_WIDGET(view->hostWindow()->platformPageClient())), &x, &y); + int x = 0; + int y = 0; + GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(view->hostWindow()->platformPageClient())); + if (window) + gdk_window_get_origin(window, &x, &y); m_menuPosition = view->contentsToWindow(rect.location()); m_menuPosition = IntPoint(m_menuPosition.x() + x, m_menuPosition.y() + y + rect.height()); m_indexMap.clear(); @@ -73,7 +84,8 @@ void PopupMenuGtk::show(const IntRect& rect, FrameView* view, int index) item = gtk_menu_item_new_with_label(client()->itemText(i).utf8().data()); m_indexMap.add(item, i); - g_signal_connect(item, "activate", G_CALLBACK(menuItemActivated), this); + g_signal_connect(item, "activate", G_CALLBACK(PopupMenuGtk::menuItemActivated), this); + g_signal_connect(item, "select", G_CALLBACK(PopupMenuGtk::selectItemCallback), this); // FIXME: Apply the PopupMenuStyle from client()->itemStyle(i) gtk_widget_set_sensitive(item, client()->itemIsEnabled(i)); @@ -138,6 +150,77 @@ void PopupMenuGtk::disconnectClient() m_popupClient = 0; } +bool PopupMenuGtk::typeAheadFind(GdkEventKey* event) +{ + // If we were given a non-printable character just skip it. + gunichar unicodeCharacter = gdk_keyval_to_unicode(event->keyval); + if (!unicodeCharacter) { + resetTypeAheadFindState(); + return false; + } + + glong charactersWritten; + GOwnPtr<gunichar2> utf16String(g_ucs4_to_utf16(&unicodeCharacter, 1, 0, &charactersWritten, 0)); + if (!utf16String) { + resetTypeAheadFindState(); + return false; + } + + // If the character is the same as the last character, the user is probably trying to + // cycle through the menulist entries. This matches the WebCore behavior for collapsed + // menulists. + bool repeatingCharacter = unicodeCharacter != m_previousKeyEventCharacter; + if (event->time - m_previousKeyEventTimestamp > gSearchTimeoutMs) + m_currentSearchString = String(static_cast<UChar*>(utf16String.get()), charactersWritten); + else if (repeatingCharacter) + m_currentSearchString.append(String(static_cast<UChar*>(utf16String.get()), charactersWritten)); + + m_previousKeyEventTimestamp = event->time; + m_previousKeyEventCharacter = unicodeCharacter; + + // Like the Chromium port, we case fold before searching, because + // strncmp does not handle non-ASCII characters. + GOwnPtr<gchar> searchStringWithCaseFolded(g_utf8_casefold(m_currentSearchString.utf8().data(), -1)); + size_t prefixLength = strlen(searchStringWithCaseFolded.get()); + + GList* children = gtk_container_get_children(GTK_CONTAINER(m_popup.get())); + if (!children) + return true; + + // If a menu item has already been selected, start searching from the current + // item down the list. This will make multiple key presses of the same character + // advance the selection. + GList* currentChild = children; + if (m_currentlySelectedMenuItem) { + currentChild = g_list_find(children, m_currentlySelectedMenuItem); + if (!currentChild) { + m_currentlySelectedMenuItem = 0; + currentChild = children; + } + + // Repeating characters should iterate. + if (repeatingCharacter) { + if (GList* nextChild = g_list_next(currentChild)) + currentChild = nextChild; + } + } + + GList* firstChild = currentChild; + do { + currentChild = g_list_next(currentChild); + if (!currentChild) + currentChild = children; + + GOwnPtr<gchar> itemText(g_utf8_casefold(gtk_menu_item_get_label(GTK_MENU_ITEM(currentChild->data)), -1)); + if (!strncmp(searchStringWithCaseFolded.get(), itemText.get(), prefixLength)) { + gtk_menu_shell_select_item(GTK_MENU_SHELL(m_popup.get()), GTK_WIDGET(currentChild->data)); + return true; + } + } while (currentChild != firstChild); + + return true; +} + void PopupMenuGtk::menuItemActivated(GtkMenuItem* item, PopupMenuGtk* that) { ASSERT(that->client()); @@ -148,6 +231,7 @@ void PopupMenuGtk::menuItemActivated(GtkMenuItem* item, PopupMenuGtk* that) void PopupMenuGtk::menuUnmapped(GtkWidget*, PopupMenuGtk* that) { ASSERT(that->client()); + that->resetTypeAheadFindState(); that->client()->popupDidHide(); } @@ -158,11 +242,29 @@ void PopupMenuGtk::menuPositionFunction(GtkMenu*, gint* x, gint* y, gboolean* pu *pushIn = true; } +void PopupMenuGtk::resetTypeAheadFindState() +{ + m_currentlySelectedMenuItem = 0; + m_previousKeyEventCharacter = 0; + m_currentSearchString = ""; +} + void PopupMenuGtk::menuRemoveItem(GtkWidget* widget, PopupMenuGtk* that) { ASSERT(that->m_popup); gtk_container_remove(GTK_CONTAINER(that->m_popup.get()), widget); } +int PopupMenuGtk::selectItemCallback(GtkMenuItem* item, PopupMenuGtk* that) +{ + that->m_currentlySelectedMenuItem = GTK_WIDGET(item); + return FALSE; +} + +int PopupMenuGtk::keyPressEventCallback(GtkWidget* widget, GdkEventKey* event, PopupMenuGtk* that) +{ + return that->typeAheadFind(event); +} + } diff --git a/WebCore/platform/gtk/PopupMenuGtk.h b/WebCore/platform/gtk/PopupMenuGtk.h index 8848e06..e47fda6 100644 --- a/WebCore/platform/gtk/PopupMenuGtk.h +++ b/WebCore/platform/gtk/PopupMenuGtk.h @@ -24,11 +24,12 @@ #include "IntRect.h" #include "PopupMenu.h" #include "PopupMenuClient.h" -#include <glib.h> #include <wtf/HashMap.h> #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> +typedef struct _GdkEventKey GdkEventKey; + namespace WebCore { class FrameView; @@ -43,19 +44,27 @@ public: virtual void hide(); virtual void updateFromElement(); virtual void disconnectClient(); + bool typeAheadFind(GdkEventKey*); private: PopupMenuClient* client() const { return m_popupClient; } + void resetTypeAheadFindState(); static void menuItemActivated(GtkMenuItem* item, PopupMenuGtk*); static void menuUnmapped(GtkWidget*, PopupMenuGtk*); static void menuPositionFunction(GtkMenu*, gint*, gint*, gboolean*, PopupMenuGtk*); static void menuRemoveItem(GtkWidget*, PopupMenuGtk*); + static int selectItemCallback(GtkMenuItem*, PopupMenuGtk*); + static int keyPressEventCallback(GtkWidget*, GdkEventKey*, PopupMenuGtk*); PopupMenuClient* m_popupClient; IntPoint m_menuPosition; PlatformRefPtr<GtkMenu> m_popup; HashMap<GtkWidget*, int> m_indexMap; + String m_currentSearchString; + uint32_t m_previousKeyEventTimestamp; + unsigned int m_previousKeyEventCharacter; + GtkWidget* m_currentlySelectedMenuItem; }; } diff --git a/WebCore/platform/gtk/RenderThemeGtk.cpp b/WebCore/platform/gtk/RenderThemeGtk.cpp index fe6c9e9..73b2d6b 100644 --- a/WebCore/platform/gtk/RenderThemeGtk.cpp +++ b/WebCore/platform/gtk/RenderThemeGtk.cpp @@ -55,6 +55,19 @@ namespace WebCore { using namespace HTMLNames; +static void paintStockIcon(GraphicsContext* context, const IntPoint& iconPoint, GtkStyle* style, const char* iconName, + GtkTextDirection direction, GtkStateType state, GtkIconSize iconSize) +{ + GtkIconSet* iconSet = gtk_style_lookup_icon_set(style, iconName); + PlatformRefPtr<GdkPixbuf> icon = adoptPlatformRef(gtk_icon_set_render_icon(iconSet, style, direction, state, iconSize, 0, 0)); + + cairo_t* cr = context->platformContext(); + cairo_save(cr); + gdk_cairo_set_source_pixbuf(cr, icon.get(), iconPoint.x(), iconPoint.y()); + cairo_paint(cr); + cairo_restore(cr); +} + #if ENABLE(VIDEO) static HTMLMediaElement* getMediaElementFromRenderObject(RenderObject* o) { @@ -66,57 +79,46 @@ static HTMLMediaElement* getMediaElementFromRenderObject(RenderObject* o) return static_cast<HTMLMediaElement*>(mediaNode); } -static gchar* getIconNameForTextDirection(const char* baseName) +static GtkIconSize getMediaButtonIconSize(int mediaIconSize) { - GString* nameWithDirection = g_string_new(baseName); - GtkTextDirection textDirection = gtk_widget_get_default_direction(); - - if (textDirection == GTK_TEXT_DIR_RTL) - g_string_append(nameWithDirection, "-rtl"); - else if (textDirection == GTK_TEXT_DIR_LTR) - g_string_append(nameWithDirection, "-ltr"); - - return g_string_free(nameWithDirection, FALSE); + GtkIconSize iconSize = gtk_icon_size_from_name("webkit-media-button-size"); + if (!iconSize) + iconSize = gtk_icon_size_register("webkit-media-button-size", mediaIconSize, mediaIconSize); + return iconSize; } -void RenderThemeGtk::initMediaStyling(GtkStyle* style, bool force) +void RenderThemeGtk::initMediaColors() { - static bool stylingInitialized = false; + GtkStyle* style = gtk_widget_get_style(GTK_WIDGET(gtkContainer())); + m_panelColor = style->bg[GTK_STATE_NORMAL]; + m_sliderColor = style->bg[GTK_STATE_ACTIVE]; + m_sliderThumbColor = style->bg[GTK_STATE_SELECTED]; +} - if (!stylingInitialized || force) { - m_panelColor = style->bg[GTK_STATE_NORMAL]; - m_sliderColor = style->bg[GTK_STATE_ACTIVE]; - m_sliderThumbColor = style->bg[GTK_STATE_SELECTED]; +void RenderThemeGtk::initMediaButtons() +{ + static bool iconsInitialized = false; - // Names of these icons can vary because of text direction. - gchar* playButtonIconName = getIconNameForTextDirection("gtk-media-play"); - gchar* seekBackButtonIconName = getIconNameForTextDirection("gtk-media-rewind"); - gchar* seekForwardButtonIconName = getIconNameForTextDirection("gtk-media-forward"); + if (iconsInitialized) + return; - m_fullscreenButton.clear(); - m_muteButton.clear(); - m_unmuteButton.clear(); - m_playButton.clear(); - m_pauseButton.clear(); - m_seekBackButton.clear(); - m_seekForwardButton.clear(); + PlatformRefPtr<GtkIconFactory> iconFactory = adoptPlatformRef(gtk_icon_factory_new()); + GtkIconSource* iconSource = gtk_icon_source_new(); + const char* icons[] = { "audio-volume-high", "audio-volume-muted" }; - m_fullscreenButton = Image::loadPlatformThemeIcon("gtk-fullscreen", m_mediaIconSize); - // Note that the muteButton and unmuteButton take icons reflecting - // the *current* state. Hence, the unmuteButton represents the *muted* - // status, the muteButton represents the then current *unmuted* status. - m_muteButton = Image::loadPlatformThemeIcon("audio-volume-high", m_mediaIconSize); - m_unmuteButton = Image::loadPlatformThemeIcon("audio-volume-muted", m_mediaIconSize); - m_playButton = Image::loadPlatformThemeIcon(reinterpret_cast<const char*>(playButtonIconName), m_mediaIconSize); - m_pauseButton = Image::loadPlatformThemeIcon("gtk-media-pause", m_mediaIconSize); - m_seekBackButton = Image::loadPlatformThemeIcon(reinterpret_cast<const char*>(seekBackButtonIconName), m_mediaIconSize); - m_seekForwardButton = Image::loadPlatformThemeIcon(reinterpret_cast<const char*>(seekForwardButtonIconName), m_mediaIconSize); + gtk_icon_factory_add_default(iconFactory.get()); - g_free(playButtonIconName); - g_free(seekBackButtonIconName); - g_free(seekForwardButtonIconName); - stylingInitialized = true; + for (size_t i = 0; i < G_N_ELEMENTS(icons); ++i) { + gtk_icon_source_set_icon_name(iconSource, icons[i]); + GtkIconSet* iconSet = gtk_icon_set_new(); + gtk_icon_set_add_source(iconSet, iconSource); + gtk_icon_factory_add(iconFactory.get(), icons[i], iconSet); + gtk_icon_set_unref(iconSet); } + + gtk_icon_source_free(iconSource); + + iconsInitialized = true; } #endif @@ -146,13 +148,6 @@ RenderThemeGtk::RenderThemeGtk() , m_mediaSliderHeight(14) , m_mediaSliderThumbWidth(12) , m_mediaSliderThumbHeight(12) - , m_fullscreenButton(0) - , m_muteButton(0) - , m_unmuteButton(0) - , m_playButton(0) - , m_pauseButton(0) - , m_seekBackButton(0) - , m_seekForwardButton(0) #ifdef GTK_API_VERSION_2 , m_themePartsHaveRGBAColormap(true) #endif @@ -176,7 +171,8 @@ RenderThemeGtk::RenderThemeGtk() ++mozGtkRefCount; #if ENABLE(VIDEO) - initMediaStyling(gtk_rc_get_style(GTK_WIDGET(gtkContainer())), false); + initMediaColors(); + initMediaButtons(); #endif } @@ -187,14 +183,6 @@ RenderThemeGtk::~RenderThemeGtk() if (!mozGtkRefCount) moz_gtk_shutdown(); - m_fullscreenButton.clear(); - m_muteButton.clear(); - m_unmuteButton.clear(); - m_playButton.clear(); - m_pauseButton.clear(); - m_seekBackButton.clear(); - m_seekForwardButton.clear(); - gtk_widget_destroy(m_gtkWindow); } @@ -229,6 +217,17 @@ static bool supportsFocus(ControlPart appearance) } } +GtkStateType RenderThemeGtk::getGtkStateType(RenderObject* object) +{ + if (!isEnabled(object) || isReadOnlyControl(object)) + return GTK_STATE_INSENSITIVE; + if (isPressed(object)) + return GTK_STATE_ACTIVE; + if (isHovered(object)) + return GTK_STATE_PRELIGHT; + return GTK_STATE_NORMAL; +} + bool RenderThemeGtk::supportsFocusRing(const RenderStyle* style) const { return supportsFocus(style->appearance()); @@ -266,23 +265,16 @@ static GtkTextDirection gtkTextDirection(TextDirection direction) } } -static void adjustMozillaStyle(const RenderThemeGtk* theme, RenderStyle* style, GtkThemeWidgetType type) +GtkStateType RenderThemeGtk::gtkIconState(RenderObject* renderObject) { - gint left, top, right, bottom; - GtkTextDirection direction = gtkTextDirection(style->direction()); - gboolean inhtml = true; - - if (moz_gtk_get_widget_border(type, &left, &top, &right, &bottom, direction, inhtml) != MOZ_GTK_SUCCESS) - return; + if (!isEnabled(renderObject)) + return GTK_STATE_INSENSITIVE; + if (isPressed(renderObject)) + return GTK_STATE_ACTIVE; + if (isHovered(renderObject)) + return GTK_STATE_PRELIGHT; - // FIXME: This approach is likely to be incorrect. See other ports and layout tests to see the problem. - const int xpadding = 1; - const int ypadding = 1; - - style->setPaddingLeft(Length(xpadding + left, Fixed)); - style->setPaddingTop(Length(ypadding + top, Fixed)); - style->setPaddingRight(Length(xpadding + right, Fixed)); - style->setPaddingBottom(Length(ypadding + bottom, Fixed)); + return GTK_STATE_NORMAL; } bool RenderThemeGtk::paintRenderObject(GtkThemeWidgetType type, RenderObject* renderObject, GraphicsContext* context, const IntRect& rect, int flags) @@ -306,14 +298,7 @@ bool RenderThemeGtk::paintRenderObject(GtkThemeWidgetType type, RenderObject* re widgetState.disabled = !isEnabled(renderObject) || isReadOnlyControl(renderObject); widgetState.isDefault = false; widgetState.canDefault = false; - - // FIXME: The depressed value should probably apply for other theme parts too. - // It must be used for range thumbs, because otherwise when the thumb is pressed, - // the rendering is incorrect. - if (type == MOZ_GTK_SCALE_THUMB_HORIZONTAL || type == MOZ_GTK_SCALE_THUMB_VERTICAL) - widgetState.depressed = isPressed(renderObject); - else - widgetState.depressed = false; + widgetState.depressed = false; WidgetRenderingContext widgetContext(context, rect); return !widgetContext.paintMozillaWidget(type, &widgetState, flags, gtkTextDirection(renderObject->style()->direction())); @@ -366,9 +351,56 @@ void RenderThemeGtk::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style->setLineHeight(RenderStyle::initialLineHeight()); } -bool RenderThemeGtk::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& rect) +bool RenderThemeGtk::paintButton(RenderObject* object, const PaintInfo& info, const IntRect& rect) { - return paintRenderObject(MOZ_GTK_BUTTON, o, i.context, rect, GTK_RELIEF_NORMAL); + if (info.context->paintingDisabled()) + return false; + + GtkWidget* widget = gtkButton(); + IntRect buttonRect(IntPoint(), rect.size()); + IntRect focusRect(buttonRect); + + GtkStateType state = getGtkStateType(object); + gtk_widget_set_state(widget, state); + gtk_widget_set_direction(widget, gtkTextDirection(object->style()->direction())); + + if (isFocused(object)) { + if (isEnabled(object)) { +#if !GTK_CHECK_VERSION(2, 22, 0) + GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS); +#endif + g_object_set(widget, "has-focus", TRUE, NULL); + } + + gboolean interiorFocus = 0, focusWidth = 0, focusPadding = 0; + gtk_widget_style_get(widget, + "interior-focus", &interiorFocus, + "focus-line-width", &focusWidth, + "focus-padding", &focusPadding, NULL); + // If we are using exterior focus, we shrink the button rect down before + // drawing. If we are using interior focus we shrink the focus rect. This + // approach originates from the Mozilla theme drawing code (gtk2drawing.c). + if (interiorFocus) { + GtkStyle* style = gtk_widget_get_style(widget); + focusRect.inflateX(-style->xthickness - focusPadding); + focusRect.inflateY(-style->ythickness - focusPadding); + } else { + buttonRect.inflateX(-focusWidth - focusPadding); + buttonRect.inflateY(-focusPadding - focusPadding); + } + } + + WidgetRenderingContext widgetContext(info.context, rect); + GtkShadowType shadowType = state == GTK_STATE_ACTIVE ? GTK_SHADOW_IN : GTK_SHADOW_OUT; + widgetContext.gtkPaintBox(buttonRect, widget, state, shadowType, "button"); + if (isFocused(object)) + widgetContext.gtkPaintFocus(focusRect, widget, state, "button"); + +#if !GTK_CHECK_VERSION(2, 22, 0) + GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS); +#endif + g_object_set(widget, "has-focus", FALSE, NULL); + return false; } static void getComboBoxPadding(RenderStyle* style, int& left, int& top, int& right, int& bottom) @@ -433,13 +465,27 @@ bool RenderThemeGtk::paintMenuListButton(RenderObject* object, const PaintInfo& return paintMenuList(object, info, rect); } +static void setTextInputBorders(RenderStyle* style) +{ + // If this control isn't drawn using the native theme, we don't touch the borders. + if (style->appearance() == NoControlPart) + return; + + // We cannot give a proper rendering when border radius is active, unfortunately. + style->resetBorderRadius(); + + int left = 0, top = 0, right = 0, bottom = 0; + moz_gtk_get_widget_border(MOZ_GTK_ENTRY, &left, &top, &right, &bottom, + gtkTextDirection(style->direction()), TRUE); + style->setBorderLeftWidth(left); + style->setBorderTopWidth(top); + style->setBorderRightWidth(right); + style->setBorderBottomWidth(bottom); +} + void RenderThemeGtk::adjustTextFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const { - style->resetBorder(); - style->resetPadding(); - style->setHeight(Length(Auto)); - style->setWhiteSpace(PRE); - adjustMozillaStyle(this, style, MOZ_GTK_ENTRY); + setTextInputBorders(style); } bool RenderThemeGtk::paintTextField(RenderObject* o, const PaintInfo& i, const IntRect& rect) @@ -447,6 +493,11 @@ bool RenderThemeGtk::paintTextField(RenderObject* o, const PaintInfo& i, const I return paintRenderObject(MOZ_GTK_ENTRY, o, i.context, rect); } +void RenderThemeGtk::adjustTextAreaStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + setTextInputBorders(style); +} + bool RenderThemeGtk::paintTextArea(RenderObject* o, const PaintInfo& i, const IntRect& r) { return paintTextField(o, i, r); @@ -467,32 +518,33 @@ void RenderThemeGtk::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* s style->resetBorder(); style->resetPadding(); - // FIXME: This should not be hard-coded. - IntSize size = IntSize(14, 14); - style->setWidth(Length(size.width(), Fixed)); - style->setHeight(Length(size.height(), Fixed)); + gint width = 0, height = 0; + gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height); + style->setWidth(Length(width, Fixed)); + style->setHeight(Length(height, Fixed)); } -static IntRect centerRectVerticallyInParentInputElement(RenderObject* object, const IntRect& rect) +static IntPoint centerRectVerticallyInParentInputElement(RenderObject* object, const IntRect& rect) { - IntRect centeredRect(rect); Node* input = object->node()->shadowAncestorNode(); // Get the renderer of <input> element. - if (!input->renderer()->isBox()) - return centeredRect; + if (!input->renderer()->isBox()) + return rect.topLeft(); // If possible center the y-coordinate of the rect vertically in the parent input element. // We also add one pixel here to ensure that the y coordinate is rounded up for box heights // that are even, which looks in relation to the box text. IntRect inputContentBox = toRenderBox(input->renderer())->absoluteContentBox(); - centeredRect.setY(inputContentBox.y() + (inputContentBox.height() - centeredRect.height() + 1) / 2); - return centeredRect; + + return IntPoint(rect.x(), inputContentBox.y() + (inputContentBox.height() - rect.height() + 1) / 2); } -bool RenderThemeGtk::paintSearchFieldResultsDecoration(RenderObject* object, const PaintInfo& i, const IntRect& rect) +bool RenderThemeGtk::paintSearchFieldResultsDecoration(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) { - static Image* searchImage = Image::loadPlatformThemeIcon(GTK_STOCK_FIND, rect.width()).releaseRef(); - IntRect centeredRect(centerRectVerticallyInParentInputElement(object, rect)); - i.context->drawImage(searchImage, ColorSpaceDeviceRGB, centeredRect); + GtkStyle* style = gtk_widget_get_style(GTK_WIDGET(gtkEntry())); + IntPoint iconPoint(centerRectVerticallyInParentInputElement(renderObject, rect)); + paintStockIcon(paintInfo.context, iconPoint, style, GTK_STOCK_FIND, + gtkTextDirection(renderObject->style()->direction()), + gtkIconState(renderObject), GTK_ICON_SIZE_MENU); return false; } @@ -501,24 +553,26 @@ void RenderThemeGtk::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* select style->resetBorder(); style->resetPadding(); - // FIXME: This should not be hard-coded. - IntSize size = IntSize(14, 14); - style->setWidth(Length(size.width(), Fixed)); - style->setHeight(Length(size.height(), Fixed)); + gint width = 0, height = 0; + gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height); + style->setWidth(Length(width, Fixed)); + style->setHeight(Length(height, Fixed)); } -bool RenderThemeGtk::paintSearchFieldCancelButton(RenderObject* object, const PaintInfo& i, const IntRect& rect) +bool RenderThemeGtk::paintSearchFieldCancelButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) { - // TODO: Brightening up the image on hover is desirable here, I believe. - static Image* cancelImage = Image::loadPlatformThemeIcon(GTK_STOCK_CLEAR, rect.width()).releaseRef(); - IntRect centeredRect(centerRectVerticallyInParentInputElement(object, rect)); - i.context->drawImage(cancelImage, ColorSpaceDeviceRGB, centeredRect); + GtkStyle* style = gtk_widget_get_style(GTK_WIDGET(gtkEntry())); + IntPoint iconPoint(centerRectVerticallyInParentInputElement(renderObject, rect)); + paintStockIcon(paintInfo.context, iconPoint, style, GTK_STOCK_CLEAR, + gtkTextDirection(renderObject->style()->direction()), + gtkIconState(renderObject), GTK_ICON_SIZE_MENU); return false; } void RenderThemeGtk::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const { - adjustTextFieldStyle(selector, style, e); + style->setLineHeight(RenderStyle::initialLineHeight()); + setTextInputBorders(style); } bool RenderThemeGtk::paintSearchField(RenderObject* o, const PaintInfo& i, const IntRect& rect) @@ -528,14 +582,30 @@ bool RenderThemeGtk::paintSearchField(RenderObject* o, const PaintInfo& i, const bool RenderThemeGtk::paintSliderTrack(RenderObject* object, const PaintInfo& info, const IntRect& rect) { + if (info.context->paintingDisabled()) + return false; + ControlPart part = object->style()->appearance(); ASSERT(part == SliderHorizontalPart || part == SliderVerticalPart); - GtkThemeWidgetType gtkPart = MOZ_GTK_SCALE_HORIZONTAL; - if (part == SliderVerticalPart) - gtkPart = MOZ_GTK_SCALE_VERTICAL; + // We shrink the trough rect slightly to make room for the focus indicator. + IntRect troughRect(IntPoint(), rect.size()); // This is relative to rect. + GtkWidget* widget = 0; + if (part == SliderVerticalPart) { + widget = gtkVScale(); + troughRect.inflateY(-gtk_widget_get_style(widget)->ythickness); + } else { + widget = gtkHScale(); + troughRect.inflateX(-gtk_widget_get_style(widget)->xthickness); + } + gtk_widget_set_direction(widget, gtkTextDirection(object->style()->direction())); + + WidgetRenderingContext widgetContext(info.context, rect); + widgetContext.gtkPaintBox(troughRect, widget, GTK_STATE_ACTIVE, GTK_SHADOW_OUT, "trough"); + if (isFocused(object)) + widgetContext.gtkPaintFocus(IntRect(IntPoint(), rect.size()), widget, getGtkStateType(object), "trough"); - return paintRenderObject(gtkPart, object, info.context, rect); + return false; } void RenderThemeGtk::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle* style, Element*) const @@ -545,14 +615,34 @@ void RenderThemeGtk::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle* styl bool RenderThemeGtk::paintSliderThumb(RenderObject* object, const PaintInfo& info, const IntRect& rect) { + if (info.context->paintingDisabled()) + return false; + ControlPart part = object->style()->appearance(); ASSERT(part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart); - GtkThemeWidgetType gtkPart = MOZ_GTK_SCALE_THUMB_HORIZONTAL; - if (part == SliderThumbVerticalPart) - gtkPart = MOZ_GTK_SCALE_THUMB_VERTICAL; - - return paintRenderObject(gtkPart, object, info.context, rect); + GtkWidget* widget = 0; + const char* detail = 0; + GtkOrientation orientation; + if (part == SliderThumbVerticalPart) { + widget = gtkVScale(); + detail = "vscale"; + orientation = GTK_ORIENTATION_VERTICAL; + } else { + widget = gtkHScale(); + detail = "hscale"; + orientation = GTK_ORIENTATION_HORIZONTAL; + } + gtk_widget_set_direction(widget, gtkTextDirection(object->style()->direction())); + + // Only some themes have slider thumbs respond to clicks and some don't. This information is + // gathered via the 'activate-slider' property, but it's deprecated in GTK+ 2.22 and removed in + // GTK+ 3.x. The drawback of not honoring it is that slider thumbs change color when you click + // on them. + IntRect thumbRect(IntPoint(), rect.size()); + WidgetRenderingContext widgetContext(info.context, rect); + widgetContext.gtkPaintSlider(thumbRect, widget, getGtkStateType(object), GTK_SHADOW_OUT, detail, orientation); + return false; } void RenderThemeGtk::adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle* style, Element*) const @@ -567,14 +657,27 @@ void RenderThemeGtk::adjustSliderThumbSize(RenderObject* o) const if (part == MediaSliderThumbPart) { o->style()->setWidth(Length(m_mediaSliderThumbWidth, Fixed)); o->style()->setHeight(Length(m_mediaSliderThumbHeight, Fixed)); - } else + return; + } + if (part == MediaVolumeSliderThumbPart) + return; #endif - if (part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart) { - gint width, height; - moz_gtk_get_scalethumb_metrics(part == SliderThumbHorizontalPart ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL, &width, &height); - o->style()->setWidth(Length(width, Fixed)); - o->style()->setHeight(Length(height, Fixed)); + + GtkWidget* widget = part == SliderThumbHorizontalPart ? gtkHScale() : gtkVScale(); + int length = 0, width = 0; + gtk_widget_style_get(widget, + "slider_length", &length, + "slider_width", &width, + NULL); + + if (part == SliderThumbHorizontalPart) { + o->style()->setWidth(Length(length, Fixed)); + o->style()->setHeight(Length(width, Fixed)); + return; } + ASSERT(part == SliderThumbVerticalPart); + o->style()->setWidth(Length(width, Fixed)); + o->style()->setHeight(Length(length, Fixed)); } Color RenderThemeGtk::platformActiveSelectionBackgroundColor() const @@ -700,17 +803,30 @@ static void gtkStyleSetCallback(GtkWidget* widget, GtkStyle* previous, RenderThe renderTheme->platformColorsDidChange(); } -GtkContainer* RenderThemeGtk::gtkContainer() const +void RenderThemeGtk::setupWidgetAndAddToContainer(GtkWidget* widget, GtkWidget* window) const +{ + gtk_container_add(GTK_CONTAINER(window), widget); + gtk_widget_realize(widget); + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); + + // FIXME: Perhaps this should only be called for the containing window or parent container. + g_signal_connect(widget, "style-set", G_CALLBACK(gtkStyleSetCallback), const_cast<RenderThemeGtk*>(this)); +} + +GtkWidget* RenderThemeGtk::gtkContainer() const { if (m_gtkContainer) return m_gtkContainer; m_gtkWindow = gtk_window_new(GTK_WINDOW_POPUP); - m_gtkContainer = GTK_CONTAINER(gtk_fixed_new()); - g_signal_connect(m_gtkWindow, "style-set", G_CALLBACK(gtkStyleSetCallback), const_cast<RenderThemeGtk*>(this)); - gtk_container_add(GTK_CONTAINER(m_gtkWindow), GTK_WIDGET(m_gtkContainer)); +#ifdef GTK_API_VERSION_2 + gtk_widget_set_colormap(m_gtkWindow, m_themeParts.colormap); +#endif gtk_widget_realize(m_gtkWindow); + gtk_widget_set_name(m_gtkWindow, "MozillaGtkWidget"); + m_gtkContainer = gtk_fixed_new(); + setupWidgetAndAddToContainer(m_gtkContainer, m_gtkWindow); return m_gtkContainer; } @@ -718,12 +834,8 @@ GtkWidget* RenderThemeGtk::gtkButton() const { if (m_gtkButton) return m_gtkButton; - m_gtkButton = gtk_button_new(); - g_signal_connect(m_gtkButton, "style-set", G_CALLBACK(gtkStyleSetCallback), const_cast<RenderThemeGtk*>(this)); - gtk_container_add(gtkContainer(), m_gtkButton); - gtk_widget_realize(m_gtkButton); - + setupWidgetAndAddToContainer(m_gtkButton, gtkContainer()); return m_gtkButton; } @@ -731,12 +843,8 @@ GtkWidget* RenderThemeGtk::gtkEntry() const { if (m_gtkEntry) return m_gtkEntry; - m_gtkEntry = gtk_entry_new(); - g_signal_connect(m_gtkEntry, "style-set", G_CALLBACK(gtkStyleSetCallback), const_cast<RenderThemeGtk*>(this)); - gtk_container_add(gtkContainer(), m_gtkEntry); - gtk_widget_realize(m_gtkEntry); - + setupWidgetAndAddToContainer(m_gtkEntry, gtkContainer()); return m_gtkEntry; } @@ -744,15 +852,29 @@ GtkWidget* RenderThemeGtk::gtkTreeView() const { if (m_gtkTreeView) return m_gtkTreeView; - m_gtkTreeView = gtk_tree_view_new(); - g_signal_connect(m_gtkTreeView, "style-set", G_CALLBACK(gtkStyleSetCallback), const_cast<RenderThemeGtk*>(this)); - gtk_container_add(gtkContainer(), m_gtkTreeView); - gtk_widget_realize(m_gtkTreeView); - + setupWidgetAndAddToContainer(m_gtkTreeView, gtkContainer()); return m_gtkTreeView; } +GtkWidget* RenderThemeGtk::gtkVScale() const +{ + if (m_gtkVScale) + return m_gtkVScale; + m_gtkVScale = gtk_vscale_new(0); + setupWidgetAndAddToContainer(m_gtkVScale, gtkContainer()); + return m_gtkVScale; +} + +GtkWidget* RenderThemeGtk::gtkHScale() const +{ + if (m_gtkHScale) + return m_gtkHScale; + m_gtkHScale = gtk_hscale_new(0); + setupWidgetAndAddToContainer(m_gtkHScale, gtkContainer()); + return m_gtkHScale; +} + GtkWidget* RenderThemeGtk::gtkScrollbar() { return moz_gtk_get_scrollbar_widget(); @@ -761,7 +883,7 @@ GtkWidget* RenderThemeGtk::gtkScrollbar() void RenderThemeGtk::platformColorsDidChange() { #if ENABLE(VIDEO) - initMediaStyling(gtk_rc_get_style(GTK_WIDGET(gtkContainer())), true); + initMediaColors(); #endif RenderTheme::platformColorsDidChange(); } @@ -772,49 +894,50 @@ String RenderThemeGtk::extraMediaControlsStyleSheet() return String(mediaControlsGtkUserAgentStyleSheet, sizeof(mediaControlsGtkUserAgentStyleSheet)); } -static inline bool paintMediaButton(GraphicsContext* context, const IntRect& r, Image* image, Color panelColor, int mediaIconSize) +bool RenderThemeGtk::paintMediaButton(RenderObject* renderObject, GraphicsContext* context, const IntRect& rect, const char* iconName) { - context->fillRect(FloatRect(r), panelColor, ColorSpaceDeviceRGB); - context->drawImage(image, ColorSpaceDeviceRGB, - IntRect(r.x() + (r.width() - mediaIconSize) / 2, - r.y() + (r.height() - mediaIconSize) / 2, - mediaIconSize, mediaIconSize)); + GtkStyle* style = gtk_widget_get_style(GTK_WIDGET(gtkContainer())); + IntPoint iconPoint(rect.x() + (rect.width() - m_mediaIconSize) / 2, + rect.y() + (rect.height() - m_mediaIconSize) / 2); + context->fillRect(FloatRect(rect), m_panelColor, ColorSpaceDeviceRGB); + paintStockIcon(context, iconPoint, style, iconName, gtkTextDirection(renderObject->style()->direction()), + gtkIconState(renderObject), getMediaButtonIconSize(m_mediaIconSize)); return false; } -bool RenderThemeGtk::paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) +bool RenderThemeGtk::paintMediaFullscreenButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) { - return paintMediaButton(paintInfo.context, r, m_fullscreenButton.get(), m_panelColor, m_mediaIconSize); + return paintMediaButton(renderObject, paintInfo.context, rect, GTK_STOCK_FULLSCREEN); } -bool RenderThemeGtk::paintMediaMuteButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) +bool RenderThemeGtk::paintMediaMuteButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) { - HTMLMediaElement* mediaElement = getMediaElementFromRenderObject(o); + HTMLMediaElement* mediaElement = getMediaElementFromRenderObject(renderObject); if (!mediaElement) return false; - return paintMediaButton(paintInfo.context, r, mediaElement->muted() ? m_unmuteButton.get() : m_muteButton.get(), m_panelColor, m_mediaIconSize); + return paintMediaButton(renderObject, paintInfo.context, rect, mediaElement->muted() ? "audio-volume-muted" : "audio-volume-high"); } -bool RenderThemeGtk::paintMediaPlayButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) +bool RenderThemeGtk::paintMediaPlayButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) { - Node* node = o->node(); + Node* node = renderObject->node(); if (!node) return false; MediaControlPlayButtonElement* button = static_cast<MediaControlPlayButtonElement*>(node); - return paintMediaButton(paintInfo.context, r, button->displayType() == MediaPlayButton ? m_playButton.get() : m_pauseButton.get(), m_panelColor, m_mediaIconSize); + return paintMediaButton(renderObject, paintInfo.context, rect, button->displayType() == MediaPlayButton ? GTK_STOCK_MEDIA_PLAY : GTK_STOCK_MEDIA_PAUSE); } -bool RenderThemeGtk::paintMediaSeekBackButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) +bool RenderThemeGtk::paintMediaSeekBackButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) { - return paintMediaButton(paintInfo.context, r, m_seekBackButton.get(), m_panelColor, m_mediaIconSize); + return paintMediaButton(renderObject, paintInfo.context, rect, GTK_STOCK_MEDIA_REWIND); } -bool RenderThemeGtk::paintMediaSeekForwardButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) +bool RenderThemeGtk::paintMediaSeekForwardButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) { - return paintMediaButton(paintInfo.context, r, m_seekForwardButton.get(), m_panelColor, m_mediaIconSize); + return paintMediaButton(renderObject, paintInfo.context, rect, GTK_STOCK_MEDIA_FORWARD); } bool RenderThemeGtk::paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) @@ -852,7 +975,7 @@ bool RenderThemeGtk::paintMediaSliderTrack(RenderObject* o, const PaintInfo& pai rangeRect = trackRect; rangeRect.setWidth(width); } else { - rangeRect.setLocation(IntPoint((start * totalWidth) / mediaDuration, trackRect.y())); + rangeRect.setLocation(IntPoint(trackRect.x() + start / mediaDuration* totalWidth, trackRect.y())); rangeRect.setSize(IntSize(width, trackRect.height())); } diff --git a/WebCore/platform/gtk/RenderThemeGtk.h b/WebCore/platform/gtk/RenderThemeGtk.h index ac08cf1..d377c45 100644 --- a/WebCore/platform/gtk/RenderThemeGtk.h +++ b/WebCore/platform/gtk/RenderThemeGtk.h @@ -100,6 +100,7 @@ protected: virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; virtual bool paintTextField(RenderObject*, const PaintInfo&, const IntRect&); + void adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const; virtual bool paintTextArea(RenderObject*, const PaintInfo&, const IntRect&); int popupInternalPaddingLeft(RenderStyle*) const; @@ -137,7 +138,8 @@ protected: virtual void adjustSliderThumbSize(RenderObject* object) const; #if ENABLE(VIDEO) - virtual void initMediaStyling(GtkStyle* style, bool force); + void initMediaColors(); + void initMediaButtons(); virtual bool paintMediaFullscreenButton(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintMediaPlayButton(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintMediaMuteButton(RenderObject*, const PaintInfo&, const IntRect&); @@ -155,26 +157,28 @@ protected: #endif private: - /* - * hold the state - */ GtkWidget* gtkButton() const; GtkWidget* gtkEntry() const; GtkWidget* gtkTreeView() const; + GtkWidget* gtkVScale() const; + GtkWidget* gtkHScale() const; + GtkWidget* gtkContainer() const; - /* - * unmapped GdkWindow having a container. This is holding all - * our fake widgets - */ - GtkContainer* gtkContainer() const; - + void setupWidgetAndAddToContainer(GtkWidget*, GtkWidget*) const; + GtkStateType getGtkStateType(RenderObject* object); bool paintRenderObject(GtkThemeWidgetType, RenderObject*, GraphicsContext*, const IntRect& rect, int flags = 0); +#if ENABLE(VIDEO) + bool paintMediaButton(RenderObject*, GraphicsContext*, const IntRect&, const char* iconName); +#endif + GtkStateType gtkIconState(RenderObject*); mutable GtkWidget* m_gtkWindow; - mutable GtkContainer* m_gtkContainer; + mutable GtkWidget* m_gtkContainer; mutable GtkWidget* m_gtkButton; mutable GtkWidget* m_gtkEntry; mutable GtkWidget* m_gtkTreeView; + mutable GtkWidget* m_gtkVScale; + mutable GtkWidget* m_gtkHScale; mutable Color m_panelColor; mutable Color m_sliderColor; @@ -185,13 +189,6 @@ private: const int m_mediaSliderThumbWidth; const int m_mediaSliderThumbHeight; - RefPtr<Image> m_fullscreenButton; - RefPtr<Image> m_muteButton; - RefPtr<Image> m_unmuteButton; - RefPtr<Image> m_playButton; - RefPtr<Image> m_pauseButton; - RefPtr<Image> m_seekBackButton; - RefPtr<Image> m_seekForwardButton; GtkThemeParts m_themeParts; #ifdef GTK_API_VERSION_2 bool m_themePartsHaveRGBAColormap; diff --git a/WebCore/platform/gtk/WidgetGtk.cpp b/WebCore/platform/gtk/WidgetGtk.cpp index db316d5..ee1005c 100644 --- a/WebCore/platform/gtk/WidgetGtk.cpp +++ b/WebCore/platform/gtk/WidgetGtk.cpp @@ -60,7 +60,7 @@ void Widget::setFocus(bool focused) gtk_widget_grab_focus(platformWidget() ? platformWidget() : GTK_WIDGET(root()->hostWindow()->platformPageClient())); } -static GdkDrawable* gdkDrawable(PlatformWidget widget) +static GdkWindow* gdkWindow(PlatformWidget widget) { return widget ? gtk_widget_get_window(widget) : 0; } @@ -78,7 +78,7 @@ void Widget::setCursor(const Cursor& cursor) if (platformCursor == lastSetCursor) return; - gdk_window_set_cursor(gdkDrawable(platformWidget()) ? GDK_WINDOW(gdkDrawable(platformWidget())) : gtk_widget_get_window(GTK_WIDGET(root()->hostWindow()->platformPageClient())), platformCursor); + gdk_window_set_cursor(gdkWindow(platformWidget()) ? gdkWindow(platformWidget()) : gtk_widget_get_window(GTK_WIDGET(root()->hostWindow()->platformPageClient())), platformCursor); lastSetCursor = platformCursor; } diff --git a/WebCore/platform/gtk/WidgetRenderingContext.h b/WebCore/platform/gtk/WidgetRenderingContext.h index 3bb8065..7334656 100644 --- a/WebCore/platform/gtk/WidgetRenderingContext.h +++ b/WebCore/platform/gtk/WidgetRenderingContext.h @@ -34,7 +34,11 @@ class WidgetRenderingContext { public: WidgetRenderingContext(GraphicsContext*, const IntRect&); ~WidgetRenderingContext(); + bool paintMozillaWidget(GtkThemeWidgetType, GtkWidgetState*, int flags, GtkTextDirection = GTK_TEXT_DIR_NONE); + void gtkPaintBox(const IntRect&, GtkWidget*, GtkStateType, GtkShadowType, const gchar*); + void gtkPaintFocus(const IntRect&, GtkWidget*, GtkStateType, const gchar*); + void gtkPaintSlider(const IntRect&, GtkWidget*, GtkStateType, GtkShadowType, const gchar*, GtkOrientation); private: GraphicsContext* m_graphicsContext; diff --git a/WebCore/platform/gtk/WidgetRenderingContextGtk2.cpp b/WebCore/platform/gtk/WidgetRenderingContextGtk2.cpp index b8712d2..e85c570 100644 --- a/WebCore/platform/gtk/WidgetRenderingContextGtk2.cpp +++ b/WebCore/platform/gtk/WidgetRenderingContextGtk2.cpp @@ -89,9 +89,9 @@ WidgetRenderingContext::WidgetRenderingContext(GraphicsContext* graphicsContext, // Fallback: We failed to create an RGBA colormap earlier, so we cannot properly paint // to a temporary surface and preserve transparency. To ensure decent widget rendering, just // paint directly to the target drawable. This will not render CSS rotational transforms properly. - if (!theme->m_themePartsHaveRGBAColormap && graphicsContext->gdkDrawable()) { + if (!theme->m_themePartsHaveRGBAColormap && graphicsContext->gdkWindow()) { m_paintRect = graphicsContext->getCTM().mapRect(targetRect); - m_target = graphicsContext->gdkDrawable(); + m_target = graphicsContext->gdkWindow(); return; } @@ -131,7 +131,7 @@ WidgetRenderingContext::~WidgetRenderingContext() { // We do not need to blit back to the target in the fallback case. See above. RenderThemeGtk* theme = static_cast<RenderThemeGtk*>(RenderTheme::defaultTheme().get()); - if (!theme->m_themePartsHaveRGBAColormap && m_graphicsContext->gdkDrawable()) + if (!theme->m_themePartsHaveRGBAColormap && m_graphicsContext->gdkWindow()) return; // Don't paint the results back if there was an error. @@ -165,6 +165,27 @@ bool WidgetRenderingContext::paintMozillaWidget(GtkThemeWidgetType type, GtkWidg return !m_hadError; } +void WidgetRenderingContext::gtkPaintBox(const IntRect& rect, GtkWidget* widget, GtkStateType stateType, GtkShadowType shadowType, const gchar* detail) +{ + GdkRectangle paintRect = { m_paintRect.x + rect.x(), m_paintRect.y + rect.y(), rect.width(), rect.height() }; + gtk_paint_box(gtk_widget_get_style(widget), m_target, stateType, shadowType, &m_paintRect, + widget, detail, paintRect.x, paintRect.y, paintRect.width, paintRect.height); +} + +void WidgetRenderingContext::gtkPaintFocus(const IntRect& rect, GtkWidget* widget, GtkStateType stateType, const gchar* detail) +{ + GdkRectangle paintRect = { m_paintRect.x + rect.x(), m_paintRect.y + rect.y(), rect.width(), rect.height() }; + gtk_paint_focus(gtk_widget_get_style(widget), m_target, stateType, &m_paintRect, widget, + detail, paintRect.x, paintRect.y, paintRect.width, paintRect.height); +} + +void WidgetRenderingContext::gtkPaintSlider(const IntRect& rect, GtkWidget* widget, GtkStateType stateType, GtkShadowType shadowType, const gchar* detail, GtkOrientation orientation) +{ + GdkRectangle paintRect = { m_paintRect.x + rect.x(), m_paintRect.y + rect.y(), rect.width(), rect.height() }; + gtk_paint_slider(gtk_widget_get_style(widget), m_target, stateType, shadowType, &m_paintRect, widget, + detail, paintRect.x, paintRect.y, paintRect.width, paintRect.height, orientation); +} + } #endif // GTK_API_VERSION_2 diff --git a/WebCore/platform/gtk/WidgetRenderingContextGtk3.cpp b/WebCore/platform/gtk/WidgetRenderingContextGtk3.cpp index e5f1823..69c4af5 100644 --- a/WebCore/platform/gtk/WidgetRenderingContextGtk3.cpp +++ b/WebCore/platform/gtk/WidgetRenderingContextGtk3.cpp @@ -47,6 +47,27 @@ bool WidgetRenderingContext::paintMozillaWidget(GtkThemeWidgetType type, GtkWidg return !m_hadError; } +void WidgetRenderingContext::gtkPaintBox(const IntRect& rect, GtkWidget* widget, GtkStateType stateType, GtkShadowType shadowType, const gchar* detail) +{ + GdkRectangle paintRect = { m_paintRect.x + rect.x(), m_paintRect.y + rect.y(), rect.width(), rect.height() }; + gtk_paint_box(gtk_widget_get_style(widget), m_target, stateType, shadowType, widget, + detail, paintRect.x, paintRect.y, paintRect.width, paintRect.height); +} + +void WidgetRenderingContext::gtkPaintFocus(const IntRect& rect, GtkWidget* widget, GtkStateType stateType, const gchar* detail) +{ + GdkRectangle paintRect = { m_paintRect.x + rect.x(), m_paintRect.y + rect.y(), rect.width(), rect.height() }; + gtk_paint_focus(gtk_widget_get_style(widget), m_target, stateType, widget, + detail, paintRect.x, paintRect.y, paintRect.width, paintRect.height); +} + +void WidgetRenderingContext::gtkPaintSlider(const IntRect& rect, GtkWidget* widget, GtkStateType stateType, GtkShadowType shadowType, const gchar* detail, GtkOrientation orientation) +{ + GdkRectangle paintRect = { m_paintRect.x + rect.x(), m_paintRect.y + rect.y(), rect.width(), rect.height() }; + gtk_paint_slider(gtk_widget_get_style(widget), m_target, stateType, shadowType, widget, + detail, paintRect.x, paintRect.y, paintRect.width, paintRect.height, orientation); +} + } #endif // !GTK_API_VERSION_2 diff --git a/WebCore/platform/gtk/gtk2drawing.c b/WebCore/platform/gtk/gtk2drawing.c index 2f2edb6..3ebd332 100644 --- a/WebCore/platform/gtk/gtk2drawing.c +++ b/WebCore/platform/gtk/gtk2drawing.c @@ -185,20 +185,6 @@ ensure_scrollbar_widget() } static gint -ensure_scale_widget() -{ - if (!gParts->hScaleWidget) { - gParts->hScaleWidget = gtk_hscale_new(NULL); - setup_widget_prototype(gParts->hScaleWidget); - } - if (!gParts->vScaleWidget) { - gParts->vScaleWidget = gtk_vscale_new(NULL); - setup_widget_prototype(gParts->vScaleWidget); - } - return MOZ_GTK_SUCCESS; -} - -static gint ensure_entry_widget() { if (!gParts->entryWidget) { @@ -921,83 +907,6 @@ moz_gtk_scrollbar_thumb_paint(GtkThemeWidgetType widget, } static gint -moz_gtk_scale_paint(GdkDrawable* drawable, GdkRectangle* rect, - GdkRectangle* cliprect, GtkWidgetState* state, - GtkOrientation flags, GtkTextDirection direction) -{ - gint x = 0, y = 0; - GtkStateType state_type = ConvertGtkState(state); - GtkStyle* style; - GtkWidget* widget; - - ensure_scale_widget(); - widget = ((flags == GTK_ORIENTATION_HORIZONTAL) ? gParts->hScaleWidget : gParts->vScaleWidget); - gtk_widget_set_direction(widget, direction); - - style = gtk_widget_get_style(widget); - - if (flags == GTK_ORIENTATION_HORIZONTAL) { - x = XTHICKNESS(style); - y++; - } - else { - x++; - y = YTHICKNESS(style); - } - - TSOffsetStyleGCs(style, rect->x, rect->y); - gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_NORMAL, - cliprect, rect->x, rect->y, - rect->width, rect->height); - - gtk_paint_box(style, drawable, GTK_STATE_ACTIVE, GTK_SHADOW_IN, cliprect, - widget, "trough", rect->x + x, rect->y + y, - rect->width - 2*x, rect->height - 2*y); - - if (state->focused) - gtk_paint_focus(style, drawable, state_type, cliprect, widget, "trough", - rect->x, rect->y, rect->width, rect->height); - - return MOZ_GTK_SUCCESS; -} - -static gint -moz_gtk_scale_thumb_paint(GdkDrawable* drawable, GdkRectangle* rect, - GdkRectangle* cliprect, GtkWidgetState* state, - GtkOrientation flags, GtkTextDirection direction) -{ - GtkStateType state_type = ConvertGtkState(state); - GtkStyle* style; - GtkWidget* widget; - gint thumb_width, thumb_height, x, y; - - ensure_scale_widget(); - widget = ((flags == GTK_ORIENTATION_HORIZONTAL) ? gParts->hScaleWidget : gParts->vScaleWidget); - gtk_widget_set_direction(widget, direction); - - style = gtk_widget_get_style(widget); - - /* determine the thumb size, and position the thumb in the center in the opposite axis */ - if (flags == GTK_ORIENTATION_HORIZONTAL) { - moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_HORIZONTAL, &thumb_width, &thumb_height); - x = rect->x; - y = rect->y + (rect->height - thumb_height) / 2; - } - else { - moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_VERTICAL, &thumb_height, &thumb_width); - x = rect->x + (rect->width - thumb_width) / 2; - y = rect->y; - } - - TSOffsetStyleGCs(style, rect->x, rect->y); - gtk_paint_slider(style, drawable, state_type, GTK_SHADOW_OUT, cliprect, - widget, (flags == GTK_ORIENTATION_HORIZONTAL) ? "hscale" : "vscale", - x, y, thumb_width, thumb_height, flags); - - return MOZ_GTK_SUCCESS; -} - -static gint moz_gtk_entry_paint(GdkDrawable* drawable, GdkRectangle* rect, GdkRectangle* cliprect, GtkWidgetState* state, GtkWidget* widget, GtkTextDirection direction) @@ -1310,14 +1219,6 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, ensure_progress_widget(); w = gParts->progresWidget; break; - case MOZ_GTK_SCALE_HORIZONTAL: - ensure_scale_widget(); - w = gParts->hScaleWidget; - break; - case MOZ_GTK_SCALE_VERTICAL: - ensure_scale_widget(); - w = gParts->vScaleWidget; - break; /* These widgets have no borders, since they are not containers. */ case MOZ_GTK_CHECKBUTTON: case MOZ_GTK_RADIOBUTTON: @@ -1326,8 +1227,6 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, case MOZ_GTK_SCROLLBAR_TRACK_VERTICAL: case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL: case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL: - case MOZ_GTK_SCALE_THUMB_HORIZONTAL: - case MOZ_GTK_SCALE_THUMB_VERTICAL: case MOZ_GTK_PROGRESS_CHUNK: *left = *top = *right = *bottom = 0; return MOZ_GTK_SUCCESS; @@ -1344,22 +1243,6 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, } gint -moz_gtk_get_scalethumb_metrics(GtkOrientation orient, gint* thumb_length, gint* thumb_height) -{ - GtkWidget* widget; - - ensure_scale_widget(); - widget = ((orient == GTK_ORIENTATION_HORIZONTAL) ? gParts->hScaleWidget : gParts->vScaleWidget); - - gtk_widget_style_get (widget, - "slider_length", thumb_length, - "slider_width", thumb_height, - NULL); - - return MOZ_GTK_SUCCESS; -} - -gint moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics *metrics) { ensure_scrollbar_widget(); @@ -1424,16 +1307,6 @@ moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable, case MOZ_GTK_SCROLLED_WINDOW: return moz_gtk_scrolled_window_paint(drawable, rect, cliprect, state); break; - case MOZ_GTK_SCALE_HORIZONTAL: - case MOZ_GTK_SCALE_VERTICAL: - return moz_gtk_scale_paint(drawable, rect, cliprect, state, - (GtkOrientation) flags, direction); - break; - case MOZ_GTK_SCALE_THUMB_HORIZONTAL: - case MOZ_GTK_SCALE_THUMB_VERTICAL: - return moz_gtk_scale_thumb_paint(drawable, rect, cliprect, state, - (GtkOrientation) flags, direction); - break; case MOZ_GTK_ENTRY: ensure_entry_widget(); return moz_gtk_entry_paint(drawable, rect, cliprect, state, diff --git a/WebCore/platform/gtk/gtk3drawing.c b/WebCore/platform/gtk/gtk3drawing.c index 880eb6d..d3bdd56 100644 --- a/WebCore/platform/gtk/gtk3drawing.c +++ b/WebCore/platform/gtk/gtk3drawing.c @@ -178,20 +178,6 @@ ensure_scrollbar_widget() } static gint -ensure_scale_widget() -{ - if (!gParts->hScaleWidget) { - gParts->hScaleWidget = gtk_hscale_new(NULL); - setup_widget_prototype(gParts->hScaleWidget); - } - if (!gParts->vScaleWidget) { - gParts->vScaleWidget = gtk_vscale_new(NULL); - setup_widget_prototype(gParts->vScaleWidget); - } - return MOZ_GTK_SUCCESS; -} - -static gint ensure_entry_widget() { if (!gParts->entryWidget) { @@ -848,82 +834,6 @@ moz_gtk_scrollbar_thumb_paint(GtkThemeWidgetType widget, } static gint -moz_gtk_scale_paint(cairo_t* cr, GdkRectangle* rect, - GtkWidgetState* state, GtkOrientation flags, - GtkTextDirection direction) -{ - gint x = 0, y = 0; - GtkStateType state_type = ConvertGtkState(state); - GtkStyle* style; - GtkWidget* widget; - - ensure_scale_widget(); - widget = ((flags == GTK_ORIENTATION_HORIZONTAL) ? gParts->hScaleWidget : gParts->vScaleWidget); - gtk_widget_set_direction(widget, direction); - - style = gtk_widget_get_style(widget); - - if (flags == GTK_ORIENTATION_HORIZONTAL) { - x = XTHICKNESS(style); - y++; - } - else { - x++; - y = YTHICKNESS(style); - } - - gtk_style_apply_default_background(style, cr, gtk_widget_get_window (widget), - GTK_STATE_NORMAL, - rect->x, rect->y, - rect->width, rect->height); - - gtk_paint_box(style, cr, GTK_STATE_ACTIVE, GTK_SHADOW_IN, - widget, "trough", rect->x + x, rect->y + y, - rect->width - 2*x, rect->height - 2*y); - - if (state->focused) - gtk_paint_focus(style, cr, state_type, widget, "trough", - rect->x, rect->y, rect->width, rect->height); - - return MOZ_GTK_SUCCESS; -} - -static gint -moz_gtk_scale_thumb_paint(cairo_t* cr, GdkRectangle* rect, - GtkWidgetState* state, GtkOrientation flags, - GtkTextDirection direction) -{ - GtkStateType state_type = ConvertGtkState(state); - GtkStyle* style; - GtkWidget* widget; - gint thumb_width, thumb_height, x, y; - - ensure_scale_widget(); - widget = ((flags == GTK_ORIENTATION_HORIZONTAL) ? gParts->hScaleWidget : gParts->vScaleWidget); - gtk_widget_set_direction(widget, direction); - - style = gtk_widget_get_style(widget); - - /* determine the thumb size, and position the thumb in the center in the opposite axis */ - if (flags == GTK_ORIENTATION_HORIZONTAL) { - moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_HORIZONTAL, &thumb_width, &thumb_height); - x = rect->x; - y = rect->y + (rect->height - thumb_height) / 2; - } - else { - moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_VERTICAL, &thumb_height, &thumb_width); - x = rect->x + (rect->width - thumb_width) / 2; - y = rect->y; - } - - gtk_paint_slider(style, cr, state_type, GTK_SHADOW_OUT, - widget, (flags == GTK_ORIENTATION_HORIZONTAL) ? "hscale" : "vscale", - x, y, thumb_width, thumb_height, flags); - - return MOZ_GTK_SUCCESS; -} - -static gint moz_gtk_entry_paint(cairo_t* cr, GdkRectangle* rect, GtkWidgetState* state, GtkWidget* widget, GtkTextDirection direction) @@ -1227,14 +1137,6 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, ensure_progress_widget(); w = gParts->progresWidget; break; - case MOZ_GTK_SCALE_HORIZONTAL: - ensure_scale_widget(); - w = gParts->hScaleWidget; - break; - case MOZ_GTK_SCALE_VERTICAL: - ensure_scale_widget(); - w = gParts->vScaleWidget; - break; /* These widgets have no borders, since they are not containers. */ case MOZ_GTK_CHECKBUTTON: case MOZ_GTK_RADIOBUTTON: @@ -1243,8 +1145,6 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, case MOZ_GTK_SCROLLBAR_TRACK_VERTICAL: case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL: case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL: - case MOZ_GTK_SCALE_THUMB_HORIZONTAL: - case MOZ_GTK_SCALE_THUMB_VERTICAL: case MOZ_GTK_PROGRESS_CHUNK: *left = *top = *right = *bottom = 0; return MOZ_GTK_SUCCESS; @@ -1261,22 +1161,6 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, } gint -moz_gtk_get_scalethumb_metrics(GtkOrientation orient, gint* thumb_length, gint* thumb_height) -{ - GtkWidget* widget; - - ensure_scale_widget(); - widget = ((orient == GTK_ORIENTATION_HORIZONTAL) ? gParts->hScaleWidget : gParts->vScaleWidget); - - gtk_widget_style_get (widget, - "slider_length", thumb_length, - "slider_width", thumb_height, - NULL); - - return MOZ_GTK_SUCCESS; -} - -gint moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics *metrics) { ensure_scrollbar_widget(); @@ -1340,16 +1224,6 @@ moz_gtk_widget_paint(GtkThemeWidgetType widget, cairo_t* cr, case MOZ_GTK_SCROLLED_WINDOW: return moz_gtk_scrolled_window_paint(cr, rect, state); break; - case MOZ_GTK_SCALE_HORIZONTAL: - case MOZ_GTK_SCALE_VERTICAL: - return moz_gtk_scale_paint(cr, rect, state, - (GtkOrientation) flags, direction); - break; - case MOZ_GTK_SCALE_THUMB_HORIZONTAL: - case MOZ_GTK_SCALE_THUMB_VERTICAL: - return moz_gtk_scale_thumb_paint(cr, rect, state, - (GtkOrientation) flags, direction); - break; case MOZ_GTK_ENTRY: ensure_entry_widget(); return moz_gtk_entry_paint(cr, rect, state, diff --git a/WebCore/platform/gtk/gtkdrawing.h b/WebCore/platform/gtk/gtkdrawing.h index a981543..9d13a07 100644 --- a/WebCore/platform/gtk/gtkdrawing.h +++ b/WebCore/platform/gtk/gtkdrawing.h @@ -93,8 +93,6 @@ typedef struct _GtkThemeParts { GtkWidget* radiobuttonWidget; GtkWidget* horizScrollbarWidget; GtkWidget* vertScrollbarWidget; - GtkWidget* hScaleWidget; - GtkWidget* vScaleWidget; GtkWidget* entryWidget; GtkWidget* comboBoxWidget; GtkWidget* comboBoxButtonWidget; @@ -147,12 +145,6 @@ typedef enum { MOZ_GTK_SCROLLBAR_THUMB_VERTICAL, /* Paints the background of a scrolled window */ MOZ_GTK_SCROLLED_WINDOW, - /* Paints a GtkScale. */ - MOZ_GTK_SCALE_HORIZONTAL, - MOZ_GTK_SCALE_VERTICAL, - /* Paints a GtkScale thumb. */ - MOZ_GTK_SCALE_THUMB_HORIZONTAL, - MOZ_GTK_SCALE_THUMB_VERTICAL, MOZ_GTK_ENTRY, /* Paints a GtkOptionMenu. */ MOZ_GTK_DROPDOWN, @@ -277,17 +269,6 @@ moz_gtk_widget_get_focus(GtkWidget* widget, gboolean* interior_focus, gint* focus_width, gint* focus_pad); /** - * Get the desired size of a GtkScale thumb - * orient: [IN] the scale orientation - * thumb_length: [OUT] the length of the thumb - * thumb_height: [OUT] the height of the thumb - * - * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise - */ -gint -moz_gtk_get_scalethumb_metrics(GtkOrientation orient, gint* thumb_length, gint* thumb_height); - -/** * Get the desired metrics for a GtkScrollbar * metrics: [IN] struct which will contain the metrics * diff --git a/WebCore/platform/haiku/ContextMenuHaiku.cpp b/WebCore/platform/haiku/ContextMenuHaiku.cpp index b978433..aaff99b 100644 --- a/WebCore/platform/haiku/ContextMenuHaiku.cpp +++ b/WebCore/platform/haiku/ContextMenuHaiku.cpp @@ -75,9 +75,8 @@ private: int m_result; }; -ContextMenu::ContextMenu(const HitTestResult& result) - : m_hitTestResult(result) - , m_platformDescription(new BMenu("context_menu")) +ContextMenu::ContextMenu() + : m_platformDescription(new BMenu("context_menu")) { } @@ -88,8 +87,6 @@ ContextMenu::~ContextMenu() void ContextMenu::appendItem(ContextMenuItem& item) { - checkOrEnableIfNeeded(item); - BMenuItem* menuItem = item.releasePlatformDescription(); if (menuItem) m_platformDescription->AddItem(menuItem); @@ -102,8 +99,6 @@ unsigned ContextMenu::itemCount() const void ContextMenu::insertItem(unsigned position, ContextMenuItem& item) { - checkOrEnableIfNeeded(item); - BMenuItem* menuItem = item.releasePlatformDescription(); if (menuItem) m_platformDescription->AddItem(menuItem, position); diff --git a/WebCore/platform/image-decoders/ImageDecoder.cpp b/WebCore/platform/image-decoders/ImageDecoder.cpp index 49c2a61..cc23b2a 100644 --- a/WebCore/platform/image-decoders/ImageDecoder.cpp +++ b/WebCore/platform/image-decoders/ImageDecoder.cpp @@ -53,11 +53,15 @@ static unsigned copyFromSharedBuffer(char* buffer, unsigned bufferLength, const return bytesExtracted; } +<<<<<<< HEAD #if !OS(ANDROID) // This method requires BMPImageDecoder, PNGImageDecoder, ICOImageDecoder and // JPEGDecoder, which aren't used on Android, and which don't all compile. // TODO: Find a better fix. ImageDecoder* ImageDecoder::create(const SharedBuffer& data, bool premultiplyAlpha, bool ignoreGammaAndColorProfile) +======= +ImageDecoder* ImageDecoder::create(const SharedBuffer& data, ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption) +>>>>>>> webkit.org at r74534 (trunk) { // We need at least 4 bytes to figure out what kind of image we're dealing // with. @@ -69,15 +73,15 @@ ImageDecoder* ImageDecoder::create(const SharedBuffer& data, bool premultiplyAlp // GIFs begin with GIF8(7 or 9). if (strncmp(contents, "GIF8", 4) == 0) - return new GIFImageDecoder(premultiplyAlpha, ignoreGammaAndColorProfile); + return new GIFImageDecoder(alphaOption, gammaAndColorProfileOption); // Test for PNG. if (!memcmp(contents, "\x89\x50\x4E\x47", 4)) - return new PNGImageDecoder(premultiplyAlpha, ignoreGammaAndColorProfile); + return new PNGImageDecoder(alphaOption, gammaAndColorProfileOption); // JPEG if (!memcmp(contents, "\xFF\xD8\xFF", 3)) - return new JPEGImageDecoder(premultiplyAlpha, ignoreGammaAndColorProfile); + return new JPEGImageDecoder(alphaOption, gammaAndColorProfileOption); #if USE(WEBP) if (!memcmp(contents, "RIFF", 4)) { @@ -87,19 +91,19 @@ ImageDecoder* ImageDecoder::create(const SharedBuffer& data, bool premultiplyAlp unsigned length = copyFromSharedBuffer(header, webpExtraMarker, data, webpExtraMarkeroffset); if (length >= webpExtraMarker) { if (!memcmp(header, "WEBPVP", webpExtraMarker)) - return new WEBPImageDecoder(premultiplyAlpha, ignoreGammaAndColorProfile); + return new WEBPImageDecoder(alphaOption, gammaAndColorProfileOption); } } #endif // BMP if (strncmp(contents, "BM", 2) == 0) - return new BMPImageDecoder(premultiplyAlpha, ignoreGammaAndColorProfile); + return new BMPImageDecoder(alphaOption, gammaAndColorProfileOption); // ICOs always begin with a 2-byte 0 followed by a 2-byte 1. // CURs begin with 2-byte 0 followed by 2-byte 2. if (!memcmp(contents, "\x00\x00\x01\x00", 4) || !memcmp(contents, "\x00\x00\x02\x00", 4)) - return new ICOImageDecoder(premultiplyAlpha, ignoreGammaAndColorProfile); + return new ICOImageDecoder(alphaOption, gammaAndColorProfileOption); // Give up. We don't know what the heck this is. return 0; diff --git a/WebCore/platform/image-decoders/ImageDecoder.h b/WebCore/platform/image-decoders/ImageDecoder.h index ceb8f9b..c3d73c0 100644 --- a/WebCore/platform/image-decoders/ImageDecoder.h +++ b/WebCore/platform/image-decoders/ImageDecoder.h @@ -233,10 +233,10 @@ namespace WebCore { // m_maxNumPixels. (Not supported by all image decoders yet) class ImageDecoder : public Noncopyable { public: - ImageDecoder(bool premultiplyAlpha, bool ignoreGammaAndColorProfile) + ImageDecoder(ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption) : m_scaled(false) - , m_premultiplyAlpha(premultiplyAlpha) - , m_ignoreGammaAndColorProfile(ignoreGammaAndColorProfile) + , m_premultiplyAlpha(alphaOption == ImageSource::AlphaPremultiplied) + , m_ignoreGammaAndColorProfile(gammaAndColorProfileOption == ImageSource::GammaAndColorProfileIgnored) , m_sizeAvailable(false) , m_maxNumPixels(-1) , m_isAllDataReceived(false) @@ -249,7 +249,7 @@ namespace WebCore { // Factory function to create an ImageDecoder. Ports that subclass // ImageDecoder can provide their own implementation of this to avoid // needing to write a dedicated setData() implementation. - static ImageDecoder* create(const SharedBuffer& data, bool premultiplyAlpha, bool ignoreGammaAndColorProfile); + static ImageDecoder* create(const SharedBuffer& data, ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption); // The the filename extension usually associated with an undecoded image // of this type. diff --git a/WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp b/WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp index 219a1e2..220a1ed 100644 --- a/WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp +++ b/WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp @@ -40,8 +40,9 @@ namespace WebCore { // don't pack). static const size_t sizeOfFileHeader = 14; -BMPImageDecoder::BMPImageDecoder(bool premultiplyAlpha, bool ignoreGammaAndColorProfile) - : ImageDecoder(premultiplyAlpha, ignoreGammaAndColorProfile) +BMPImageDecoder::BMPImageDecoder(ImageSource::AlphaOption alphaOption, + ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption) + : ImageDecoder(alphaOption, gammaAndColorProfileOption) , m_decodedOffset(0) { } diff --git a/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h b/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h index 695fab4..5f4ed82 100644 --- a/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h +++ b/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h @@ -39,7 +39,7 @@ namespace WebCore { // This class decodes the BMP image format. class BMPImageDecoder : public ImageDecoder { public: - BMPImageDecoder(bool premultiplyAlpha, bool ignoreGammaAndColorProfile); + BMPImageDecoder(ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption); // ImageDecoder virtual String filenameExtension() const { return "bmp"; } diff --git a/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp b/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp index dfdf35e..e92f264 100644 --- a/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp +++ b/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp @@ -29,8 +29,9 @@ namespace WebCore { -GIFImageDecoder::GIFImageDecoder(bool premultiplyAlpha, bool ignoreGammaAndColorProfile) - : ImageDecoder(premultiplyAlpha, ignoreGammaAndColorProfile) +GIFImageDecoder::GIFImageDecoder(ImageSource::AlphaOption alphaOption, + ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption) + : ImageDecoder(alphaOption, gammaAndColorProfileOption) , m_alreadyScannedThisDataForFrameCount(true) , m_repetitionCount(cAnimationLoopOnce) , m_readOffset(0) diff --git a/WebCore/platform/image-decoders/gif/GIFImageDecoder.h b/WebCore/platform/image-decoders/gif/GIFImageDecoder.h index 5b4ca10..64240d4 100644 --- a/WebCore/platform/image-decoders/gif/GIFImageDecoder.h +++ b/WebCore/platform/image-decoders/gif/GIFImageDecoder.h @@ -36,7 +36,7 @@ namespace WebCore { // This class decodes the GIF image format. class GIFImageDecoder : public ImageDecoder { public: - GIFImageDecoder(bool premultiplyAlpha, bool ignoreGammaAndColorProfile); + GIFImageDecoder(ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption); virtual ~GIFImageDecoder(); enum GIFQuery { GIFFullQuery, GIFSizeQuery, GIFFrameCountQuery }; diff --git a/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp b/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp index b07cf92..92a7dcf 100644 --- a/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp +++ b/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp @@ -44,8 +44,9 @@ namespace WebCore { static const size_t sizeOfDirectory = 6; static const size_t sizeOfDirEntry = 16; -ICOImageDecoder::ICOImageDecoder(bool premultiplyAlpha, bool ignoreGammaAndColorProfile) - : ImageDecoder(premultiplyAlpha, ignoreGammaAndColorProfile) +ICOImageDecoder::ICOImageDecoder(ImageSource::AlphaOption alphaOption, + ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption) + : ImageDecoder(alphaOption, gammaAndColorProfileOption) , m_decodedOffset(0) { } @@ -201,7 +202,9 @@ bool ICOImageDecoder::decodeAtIndex(size_t index) } if (!m_pngDecoders[index]) { - m_pngDecoders[index].set(new PNGImageDecoder(m_premultiplyAlpha, m_ignoreGammaAndColorProfile)); + m_pngDecoders[index].set( + new PNGImageDecoder(m_premultiplyAlpha ? ImageSource::AlphaPremultiplied : ImageSource::AlphaNotPremultiplied, + m_ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied)); setDataForPNGDecoderAtIndex(index); } // Fail if the size the PNGImageDecoder calculated does not match the size diff --git a/WebCore/platform/image-decoders/ico/ICOImageDecoder.h b/WebCore/platform/image-decoders/ico/ICOImageDecoder.h index dc631f4..c2af6a3 100644 --- a/WebCore/platform/image-decoders/ico/ICOImageDecoder.h +++ b/WebCore/platform/image-decoders/ico/ICOImageDecoder.h @@ -40,7 +40,7 @@ namespace WebCore { // This class decodes the ICO and CUR image formats. class ICOImageDecoder : public ImageDecoder { public: - ICOImageDecoder(bool premultiplyAlpha, bool ignoreGammaAndColorProfile); + ICOImageDecoder(ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption); virtual ~ICOImageDecoder(); // ImageDecoder diff --git a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp index 855ba24..632d428 100644 --- a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp +++ b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp @@ -222,12 +222,6 @@ public: // jpeglib cannot convert these to rgb, but it can convert ycck // to cmyk. m_info.out_color_space = JCS_CMYK; - - // Same as with grayscale images, we convert CMYK images to RGBA - // ones. When we keep the color profiles of these CMYK images, - // CoreGraphics will convert their colors again. So, we discard - // their color profiles to prevent color corruption. - m_decoder->setIgnoreGammaAndColorProfile(true); break; default: return m_decoder->setFailed(); @@ -404,8 +398,9 @@ void term_source(j_decompress_ptr jd) src->decoder->decoder()->jpegComplete(); } -JPEGImageDecoder::JPEGImageDecoder(bool premultiplyAlpha, bool ignoreGammaAndColorProfile) - : ImageDecoder(premultiplyAlpha, ignoreGammaAndColorProfile) +JPEGImageDecoder::JPEGImageDecoder(ImageSource::AlphaOption alphaOption, + ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption) + : ImageDecoder(alphaOption, gammaAndColorProfileOption) { } diff --git a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h index a60b387..63f29ab 100644 --- a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h +++ b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h @@ -37,7 +37,7 @@ namespace WebCore { // This class decodes the JPEG image format. class JPEGImageDecoder : public ImageDecoder { public: - JPEGImageDecoder(bool premultiplyAlpha, bool ignoreGammaAndColorProfile); + JPEGImageDecoder(ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption); virtual ~JPEGImageDecoder(); // ImageDecoder diff --git a/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp b/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp index 794a474..3fe4d3c 100644 --- a/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp +++ b/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp @@ -169,8 +169,9 @@ private: unsigned m_currentBufferSize; }; -PNGImageDecoder::PNGImageDecoder(bool premultiplyAlpha, bool ignoreGammaAndColorProfile) - : ImageDecoder(premultiplyAlpha, ignoreGammaAndColorProfile) +PNGImageDecoder::PNGImageDecoder(ImageSource::AlphaOption alphaOption, + ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption) + : ImageDecoder(alphaOption, gammaAndColorProfileOption) , m_doNothingOnFailure(false) { } diff --git a/WebCore/platform/image-decoders/png/PNGImageDecoder.h b/WebCore/platform/image-decoders/png/PNGImageDecoder.h index 68b0c1f..1e8902f 100644 --- a/WebCore/platform/image-decoders/png/PNGImageDecoder.h +++ b/WebCore/platform/image-decoders/png/PNGImageDecoder.h @@ -36,7 +36,7 @@ namespace WebCore { // This class decodes the PNG image format. class PNGImageDecoder : public ImageDecoder { public: - PNGImageDecoder(bool premultiplyAlpha, bool ignoreGammaAndColorProfile); + PNGImageDecoder(ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption); virtual ~PNGImageDecoder(); // ImageDecoder diff --git a/WebCore/platform/image-decoders/webp/WEBPImageDecoder.cpp b/WebCore/platform/image-decoders/webp/WEBPImageDecoder.cpp index 0fc0bd5..a988d9c 100644 --- a/WebCore/platform/image-decoders/webp/WEBPImageDecoder.cpp +++ b/WebCore/platform/image-decoders/webp/WEBPImageDecoder.cpp @@ -35,8 +35,9 @@ namespace WebCore { -WEBPImageDecoder::WEBPImageDecoder(bool premultiplyAlpha, bool ignoreGammaAndColorProfile) - : ImageDecoder(premultiplyAlpha, ignoreGammaAndColorProfile) +WEBPImageDecoder::WEBPImageDecoder(ImageSource::AlphaOption alphaOption, + ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption) + : ImageDecoder(alphaOption, gammaAndColorProfileOption) { } diff --git a/WebCore/platform/image-decoders/webp/WEBPImageDecoder.h b/WebCore/platform/image-decoders/webp/WEBPImageDecoder.h index 57b1dae..6cf8870 100644 --- a/WebCore/platform/image-decoders/webp/WEBPImageDecoder.h +++ b/WebCore/platform/image-decoders/webp/WEBPImageDecoder.h @@ -37,7 +37,7 @@ namespace WebCore { class WEBPImageDecoder : public ImageDecoder { public: - WEBPImageDecoder(bool premultiplyAlpha, bool ignoreGammaAndColorProfile); + WEBPImageDecoder(ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption); virtual ~WEBPImageDecoder(); virtual String filenameExtension() const { return "vp8"; } virtual bool isSizeAvailable(); diff --git a/WebCore/platform/image-encoders/skia/JPEGImageEncoder.cpp b/WebCore/platform/image-encoders/skia/JPEGImageEncoder.cpp new file mode 100644 index 0000000..d4e1481 --- /dev/null +++ b/WebCore/platform/image-encoders/skia/JPEGImageEncoder.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2010, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JPEGImageEncoder.h" + +#include "IntSize.h" +#include "SkBitmap.h" +#include "SkUnPreMultiply.h" +#include "SkColorPriv.h" +extern "C" { +#include <stdio.h> // jpeglib.h needs stdio.h FILE +#include "jpeglib.h" +#include <setjmp.h> +} + +namespace WebCore { + +struct JPEGOutputBuffer : public jpeg_destination_mgr { + Vector<unsigned char>* output; + Vector<unsigned char> buffer; +}; + +static void prepareOutput(j_compress_ptr cinfo) +{ + JPEGOutputBuffer* out = static_cast<JPEGOutputBuffer*>(cinfo->dest); + const size_t internalBufferSize = 8192; + out->buffer.resize(internalBufferSize); + out->next_output_byte = out->buffer.data(); + out->free_in_buffer = out->buffer.size(); +} + +static boolean writeOutput(j_compress_ptr cinfo) +{ + JPEGOutputBuffer* out = static_cast<JPEGOutputBuffer*>(cinfo->dest); + out->output->append(out->buffer.data(), out->buffer.size()); + out->next_output_byte = out->buffer.data(); + out->free_in_buffer = out->buffer.size(); + return TRUE; +} + +static void finishOutput(j_compress_ptr cinfo) +{ + JPEGOutputBuffer* out = static_cast<JPEGOutputBuffer*>(cinfo->dest); + const size_t size = out->buffer.size() - out->free_in_buffer; + out->output->append(out->buffer.data(), size); +} + +static void handleError(j_common_ptr common) +{ + jmp_buf* jumpBufferPtr = static_cast<jmp_buf*>(common->client_data); + longjmp(*jumpBufferPtr, -1); +} + +// FIXME: is alpha unpremultiplication correct, or should the alpha channel +// be ignored? See bug http://webkit.org/b/40147. +void preMultipliedBGRAtoRGB(const SkPMColor* input, unsigned int pixels, unsigned char* output) +{ + static const SkUnPreMultiply::Scale* scale = SkUnPreMultiply::GetScaleTable(); + + for (; pixels-- > 0; ++input) { + const unsigned alpha = SkGetPackedA32(*input); + if ((alpha != 0) && (alpha != 255)) { + *output++ = SkUnPreMultiply::ApplyScale(scale[alpha], SkGetPackedR32(*input)); + *output++ = SkUnPreMultiply::ApplyScale(scale[alpha], SkGetPackedG32(*input)); + *output++ = SkUnPreMultiply::ApplyScale(scale[alpha], SkGetPackedB32(*input)); + } else { + *output++ = SkGetPackedR32(*input); + *output++ = SkGetPackedG32(*input); + *output++ = SkGetPackedB32(*input); + } + } +} + +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()); + imageSize.clampNegativeToZero(); + JPEGOutputBuffer destination; + destination.output = output; + Vector<JSAMPLE> row; + + jpeg_compress_struct cinfo; + jpeg_error_mgr error; + cinfo.err = jpeg_std_error(&error); + error.error_exit = handleError; + jmp_buf jumpBuffer; + cinfo.client_data = &jumpBuffer; + + if (setjmp(jumpBuffer)) { + jpeg_destroy_compress(&cinfo); + return false; + } + + jpeg_create_compress(&cinfo); + cinfo.dest = &destination; + cinfo.dest->init_destination = prepareOutput; + cinfo.dest->empty_output_buffer = writeOutput; + cinfo.dest->term_destination = finishOutput; + cinfo.image_height = imageSize.height(); + cinfo.image_width = imageSize.width(); + cinfo.in_color_space = JCS_RGB; + cinfo.input_components = 3; + + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, quality, TRUE); + jpeg_start_compress(&cinfo, TRUE); + + const SkPMColor* pixels = static_cast<SkPMColor*>(bitmap.getPixels()); + row.resize(cinfo.image_width * cinfo.input_components); + while (cinfo.next_scanline < cinfo.image_height) { + preMultipliedBGRAtoRGB(pixels, cinfo.image_width, row.data()); + jpeg_write_scanlines(&cinfo, row.dataSlot(), 1); + pixels += cinfo.image_width; + } + + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + return true; +} + +} // namespace WebCore diff --git a/WebCore/platform/image-encoders/skia/JPEGImageEncoder.h b/WebCore/platform/image-encoders/skia/JPEGImageEncoder.h new file mode 100644 index 0000000..f2ac52d --- /dev/null +++ b/WebCore/platform/image-encoders/skia/JPEGImageEncoder.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2010, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JPEGImageEncoder_h +#define JPEGImageEncoder_h + +#include "Vector.h" + +class SkBitmap; + +namespace WebCore { + +class JPEGImageEncoder { +public: + // Encode the input bitmap with a compression quality in [0-100]. + static bool encode(const SkBitmap&, int quality, Vector<unsigned char>*); + + // For callers: provide a reasonable compression quality default. + enum Quality { DefaultCompressionQuality = 92 }; +}; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/image-encoders/skia/PNGImageEncoder.cpp b/WebCore/platform/image-encoders/skia/PNGImageEncoder.cpp index a2e8760..9fc82c4 100644 --- a/WebCore/platform/image-encoders/skia/PNGImageEncoder.cpp +++ b/WebCore/platform/image-encoders/skia/PNGImageEncoder.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2006-2009, Google Inc. All rights reserved. - * + * Copyright (c) 2010, Google Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above @@ -14,7 +14,7 @@ * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -29,172 +29,66 @@ */ #include "config.h" - -#include "IntSize.h" -#include "OwnArrayPtr.h" #include "PNGImageEncoder.h" -#include "Vector.h" +#include "IntSize.h" #include "SkBitmap.h" #include "SkUnPreMultiply.h" - extern "C" { #include "png.h" } namespace WebCore { -// Converts BGRA->RGBA and RGBA->BGRA. -static void convertBetweenBGRAandRGBA(const unsigned char* input, int numberOfPixels, - unsigned char* output) +static void writeOutput(png_structp png, png_bytep data, png_size_t size) { - for (int x = 0; x < numberOfPixels; x++) { - const unsigned char* pixelIn = &input[x * 4]; - unsigned char* pixelOut = &output[x * 4]; - pixelOut[0] = pixelIn[2]; - pixelOut[1] = pixelIn[1]; - pixelOut[2] = pixelIn[0]; - pixelOut[3] = pixelIn[3]; - } + static_cast<Vector<unsigned char>*>(png->io_ptr)->append(data, size); } -// Converts BGRA->RGBA and RGBA->BGRA and undoes alpha premultiplication. -static void preMultipliedBGRAtoRGBA(const unsigned char* input, int numberOfPixels, - unsigned char* output) +static void preMultipliedBGRAtoRGBA(const SkPMColor* input, int pixels, unsigned char* output) { - SkBitmap inputBitmap; - inputBitmap.setConfig(SkBitmap::kARGB_8888_Config, numberOfPixels, 1); - inputBitmap.setPixels(const_cast<unsigned char*>(input)); - for (int x = 0; x < numberOfPixels; x++) { - uint32_t srcPixel = *inputBitmap.getAddr32(x, 0); - SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(srcPixel); - unsigned char* pixelOut = &output[x * 4]; - pixelOut[0] = SkColorGetR(unmultiplied); - pixelOut[1] = SkColorGetG(unmultiplied); - pixelOut[2] = SkColorGetB(unmultiplied); - pixelOut[3] = SkColorGetA(unmultiplied); + while (pixels-- > 0) { + SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(*input++); + *output++ = SkColorGetR(unmultiplied); + *output++ = SkColorGetG(unmultiplied); + *output++ = SkColorGetB(unmultiplied); + *output++ = SkColorGetA(unmultiplied); } } - -// Encoder -------------------------------------------------------------------- -// -// This section of the code is based on nsPNGEncoder.cpp in Mozilla -// (Copyright 2005 Google Inc.) - -// Passed around as the io_ptr in the png structs so our callbacks know where -// to write data. -struct PNGEncoderState { - PNGEncoderState(Vector<unsigned char>* o) : m_out(o) {} - Vector<unsigned char>* m_out; -}; - -// Called by libpng to flush its internal buffer to ours. -void encoderWriteCallback(png_structp png, png_bytep data, png_size_t size) +bool PNGImageEncoder::encode(const SkBitmap& bitmap, Vector<unsigned char>* output) { - PNGEncoderState* state = static_cast<PNGEncoderState*>(png_get_io_ptr(png)); - ASSERT(state->m_out); + if (bitmap.config() != SkBitmap::kARGB_8888_Config) + return false; // Only support ARGB 32 bpp skia bitmaps. - size_t oldSize = state->m_out->size(); - state->m_out->resize(oldSize + size); - memcpy(&(*state->m_out)[oldSize], data, size); -} - -// Automatically destroys the given write structs on destruction to make -// cleanup and error handling code cleaner. -class PNGWriteStructDestroyer { -public: - PNGWriteStructDestroyer(png_struct** ps, png_info** pi) - : m_pngStruct(ps) - , m_pngInfo(pi) { - } - - ~PNGWriteStructDestroyer() { - png_destroy_write_struct(m_pngStruct, m_pngInfo); - } - -private: - png_struct** m_pngStruct; - png_info** m_pngInfo; -}; - -static bool encodeImpl(const unsigned char* input, - const IntSize& size, - int bytesPerRow, - Vector<unsigned char>* output, - void (*conversionFunc)(const unsigned char*, int, unsigned char*) - ) -{ - int inputColorComponents = 4; - int outputColorComponents = 4; - int pngOutputColorType = PNG_COLOR_TYPE_RGB_ALPHA; - IntSize imageSize(size); + SkAutoLockPixels bitmapLock(bitmap); + IntSize imageSize(bitmap.width(), bitmap.height()); imageSize.clampNegativeToZero(); + Vector<unsigned char> row; - // Row stride should be at least as long as the length of the data. - if (inputColorComponents * imageSize.width() > bytesPerRow) { - ASSERT(false); - return false; - } - - png_struct* pngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); - if (!pngPtr) - return false; - - png_info* infoPtr = png_create_info_struct(pngPtr); - if (!infoPtr) { - png_destroy_write_struct(&pngPtr, NULL); + png_struct* png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); + png_info* info = png_create_info_struct(png); + if (!png || !info || setjmp(png_jmpbuf(png))) { + png_destroy_write_struct(png ? &png : 0, info ? &info : 0); return false; } - PNGWriteStructDestroyer destroyer(&pngPtr, &infoPtr); - - if (setjmp(png_jmpbuf(pngPtr))) { - // The destroyer will ensure that the structures are cleaned up in this - // case, even though we may get here as a jump from random parts of the - // PNG library called below. - return false; - } - - // Set our callback for libpng to give us the data. - PNGEncoderState state(output); - png_set_write_fn(pngPtr, &state, encoderWriteCallback, NULL); - - png_set_IHDR(pngPtr, infoPtr, imageSize.width(), imageSize.height(), 8, pngOutputColorType, - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, - PNG_FILTER_TYPE_DEFAULT); - png_write_info(pngPtr, infoPtr); - OwnArrayPtr<unsigned char> rowPixels(new unsigned char[imageSize.width() * outputColorComponents]); - for (int y = 0; y < imageSize.height(); y ++) { - conversionFunc(&input[y * bytesPerRow], imageSize.width(), rowPixels.get()); - png_write_row(pngPtr, rowPixels.get()); + png_set_write_fn(png, output, writeOutput, 0); + png_set_IHDR(png, info, imageSize.width(), imageSize.height(), + 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()); + for (int y = 0; y < imageSize.height(); ++y) { + preMultipliedBGRAtoRGBA(pixels, imageSize.width(), row.data()); + png_write_row(png, row.data()); + pixels += imageSize.width(); } - png_write_end(pngPtr, infoPtr); + png_write_end(png, info); + png_destroy_write_struct(&png, &info); return true; } - -// static -bool PNGImageEncoder::encode(const SkBitmap& image, Vector<unsigned char>* output) -{ - if (image.config() != SkBitmap::kARGB_8888_Config) - return false; // Only support ARGB at 8 bpp now. - - image.lockPixels(); - bool result = encodeImpl(static_cast<unsigned char*>( - image.getPixels()), IntSize(image.width(), image.height()), - image.rowBytes(), output, preMultipliedBGRAtoRGBA); - image.unlockPixels(); - return result; -} - -// static -bool PNGImageEncoder::encode(const unsigned char* input, const IntSize& size, - int bytesPerRow, - Vector<unsigned char>* output) -{ - return encodeImpl(input, size, bytesPerRow, output, convertBetweenBGRAandRGBA); -} - -} // namespace WebCore +} // namespace WebCore diff --git a/WebCore/platform/image-encoders/skia/PNGImageEncoder.h b/WebCore/platform/image-encoders/skia/PNGImageEncoder.h index b5865d2..b8dfec3 100644 --- a/WebCore/platform/image-encoders/skia/PNGImageEncoder.h +++ b/WebCore/platform/image-encoders/skia/PNGImageEncoder.h @@ -1,10 +1,10 @@ /* - * Copyright (c) 2006-2009, Google Inc. All rights reserved. + * Copyright (c) 2010, Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above @@ -14,7 +14,7 @@ * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -33,23 +33,16 @@ #include "Vector.h" -class IntSize; class SkBitmap; namespace WebCore { - // Interface for encoding PNG data. This is a wrapper around libpng. - class PNGImageEncoder { - public: - // Encodes the specific SkBitmap into the supplied vector. - static bool encode(const SkBitmap&, WTF::Vector<unsigned char>* output); - - // Encodes the specified image data into the supplied vector. - // w, h give the size of the image and bytes_per_row gives the bytes - // per row. - static bool encode(const unsigned char* input, const IntSize& size, int bytesPerRow, WTF::Vector<unsigned char>* output); - }; +// Interface for encoding PNG data. This is a wrapper around libpng. +class PNGImageEncoder { +public: + static bool encode(const SkBitmap&, Vector<unsigned char>* output); +}; -} // namespace WebCore +} // namespace WebCore #endif diff --git a/WebCore/platform/mac/ContextMenuMac.mm b/WebCore/platform/mac/ContextMenuMac.mm index 7c91028..c9451b9 100644 --- a/WebCore/platform/mac/ContextMenuMac.mm +++ b/WebCore/platform/mac/ContextMenuMac.mm @@ -28,92 +28,27 @@ #if ENABLE(CONTEXT_MENUS) -#include "ContextMenuController.h" - -@interface WebCoreMenuTarget : NSObject { - WebCore::ContextMenuController* _menuController; -} -+ (WebCoreMenuTarget*)sharedMenuTarget; -- (WebCore::ContextMenuController*)menuController; -- (void)setMenuController:(WebCore::ContextMenuController*)menuController; -- (void)forwardContextMenuAction:(id)sender; -- (BOOL)validateMenuItem:(NSMenuItem *)item; -@end - -static WebCoreMenuTarget* target; - -@implementation WebCoreMenuTarget - -+ (WebCoreMenuTarget*)sharedMenuTarget -{ - if (!target) - target = [[WebCoreMenuTarget alloc] init]; - return target; -} - -- (WebCore::ContextMenuController*)menuController -{ - return _menuController; -} - -- (void)setMenuController:(WebCore::ContextMenuController*)menuController -{ - _menuController = menuController; -} - -- (void)forwardContextMenuAction:(id)sender -{ - WebCore::ContextMenuItem item(WebCore::ActionType, static_cast<WebCore::ContextMenuAction>([sender tag]), [sender title]); - _menuController->contextMenuItemSelected(&item); -} - -- (BOOL)validateMenuItem:(NSMenuItem *)item -{ - WebCore::ContextMenuItem coreItem(item); - ASSERT(_menuController->contextMenu()); - _menuController->contextMenu()->checkOrEnableIfNeeded(coreItem); - return coreItem.enabled(); -} - -@end - namespace WebCore { -ContextMenu::ContextMenu(const HitTestResult& result) - : m_hitTestResult(result) +ContextMenu::ContextMenu() { NSMutableArray* array = [[NSMutableArray alloc] init]; m_platformDescription = array; [array release]; - - [[WebCoreMenuTarget sharedMenuTarget] setMenuController:controller()]; } -ContextMenu::ContextMenu(const HitTestResult& result, const PlatformMenuDescription menu) - : m_hitTestResult(result) - , m_platformDescription(menu) +ContextMenu::ContextMenu(const PlatformMenuDescription menu) + : m_platformDescription(menu) { - [[WebCoreMenuTarget sharedMenuTarget] setMenuController:controller()]; } ContextMenu::~ContextMenu() { } - -static void setMenuItemTarget(NSMenuItem* menuItem) -{ - [menuItem setTarget:[WebCoreMenuTarget sharedMenuTarget]]; - [menuItem setAction:@selector(forwardContextMenuAction:)]; -} void ContextMenu::appendItem(ContextMenuItem& item) { - checkOrEnableIfNeeded(item); - - ContextMenuItemType type = item.type(); NSMenuItem* platformItem = item.releasePlatformDescription(); - if (type == ActionType) - setMenuItemTarget(platformItem); [m_platformDescription.get() addObject:platformItem]; [platformItem release]; @@ -121,12 +56,7 @@ void ContextMenu::appendItem(ContextMenuItem& item) void ContextMenu::insertItem(unsigned position, ContextMenuItem& item) { - checkOrEnableIfNeeded(item); - - ContextMenuItemType type = item.type(); NSMenuItem* platformItem = item.releasePlatformDescription(); - if (type == ActionType) - setMenuItemTarget(platformItem); [m_platformDescription.get() insertObject:platformItem atIndex:position]; [platformItem release]; diff --git a/WebCore/platform/mac/GeolocationServiceMac.h b/WebCore/platform/mac/GeolocationServiceMac.h deleted file mode 100644 index 4beefca..0000000 --- a/WebCore/platform/mac/GeolocationServiceMac.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2009 Apple Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef GeolocationServiceMac_h -#define GeolocationServiceMac_h - -#if ENABLE(GEOLOCATION) - -#include "GeolocationService.h" -#include <wtf/PassRefPtr.h> -#include <wtf/RefPtr.h> -#include <wtf/RetainPtr.h> - -#ifdef __OBJC__ -@class CLLocationManager; -@class WebCoreCoreLocationObserver; -#else -class CLLocationManager; -class WebCoreCoreLocationObserver; -#endif - -namespace WebCore { - -class GeolocationServiceMac : public GeolocationService { -public: - static GeolocationService* create(GeolocationServiceClient*); - virtual ~GeolocationServiceMac(); - - virtual bool startUpdating(PositionOptions*); - virtual void stopUpdating(); - - virtual void suspend(); - virtual void resume(); - - virtual Geoposition* lastPosition() const { return m_lastPosition.get(); } - virtual PositionError* lastError() const { return m_lastError.get(); } - - void positionChanged(PassRefPtr<Geoposition>); - void errorOccurred(PassRefPtr<PositionError>); - -private: - GeolocationServiceMac(GeolocationServiceClient*); - - RetainPtr<CLLocationManager> m_locationManager; - RetainPtr<WebCoreCoreLocationObserver> m_objcObserver; - - RefPtr<Geoposition> m_lastPosition; - RefPtr<PositionError> m_lastError; -}; - -} // namespace WebCore - -#endif // ENABLE(GEOLOCATION) - -#endif // GeolocationServiceMac_h diff --git a/WebCore/platform/mac/GeolocationServiceMac.mm b/WebCore/platform/mac/GeolocationServiceMac.mm deleted file mode 100644 index 9c781ad..0000000 --- a/WebCore/platform/mac/GeolocationServiceMac.mm +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (C) 2009 Apple Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import "config.h" - -#if ENABLE(GEOLOCATION) && !ENABLE(CLIENT_BASED_GEOLOCATION) - -#import "GeolocationServiceMac.h" - -#import "Geoposition.h" -#import "PositionError.h" -#import "PositionOptions.h" -#import "SoftLinking.h" -#import <CoreLocation/CoreLocation.h> -#import <objc/objc-runtime.h> -#import <wtf/RefPtr.h> -#import <wtf/UnusedParam.h> - -SOFT_LINK_FRAMEWORK(CoreLocation) - -SOFT_LINK_CLASS(CoreLocation, CLLocationManager) -SOFT_LINK_CLASS(CoreLocation, CLLocation) - -SOFT_LINK_CONSTANT(CoreLocation, kCLLocationAccuracyBest, double) -SOFT_LINK_CONSTANT(CoreLocation, kCLLocationAccuracyHundredMeters, double) - -#define kCLLocationAccuracyBest getkCLLocationAccuracyBest() -#define kCLLocationAccuracyHundredMeters getkCLLocationAccuracyHundredMeters() - -using namespace WebCore; - -@interface WebCoreCoreLocationObserver : NSObject<CLLocationManagerDelegate> -{ - GeolocationServiceMac* m_callback; -} - -- (id)initWithCallback:(GeolocationServiceMac*)callback; - -- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation; -- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error; - -@end - -namespace WebCore { - -GeolocationService* GeolocationServiceMac::create(GeolocationServiceClient* client) -{ - return new GeolocationServiceMac(client); -} - -GeolocationService::FactoryFunction* GeolocationService::s_factoryFunction = &GeolocationServiceMac::create; - -GeolocationServiceMac::GeolocationServiceMac(GeolocationServiceClient* client) - : GeolocationService(client) - , m_objcObserver(AdoptNS, [[WebCoreCoreLocationObserver alloc] initWithCallback:this]) -{ -} - -GeolocationServiceMac::~GeolocationServiceMac() -{ - [m_locationManager.get() stopUpdatingLocation]; - m_locationManager.get().delegate = nil; -} - -bool GeolocationServiceMac::startUpdating(PositionOptions* options) -{ - #define CLLocationManager getCLLocationManagerClass() - if (!m_locationManager.get()) { - m_locationManager.adoptNS([[CLLocationManager alloc] init]); - m_locationManager.get().delegate = m_objcObserver.get(); - } - - if (!m_locationManager.get().locationServicesEnabled) - return false; - - if (options) { - // CLLocationAccuracy values suggested by Ron Huang. - CLLocationAccuracy accuracy = options->enableHighAccuracy() ? kCLLocationAccuracyBest : kCLLocationAccuracyHundredMeters; - m_locationManager.get().desiredAccuracy = accuracy; - } - - // This can safely be called multiple times. - [m_locationManager.get() startUpdatingLocation]; - - return true; - #undef CLLocationManager -} - -void GeolocationServiceMac::stopUpdating() -{ - [m_locationManager.get() stopUpdatingLocation]; -} - -void GeolocationServiceMac::suspend() -{ - [m_locationManager.get() stopUpdatingLocation]; -} - -void GeolocationServiceMac::resume() -{ - [m_locationManager.get() startUpdatingLocation]; -} - -void GeolocationServiceMac::positionChanged(PassRefPtr<Geoposition> position) -{ - m_lastPosition = position; - GeolocationService::positionChanged(); -} - -void GeolocationServiceMac::errorOccurred(PassRefPtr<PositionError> error) -{ - m_lastError = error; - GeolocationService::errorOccurred(); -} - -} // namespace WebCore - -@implementation WebCoreCoreLocationObserver - -- (id)initWithCallback:(GeolocationServiceMac *)callback -{ - self = [super init]; - if (self) - m_callback = callback; - return self; -} - -- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation -{ - ASSERT(m_callback); - ASSERT(newLocation); - UNUSED_PARAM(manager); - UNUSED_PARAM(oldLocation); - - // Normalize - bool canProvideAltitude = true; - bool canProvideAltitudeAccuracy = true; - double altitude = newLocation.altitude; - double altitudeAccuracy = newLocation.verticalAccuracy; - if (altitudeAccuracy < 0.0) { - canProvideAltitude = false; - canProvideAltitudeAccuracy = false; - } - - bool canProvideSpeed = true; - double speed = newLocation.speed; - if (speed < 0.0) - canProvideSpeed = false; - - bool canProvideHeading = true; - double heading = newLocation.course; - if (heading < 0.0) - canProvideHeading = false; - - WTF::RefPtr<WebCore::Coordinates> newCoordinates = WebCore::Coordinates::create( - newLocation.coordinate.latitude, - newLocation.coordinate.longitude, - canProvideAltitude, - altitude, - newLocation.horizontalAccuracy, - canProvideAltitudeAccuracy, - altitudeAccuracy, - canProvideHeading, - heading, - canProvideSpeed, - speed); - WTF::RefPtr<WebCore::Geoposition> newPosition = WebCore::Geoposition::create( - newCoordinates.release(), - [newLocation.timestamp timeIntervalSince1970] * 1000.0); // seconds -> milliseconds - - m_callback->positionChanged(newPosition.release()); -} - -- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error -{ - ASSERT(m_callback); - ASSERT(error); - - UNUSED_PARAM(manager); - - PositionError::ErrorCode code; - switch ([error code]) { - case kCLErrorDenied: - code = PositionError::PERMISSION_DENIED; - break; - case kCLErrorLocationUnknown: - code = PositionError::POSITION_UNAVAILABLE; - break; - default: - code = PositionError::POSITION_UNAVAILABLE; - break; - } - - m_callback->errorOccurred(PositionError::create(code, [error localizedDescription])); -} - -@end - -#endif // ENABLE(GEOLOCATION) diff --git a/WebCore/platform/mac/ScrollAnimatorMac.cpp b/WebCore/platform/mac/ScrollAnimatorMac.cpp deleted file mode 100644 index f127a62..0000000 --- a/WebCore/platform/mac/ScrollAnimatorMac.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2010 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#if ENABLE(SMOOTH_SCROLLING) - -#include "ScrollAnimatorMac.h" - -namespace WebCore { - -ScrollAnimator* ScrollAnimator::create(ScrollbarClient* client) -{ - return new ScrollAnimatorMac(client); -} - -ScrollAnimatorMac::ScrollAnimatorMac(ScrollbarClient* client) - : ScrollAnimator(client) -{ -} - -ScrollAnimatorMac::~ScrollAnimatorMac() -{ -} - -bool ScrollAnimatorMac::scroll(ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float multiplier) -{ - return ScrollAnimator::scroll(orientation, granularity, step, multiplier); -} - -void ScrollAnimatorMac::setScrollPositionAndStopAnimation(ScrollbarOrientation orientation, float pos) -{ - return ScrollAnimator::setScrollPositionAndStopAnimation(orientation, pos); -} - -} // namespace WebCore - -#endif // ENABLE(SMOOTH_SCROLLING) diff --git a/WebCore/platform/mac/ScrollAnimatorMac.h b/WebCore/platform/mac/ScrollAnimatorMac.h index 3beaa4e..234e43c 100644 --- a/WebCore/platform/mac/ScrollAnimatorMac.h +++ b/WebCore/platform/mac/ScrollAnimatorMac.h @@ -28,8 +28,15 @@ #if ENABLE(SMOOTH_SCROLLING) +#include "FloatPoint.h" #include "ScrollAnimator.h" -#include "Timer.h" +#include <wtf/RetainPtr.h> + +#ifdef __OBJC__ +@class ScrollAnimationHelperDelegate; +#else +class ScrollAnimationHelperDelegate; +#endif namespace WebCore { @@ -40,6 +47,14 @@ public: virtual bool scroll(ScrollbarOrientation, ScrollGranularity, float step, float multiplier); virtual void setScrollPositionAndStopAnimation(ScrollbarOrientation, float position); + + // Called by the ScrollAnimationHelperDelegate. + FloatPoint currentPosition() const; + void immediateScrollToPoint(const FloatPoint& newPosition); + +private: + RetainPtr<id> m_scrollAnimationHelper; + RetainPtr<ScrollAnimationHelperDelegate> m_scrollAnimationHelperDelegate; }; } // namespace WebCore diff --git a/WebCore/platform/mac/ScrollAnimatorMac.mm b/WebCore/platform/mac/ScrollAnimatorMac.mm new file mode 100644 index 0000000..ca71bd3 --- /dev/null +++ b/WebCore/platform/mac/ScrollAnimatorMac.mm @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(SMOOTH_SCROLLING) + +#include "ScrollAnimatorMac.h" +#include "ScrollbarClient.h" + +@interface NSObject (NSScrollAnimationHelperDetails) +- (id)initWithDelegate:(id)delegate; +- (void)_stopRun; +- (BOOL)_isAnimating; +- (NSPoint)targetOrigin; +@end + +@interface ScrollAnimationHelperDelegate : NSObject +{ + WebCore::ScrollAnimatorMac* _animator; +} + +- (id)initWithScrollAnimator:(WebCore::ScrollAnimatorMac*)scrollAnimator; + +- (NSRect)bounds; +- (void)_immediateScrollToPoint:(NSPoint)newPosition; +- (NSSize)convertSizeToBase:(NSSize)size; +- (NSSize)convertSizeFromBase:(NSSize)size; + +- (id)superview; // Return nil. +- (id)documentView; // Return nil. +- (id)window; // Return nil. +- (void)_recursiveRecomputeToolTips; // No-op. +@end + +static NSSize abs(NSSize size) +{ + NSSize finalSize = size; + if (finalSize.width < 0) + finalSize.width = -finalSize.width; + if (finalSize.height < 0) + finalSize.height = -finalSize.height; + return finalSize; +} + +@implementation ScrollAnimationHelperDelegate + +- (id)initWithScrollAnimator:(WebCore::ScrollAnimatorMac*)scrollAnimator +{ + self = [super init]; + if (!self) + return nil; + + _animator = scrollAnimator; + return self; +} + +- (NSRect)bounds +{ + WebCore::FloatPoint currentPosition = _animator->currentPosition(); + return NSMakeRect(currentPosition.x(), currentPosition.y(), 0, 0); +} + +- (void)_immediateScrollToPoint:(NSPoint)newPosition +{ + _animator->immediateScrollToPoint(newPosition); +} + +- (NSSize)convertSizeToBase:(NSSize)size +{ + return abs(size); +} + +- (NSSize)convertSizeFromBase:(NSSize)size +{ + return abs(size); +} + +- (id)superview +{ + return nil; +} + +- (id)documentView +{ + return nil; +} + +- (id)window +{ + return nil; +} + +- (void)_recursiveRecomputeToolTips +{ +} + +@end + +namespace WebCore { + +ScrollAnimator* ScrollAnimator::create(ScrollbarClient* client) +{ + return new ScrollAnimatorMac(client); +} + +ScrollAnimatorMac::ScrollAnimatorMac(ScrollbarClient* client) + : ScrollAnimator(client) +{ + m_scrollAnimationHelperDelegate.adoptNS([[ScrollAnimationHelperDelegate alloc] initWithScrollAnimator:this]); + m_scrollAnimationHelper.adoptNS([[NSClassFromString(@"NSScrollAnimationHelper") alloc] initWithDelegate:m_scrollAnimationHelperDelegate.get()]); +} + +ScrollAnimatorMac::~ScrollAnimatorMac() +{ +} + +bool ScrollAnimatorMac::scroll(ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float multiplier) +{ + if (![[NSUserDefaults standardUserDefaults] boolForKey:@"AppleScrollAnimationEnabled"]) + return ScrollAnimator::scroll(orientation, granularity, step, multiplier); + + if (granularity == ScrollByPixel) + return ScrollAnimator::scroll(orientation, granularity, step, multiplier); + + float currentPos = orientation == HorizontalScrollbar ? m_currentPosX : m_currentPosY; + float newPos = std::max<float>(std::min<float>(currentPos + (step * multiplier), static_cast<float>(m_client->scrollSize(orientation))), 0); + if (currentPos == newPos) + return false; + + NSPoint newPoint; + if ([m_scrollAnimationHelper.get() _isAnimating]) { + NSPoint targetOrigin = [m_scrollAnimationHelper.get() targetOrigin]; + newPoint = orientation == HorizontalScrollbar ? NSMakePoint(newPos, targetOrigin.y) : NSMakePoint(targetOrigin.x, newPos); + } else + newPoint = orientation == HorizontalScrollbar ? NSMakePoint(newPos, m_currentPosY) : NSMakePoint(m_currentPosX, newPos); + + [m_scrollAnimationHelper.get() scrollToPoint:newPoint]; + return true; +} + +void ScrollAnimatorMac::setScrollPositionAndStopAnimation(ScrollbarOrientation orientation, float pos) +{ + [m_scrollAnimationHelper.get() _stopRun]; + ScrollAnimator::setScrollPositionAndStopAnimation(orientation, pos); +} + +FloatPoint ScrollAnimatorMac::currentPosition() const +{ + return FloatPoint(m_currentPosX, m_currentPosY); +} + +void ScrollAnimatorMac::immediateScrollToPoint(const FloatPoint& newPosition) +{ + m_currentPosX = newPosition.x(); + m_currentPosY = newPosition.y(); + + m_client->setScrollOffsetFromAnimation(IntPoint(m_currentPosX, m_currentPosY)); +} + +} // namespace WebCore + +#endif // ENABLE(SMOOTH_SCROLLING) diff --git a/WebCore/platform/mac/ScrollViewMac.mm b/WebCore/platform/mac/ScrollViewMac.mm index 7e415da..93ec971 100644 --- a/WebCore/platform/mac/ScrollViewMac.mm +++ b/WebCore/platform/mac/ScrollViewMac.mm @@ -147,7 +147,8 @@ void ScrollView::platformSetScrollbarsSuppressed(bool repaintOnUnsuppress) void ScrollView::platformSetScrollPosition(const IntPoint& scrollPoint) { BEGIN_BLOCK_OBJC_EXCEPTIONS; - NSPoint tempPoint = { max(-[scrollView() scrollOriginX], scrollPoint.x()), max(0, scrollPoint.y()) }; // Don't use NSMakePoint to work around 4213314. + NSPoint floatPoint = scrollPoint; + NSPoint tempPoint = { max(-[scrollView() scrollOrigin].x, floatPoint.x), max(-[scrollView() scrollOrigin].y, floatPoint.y) }; // Don't use NSMakePoint to work around 4213314. [documentView() scrollPoint:tempPoint]; END_BLOCK_OBJC_EXCEPTIONS; } @@ -202,10 +203,10 @@ bool ScrollView::platformIsOffscreen() const return ![platformWidget() window] || ![[platformWidget() window] isVisible]; } -void ScrollView::platformSetScrollOriginX(int x) +void ScrollView::platformSetScrollOrigin(const IntPoint& origin, bool updatePosition) { BEGIN_BLOCK_OBJC_EXCEPTIONS; - [scrollView() setScrollOriginX:x]; + [scrollView() setScrollOrigin:origin updatePosition:updatePosition]; END_BLOCK_OBJC_EXCEPTIONS; } diff --git a/WebCore/platform/mac/WebCoreSystemInterface.h b/WebCore/platform/mac/WebCoreSystemInterface.h index 201266e..0c78c23 100644 --- a/WebCore/platform/mac/WebCoreSystemInterface.h +++ b/WebCore/platform/mac/WebCoreSystemInterface.h @@ -29,6 +29,10 @@ #include <ApplicationServices/ApplicationServices.h> #include <objc/objc.h> +#if PLATFORM(MAC) && PLATFORM(CA) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) +#include <IOSurface/IOSurface.h> +#endif + typedef struct _NSRange NSRange; #ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES @@ -179,6 +183,9 @@ extern CFIndex (*wkGetHyphenationLocationBeforeIndex)(CFStringRef string, CFInde extern CTLineRef (*wkCreateCTLineWithUniCharProvider)(const UniChar* (*provide)(CFIndex stringIndex, CFIndex* charCount, CFDictionaryRef* attributes, void*), void (*dispose)(const UniChar* chars, void*), void*); #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) extern CTTypesetterRef (*wkCreateCTTypesetterWithUniCharProviderAndOptions)(const UniChar* (*provide)(CFIndex stringIndex, CFIndex* charCount, CFDictionaryRef* attributes, void*), void (*dispose)(const UniChar* chars, void*), void*, CFDictionaryRef options); + +extern CGContextRef (*wkIOSurfaceContextCreate)(IOSurfaceRef surface, unsigned width, unsigned height, CGColorSpaceRef colorSpace); +extern CGImageRef (*wkIOSurfaceContextCreateImage)(CGContextRef context); #endif } diff --git a/WebCore/platform/mac/WebCoreSystemInterface.mm b/WebCore/platform/mac/WebCoreSystemInterface.mm index 9c0c441..df3c77c 100644 --- a/WebCore/platform/mac/WebCoreSystemInterface.mm +++ b/WebCore/platform/mac/WebCoreSystemInterface.mm @@ -122,4 +122,7 @@ CFIndex (*wkGetHyphenationLocationBeforeIndex)(CFStringRef string, CFIndex index CTLineRef (*wkCreateCTLineWithUniCharProvider)(const UniChar* (*provide)(CFIndex stringIndex, CFIndex* charCount, CFDictionaryRef* attributes, void*), void (*dispose)(const UniChar* chars, void*), void*); #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) CTTypesetterRef (*wkCreateCTTypesetterWithUniCharProviderAndOptions)(const UniChar* (*provide)(CFIndex stringIndex, CFIndex* charCount, CFDictionaryRef* attributes, void*), void (*dispose)(const UniChar* chars, void*), void*, CFDictionaryRef options); + +CGContextRef (*wkIOSurfaceContextCreate)(IOSurfaceRef surface, unsigned width, unsigned height, CGColorSpaceRef colorSpace); +CGImageRef (*wkIOSurfaceContextCreateImage)(CGContextRef context); #endif diff --git a/WebCore/platform/mock/GeolocationClientMock.cpp b/WebCore/platform/mock/GeolocationClientMock.cpp index 3c4697f..5255b34 100644 --- a/WebCore/platform/mock/GeolocationClientMock.cpp +++ b/WebCore/platform/mock/GeolocationClientMock.cpp @@ -41,8 +41,10 @@ namespace WebCore { GeolocationClientMock::GeolocationClientMock() : m_controller(0) - , m_timer(this, &GeolocationClientMock::timerFired) + , m_controllerTimer(this, &GeolocationClientMock::controllerTimerFired) + , m_permissionTimer(this, &GeolocationClientMock::permissionTimerFired) , m_isActive(false) + , m_permissionState(PermissionStateUnset) { } @@ -71,10 +73,55 @@ void GeolocationClientMock::setError(PassRefPtr<GeolocationError> error) asyncUpdateController(); } +void GeolocationClientMock::setPermission(bool allowed) +{ + m_permissionState = allowed ? PermissionStateAllowed : PermissionStateDenied; + asyncUpdatePermission(); +} + +void GeolocationClientMock::requestPermission(Geolocation* geolocation) +{ + m_pendingPermission.add(geolocation); + if (m_permissionState != PermissionStateUnset) + asyncUpdatePermission(); +} + +void GeolocationClientMock::cancelPermissionRequest(Geolocation* geolocation) +{ + // Called from Geolocation::disconnectFrame() in response to Frame destruction. + m_pendingPermission.remove(geolocation); + if (m_pendingPermission.isEmpty() && m_permissionTimer.isActive()) + m_permissionTimer.stop(); +} + +void GeolocationClientMock::asyncUpdatePermission() +{ + ASSERT(m_permissionState != PermissionStateUnset); + if (!m_permissionTimer.isActive()) + m_permissionTimer.startOneShot(0); +} + +void GeolocationClientMock::permissionTimerFired(WebCore::Timer<GeolocationClientMock>* timer) +{ + ASSERT_UNUSED(timer, timer == &m_permissionTimer); + ASSERT(m_permissionState != PermissionStateUnset); + bool allowed = m_permissionState == PermissionStateAllowed; + GeolocationSet::iterator end = m_pendingPermission.end(); + + // Once permission has been set (or denied) on a Geolocation object, there can be + // no further requests for permission to the mock. Consequently the callbacks + // which fire synchronously from Geolocation::setIsAllowed() cannot reentrantly modify + // m_pendingPermission. + for (GeolocationSet::iterator it = m_pendingPermission.begin(); it != end; ++it) + (*it)->setIsAllowed(allowed); + m_pendingPermission.clear(); +} + void GeolocationClientMock::reset() { m_lastPosition = 0; m_lastError = 0; + m_permissionState = PermissionStateUnset; } void GeolocationClientMock::geolocationDestroyed() @@ -93,7 +140,7 @@ void GeolocationClientMock::stopUpdating() { ASSERT(m_isActive); m_isActive = false; - m_timer.stop(); + m_controllerTimer.stop(); } void GeolocationClientMock::setEnableHighAccuracy(bool) @@ -110,18 +157,13 @@ GeolocationPosition* GeolocationClientMock::lastPosition() void GeolocationClientMock::asyncUpdateController() { ASSERT(m_controller); - if (m_isActive && !m_timer.isActive()) - m_timer.startOneShot(0); -} - -void GeolocationClientMock::timerFired(Timer<GeolocationClientMock>* timer) -{ - ASSERT_UNUSED(timer, timer == &m_timer); - updateController(); + if (m_isActive && !m_controllerTimer.isActive()) + m_controllerTimer.startOneShot(0); } -void GeolocationClientMock::updateController() +void GeolocationClientMock::controllerTimerFired(Timer<GeolocationClientMock>* timer) { + ASSERT_UNUSED(timer, timer == &m_controllerTimer); ASSERT(m_controller); if (m_lastPosition.get()) diff --git a/WebCore/platform/mock/GeolocationClientMock.h b/WebCore/platform/mock/GeolocationClientMock.h index f57afa9..df35316 100644 --- a/WebCore/platform/mock/GeolocationClientMock.h +++ b/WebCore/platform/mock/GeolocationClientMock.h @@ -37,6 +37,7 @@ #include "PlatformString.h" #include "Timer.h" +#include <wtf/HashSet.h> #include <wtf/PassRefPtr.h> #include <wtf/RefPtr.h> @@ -57,6 +58,7 @@ public: void setError(PassRefPtr<GeolocationError>); void setPosition(PassRefPtr<GeolocationPosition>); + void setPermission(bool allowed); // GeolocationClient virtual void geolocationDestroyed(); @@ -64,17 +66,30 @@ public: virtual void stopUpdating(); virtual void setEnableHighAccuracy(bool); virtual GeolocationPosition* lastPosition(); + virtual void requestPermission(Geolocation*); + virtual void cancelPermissionRequest(Geolocation*); private: - void timerFired(Timer<GeolocationClientMock>*); void asyncUpdateController(); - void updateController(); + void controllerTimerFired(Timer<GeolocationClientMock>*); + + void asyncUpdatePermission(); + void permissionTimerFired(Timer<GeolocationClientMock>*); GeolocationController* m_controller; RefPtr<GeolocationPosition> m_lastPosition; RefPtr<GeolocationError> m_lastError; - Timer<GeolocationClientMock> m_timer; + Timer<GeolocationClientMock> m_controllerTimer; + Timer<GeolocationClientMock> m_permissionTimer; bool m_isActive; + + enum PermissionState { + PermissionStateUnset, + PermissionStateAllowed, + PermissionStateDenied, + } m_permissionState; + typedef WTF::HashSet<RefPtr<Geolocation> > GeolocationSet; + GeolocationSet m_pendingPermission; }; } diff --git a/WebCore/platform/network/ResourceRequestBase.cpp b/WebCore/platform/network/ResourceRequestBase.cpp index 5312007..ae8316a 100644 --- a/WebCore/platform/network/ResourceRequestBase.cpp +++ b/WebCore/platform/network/ResourceRequestBase.cpp @@ -234,6 +234,16 @@ void ResourceRequestBase::setHTTPHeaderField(const char* name, const String& val setHTTPHeaderField(AtomicString(name), value); } +void ResourceRequestBase::clearHTTPAuthorization() +{ + updateResourceRequest(); + + m_httpHeaderFields.remove("Authorization"); + + if (url().protocolInHTTPFamily()) + m_platformRequestUpdated = false; +} + void ResourceRequestBase::clearHTTPReferrer() { updateResourceRequest(); diff --git a/WebCore/platform/network/ResourceRequestBase.h b/WebCore/platform/network/ResourceRequestBase.h index 33a184e..5cb7ee3 100644 --- a/WebCore/platform/network/ResourceRequestBase.h +++ b/WebCore/platform/network/ResourceRequestBase.h @@ -100,6 +100,8 @@ namespace WebCore { void addHTTPHeaderField(const AtomicString& name, const String& value); void addHTTPHeaderFields(const HTTPHeaderMap& headerFields); + void clearHTTPAuthorization(); + String httpContentType() const { return httpHeaderField("Content-Type"); } void setHTTPContentType(const String& httpContentType) { setHTTPHeaderField("Content-Type", httpContentType); } diff --git a/WebCore/platform/network/SocketStreamErrorBase.cpp b/WebCore/platform/network/SocketStreamErrorBase.cpp index 72fb44c..bbb5d55 100644 --- a/WebCore/platform/network/SocketStreamErrorBase.cpp +++ b/WebCore/platform/network/SocketStreamErrorBase.cpp @@ -42,7 +42,22 @@ SocketStreamError SocketStreamErrorBase::copy() const bool SocketStreamErrorBase::compare(const SocketStreamError& a, const SocketStreamError& b) { - return a.errorCode() == b.errorCode(); + if (a.isNull() && b.isNull()) + return true; + + if (a.isNull() || b.isNull()) + return false; + + if (a.errorCode() != b.errorCode()) + return false; + + if (a.failingURL() != b.failingURL()) + return false; + + if (a.localizedDescription() != b.localizedDescription()) + return false; + + return true; } } // namespace WebCore diff --git a/WebCore/platform/network/SocketStreamErrorBase.h b/WebCore/platform/network/SocketStreamErrorBase.h index b7ca35b..e6cc567 100644 --- a/WebCore/platform/network/SocketStreamErrorBase.h +++ b/WebCore/platform/network/SocketStreamErrorBase.h @@ -32,6 +32,8 @@ #ifndef SocketStreamErrorBase_h #define SocketStreamErrorBase_h +#include "PlatformString.h" + namespace WebCore { class SocketStreamError; @@ -44,6 +46,8 @@ namespace WebCore { bool isNull() const { return m_isNull; } int errorCode() const { return m_errorCode; } + const String& failingURL() const { return m_failingURL; } + const String& localizedDescription() const { return m_localizedDescription; } static bool compare(const SocketStreamError&, const SocketStreamError&); @@ -60,7 +64,17 @@ namespace WebCore { { } + SocketStreamErrorBase(int errorCode, const String& failingURL, const String& localizedDescription) + : m_errorCode(errorCode) + , m_failingURL(failingURL) + , m_localizedDescription(localizedDescription) + , m_isNull(false) + { + } + int m_errorCode; + String m_failingURL; + String m_localizedDescription; bool m_isNull; }; diff --git a/WebCore/platform/network/cf/DNSCFNet.cpp b/WebCore/platform/network/cf/DNSCFNet.cpp index fbceb7d..166abbf 100644 --- a/WebCore/platform/network/cf/DNSCFNet.cpp +++ b/WebCore/platform/network/cf/DNSCFNet.cpp @@ -27,6 +27,7 @@ #include "config.h" #include "DNS.h" +#include "KURL.h" #include "Timer.h" #include <wtf/HashSet.h> #include <wtf/RetainPtr.h> @@ -37,6 +38,10 @@ #include "LoaderRunLoopCF.h" #endif +#if defined(BUILDING_ON_LEOPARD) +#include <SystemConfiguration/SystemConfiguration.h> +#endif + #ifdef BUILDING_ON_TIGER // This function is available on Tiger, but not declared in the CFRunLoop.h header on Tiger. extern "C" CFRunLoopRef CFRunLoopGetMain(); @@ -62,6 +67,37 @@ const int maxRequestsToQueue = 64; // If there were queued names that couldn't be sent simultaneously, check the state of resolvers after this delay. const double retryResolvingInSeconds = 0.1; +static bool proxyIsEnabledInSystemPreferences() +{ + // Don't do DNS prefetch if proxies are involved. For many proxy types, the user agent is never exposed + // to the IP address during normal operation. Querying an internal DNS server may not help performance, + // as it doesn't necessarily look up the actual external IP. Also, if DNS returns a fake internal address, + // local caches may keep it even after re-connecting to another network. + +#if !defined(BUILDING_ON_LEOPARD) + RetainPtr<CFDictionaryRef> proxySettings(AdoptCF, CFNetworkCopySystemProxySettings()); +#else + RetainPtr<CFDictionaryRef> proxySettings(AdoptCF, SCDynamicStoreCopyProxies(0)); +#endif + if (!proxySettings) + return false; + + static CFURLRef httpCFURL = KURL(ParsedURLString, "http://example.com/").createCFURL(); + static CFURLRef httpsCFURL = KURL(ParsedURLString, "https://example.com/").createCFURL(); + + RetainPtr<CFArrayRef> httpProxyArray(AdoptCF, CFNetworkCopyProxiesForURL(httpCFURL, proxySettings.get())); + RetainPtr<CFArrayRef> httpsProxyArray(AdoptCF, CFNetworkCopyProxiesForURL(httpsCFURL, proxySettings.get())); + + CFIndex httpProxyCount = CFArrayGetCount(httpProxyArray.get()); + CFIndex httpsProxyCount = CFArrayGetCount(httpsProxyArray.get()); + if (httpProxyCount == 1 && CFEqual(CFDictionaryGetValue(static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(httpProxyArray.get(), 0)), kCFProxyTypeKey), kCFProxyTypeNone)) + httpProxyCount = 0; + if (httpsProxyCount == 1 && CFEqual(CFDictionaryGetValue(static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(httpsProxyArray.get(), 0)), kCFProxyTypeKey), kCFProxyTypeNone)) + httpsProxyCount = 0; + + return httpProxyCount || httpsProxyCount; +} + class DNSResolveQueue : public TimerBase { public: static DNSResolveQueue& shared(); @@ -92,6 +128,9 @@ void DNSResolveQueue::add(const String& name) { // If there are no names queued, and few enough are in flight, resolve immediately (the mouse may be over a link). if (!m_names.size()) { + if (proxyIsEnabledInSystemPreferences()) + return; + if (atomicIncrement(&m_requestsInFlight) <= namesToResolveImmediately) { resolve(name); return; @@ -115,6 +154,11 @@ void DNSResolveQueue::decrementRequestCount() void DNSResolveQueue::fired() { + if (proxyIsEnabledInSystemPreferences()) { + m_names.clear(); + return; + } + int requestsAllowed = maxSimultaneousRequests - m_requestsInFlight; for (; !m_names.isEmpty() && requestsAllowed > 0; --requestsAllowed) { diff --git a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp index e48bd2d..f0773d2 100644 --- a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp +++ b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp @@ -481,6 +481,8 @@ void ResourceHandle::willSendRequest(ResourceRequest& request, const ResourceRes d->m_pass = url.pass(); d->m_lastHTTPMethod = request.httpMethod(); request.removeCredentials(); + if (!protocolHostAndPortAreEqual(request.url(), redirectResponse.url())) + request.clearHTTPAuthorization(); client()->willSendRequest(this, request, redirectResponse); } diff --git a/WebCore/platform/network/cf/ResourceResponseCFNet.cpp b/WebCore/platform/network/cf/ResourceResponseCFNet.cpp index 469e5ad..9a83add 100644 --- a/WebCore/platform/network/cf/ResourceResponseCFNet.cpp +++ b/WebCore/platform/network/cf/ResourceResponseCFNet.cpp @@ -79,6 +79,11 @@ void ResourceResponse::platformLazyInit() m_expectedContentLength = CFURLResponseGetExpectedContentLength(m_cfResponse.get()); m_textEncodingName = CFURLResponseGetTextEncodingName(m_cfResponse.get()); + // Workaround for <rdar://problem/8757088>, can be removed once that is fixed. + unsigned textEncodingNameLength = m_textEncodingName.length(); + if (textEncodingNameLength >= 2 && m_textEncodingName[0U] == '"' && m_textEncodingName[textEncodingNameLength - 1] == '"') + m_textEncodingName = m_textEncodingName.substring(1, textEncodingNameLength - 2); + m_lastModifiedDate = toTimeT(CFURLResponseGetLastModifiedDate(m_cfResponse.get())); RetainPtr<CFStringRef> suggestedFilename(AdoptCF, CFURLResponseCopySuggestedFilename(m_cfResponse.get())); diff --git a/WebCore/platform/network/cf/SocketStreamError.h b/WebCore/platform/network/cf/SocketStreamError.h index 6a0b441..5a0ca07 100644 --- a/WebCore/platform/network/cf/SocketStreamError.h +++ b/WebCore/platform/network/cf/SocketStreamError.h @@ -42,7 +42,10 @@ public: : SocketStreamErrorBase(errorCode) { } - + SocketStreamError(int errorCode, const String& failingURL, const String& localizedDescription) + : SocketStreamErrorBase(errorCode, failingURL, localizedDescription) + { + } }; } // namespace WebCore diff --git a/WebCore/platform/network/cf/SocketStreamHandle.h b/WebCore/platform/network/cf/SocketStreamHandle.h index 41d543a..df1d4a3 100644 --- a/WebCore/platform/network/cf/SocketStreamHandle.h +++ b/WebCore/platform/network/cf/SocketStreamHandle.h @@ -84,6 +84,10 @@ private: void readStreamCallback(CFStreamEventType); void writeStreamCallback(CFStreamEventType); +#ifndef BUILDING_ON_TIGER + void reportErrorToClient(CFErrorRef); +#endif + // No authentication for streams per se, but proxy may ask for credentials. virtual void receivedCredential(const AuthenticationChallenge&, const Credential&); virtual void receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&); diff --git a/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp b/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp index 24b5835..821b1ca 100644 --- a/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp +++ b/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp @@ -39,6 +39,7 @@ #include "SocketStreamError.h" #include "SocketStreamHandleClient.h" #include <wtf/MainThread.h> +#include <wtf/text/StringConcatenate.h> #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) #include <SystemConfiguration/SystemConfiguration.h> @@ -530,8 +531,13 @@ void SocketStreamHandle::readStreamCallback(CFStreamEventType type) ASSERT_NOT_REACHED(); break; case kCFStreamEventErrorOccurred: { +#ifndef BUILDING_ON_TIGER + RetainPtr<CFErrorRef> error(AdoptCF, CFReadStreamCopyError(m_readStream.get())); + reportErrorToClient(error.get()); +#else CFStreamError error = CFReadStreamGetError(m_readStream.get()); m_client->didFail(this, SocketStreamError(error.error)); // FIXME: Provide a sensible error. +#endif break; } case kCFStreamEventEndEncountered: @@ -574,8 +580,13 @@ void SocketStreamHandle::writeStreamCallback(CFStreamEventType type) break; } case kCFStreamEventErrorOccurred: { +#ifndef BUILDING_ON_TIGER + RetainPtr<CFErrorRef> error(AdoptCF, CFWriteStreamCopyError(m_writeStream.get())); + reportErrorToClient(error.get()); +#else CFStreamError error = CFWriteStreamGetError(m_writeStream.get()); m_client->didFail(this, SocketStreamError(error.error)); // FIXME: Provide a sensible error. +#endif break; } case kCFStreamEventEndEncountered: @@ -584,6 +595,29 @@ void SocketStreamHandle::writeStreamCallback(CFStreamEventType type) } } +#ifndef BUILDING_ON_TIGER +void SocketStreamHandle::reportErrorToClient(CFErrorRef error) +{ + CFIndex errorCode = CFErrorGetCode(error); + String description; + +#if PLATFORM(MAC) + if (CFEqual(CFErrorGetDomain(error), kCFErrorDomainOSStatus)) { + const char* descriptionOSStatus = GetMacOSStatusCommentString(static_cast<OSStatus>(errorCode)); + if (descriptionOSStatus && descriptionOSStatus[0] != '\0') + description = makeString("OSStatus Error ", String::number(errorCode), ": ", descriptionOSStatus); + } +#endif + + if (description.isNull()) { + RetainPtr<CFStringRef> descriptionCF(AdoptCF, CFErrorCopyDescription(error)); + description = String(descriptionCF.get()); + } + + m_client->didFail(this, SocketStreamError(static_cast<int>(errorCode), m_url.string(), description)); +} +#endif // BUILDING_ON_TIGER + SocketStreamHandle::~SocketStreamHandle() { LOG(Network, "SocketStreamHandle %p dtor", this); diff --git a/WebCore/platform/network/mac/AuthenticationChallenge.h b/WebCore/platform/network/mac/AuthenticationChallenge.h index d74a92c..8f60933 100644 --- a/WebCore/platform/network/mac/AuthenticationChallenge.h +++ b/WebCore/platform/network/mac/AuthenticationChallenge.h @@ -49,6 +49,7 @@ public: NSURLAuthenticationChallenge *nsURLAuthenticationChallenge() const { return m_nsChallenge.get(); } void setAuthenticationClient(AuthenticationClient*); // Changes sender to one that invokes client methods. + AuthenticationClient* authenticationClient() const; private: friend class AuthenticationChallengeBase; diff --git a/WebCore/platform/network/mac/AuthenticationMac.mm b/WebCore/platform/network/mac/AuthenticationMac.mm index 1c05917..cdf643f 100644 --- a/WebCore/platform/network/mac/AuthenticationMac.mm +++ b/WebCore/platform/network/mac/AuthenticationMac.mm @@ -41,6 +41,7 @@ using namespace WebCore; AuthenticationClient* m_client; } - (id)initWithAuthenticationClient:(AuthenticationClient*)client; +- (AuthenticationClient*)client; - (void)detachClient; @end @@ -55,6 +56,11 @@ using namespace WebCore; return self; } +- (AuthenticationClient*)client +{ + return m_client; +} + - (void)detachClient { m_client = 0; @@ -123,6 +129,14 @@ void AuthenticationChallenge::setAuthenticationClient(AuthenticationClient* clie } } +AuthenticationClient* AuthenticationChallenge::authenticationClient() const +{ + if ([m_sender.get() isMemberOfClass:[WebCoreAuthenticationClientAsChallengeSender class]]) + return [static_cast<WebCoreAuthenticationClientAsChallengeSender*>(m_sender.get()) client]; + + return 0; +} + bool AuthenticationChallenge::platformCompare(const AuthenticationChallenge& a, const AuthenticationChallenge& b) { if (a.sender() != b.sender()) diff --git a/WebCore/platform/network/mac/ResourceHandleMac.mm b/WebCore/platform/network/mac/ResourceHandleMac.mm index daec366..caa33d7 100644 --- a/WebCore/platform/network/mac/ResourceHandleMac.mm +++ b/WebCore/platform/network/mac/ResourceHandleMac.mm @@ -552,6 +552,8 @@ void ResourceHandle::willSendRequest(ResourceRequest& request, const ResourceRes d->m_pass = url.pass(); d->m_lastHTTPMethod = request.httpMethod(); request.removeCredentials(); + if (!protocolHostAndPortAreEqual(request.url(), redirectResponse.url())) + request.clearHTTPAuthorization(); client()->willSendRequest(this, request, redirectResponse); } diff --git a/WebCore/platform/network/mac/ResourceResponseMac.mm b/WebCore/platform/network/mac/ResourceResponseMac.mm index e1f1790..4376b64 100644 --- a/WebCore/platform/network/mac/ResourceResponseMac.mm +++ b/WebCore/platform/network/mac/ResourceResponseMac.mm @@ -74,6 +74,12 @@ void ResourceResponse::platformLazyInit() m_mimeType = [m_nsResponse.get() MIMEType]; m_expectedContentLength = [m_nsResponse.get() expectedContentLength]; m_textEncodingName = [m_nsResponse.get() textEncodingName]; + + // Workaround for <rdar://problem/8757088>, can be removed once that is fixed. + unsigned textEncodingNameLength = m_textEncodingName.length(); + if (textEncodingNameLength >= 2 && m_textEncodingName[0U] == '"' && m_textEncodingName[textEncodingNameLength - 1] == '"') + m_textEncodingName = m_textEncodingName.substring(1, textEncodingNameLength - 2); + m_suggestedFilename = [m_nsResponse.get() suggestedFilename]; if ([m_nsResponse.get() isKindOfClass:[NSHTTPURLResponse class]]) { diff --git a/WebCore/platform/network/qt/AuthenticationChallenge.h b/WebCore/platform/network/qt/AuthenticationChallenge.h index 753ac6f..ebbc0cd 100644 --- a/WebCore/platform/network/qt/AuthenticationChallenge.h +++ b/WebCore/platform/network/qt/AuthenticationChallenge.h @@ -29,6 +29,8 @@ namespace WebCore { +class AuthenticationClient; + class AuthenticationChallenge : public AuthenticationChallengeBase { public: AuthenticationChallenge() @@ -39,6 +41,9 @@ public: : AuthenticationChallengeBase(protectionSpace, proposedCredential, previousFailureCount, response, error) { } + + AuthenticationClient* authenticationClient() const { return 0; } // FIXME: Implement! + }; } diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp index 01e624e..2ff7d9c 100644 --- a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp +++ b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp @@ -23,6 +23,7 @@ #include "HTTPParsers.h" #include "MIMETypeRegistry.h" +#include "QtNAMThreadSafeProxy.h" #include "ResourceHandle.h" #include "ResourceHandleClient.h" #include "ResourceHandleInternal.h" @@ -46,7 +47,7 @@ // 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 +#define SIGNAL_CONN Qt::AutoConnection #else #define SIGNAL_CONN Qt::QueuedConnection #endif @@ -56,8 +57,9 @@ static const int gMaxRecursionLimit = 10; namespace WebCore { // Take a deep copy of the FormDataElement -FormDataIODevice::FormDataIODevice(FormData* data) - : m_formElements(data ? data->elements() : Vector<FormDataElement>()) +FormDataIODevice::FormDataIODevice(FormData* data, QObject* parent) + : QIODevice(parent) + , m_formElements(data ? data->elements() : Vector<FormDataElement>()) , m_currentFile(0) , m_currentDelta(0) , m_fileSize(0) @@ -184,7 +186,7 @@ QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode load , m_resourceHandle(handle) , m_redirected(false) , m_responseSent(false) - , m_responseDataSent(false) + , m_responseContainsData(false) , m_loadMode(loadMode) , m_shouldStart(true) , m_shouldFinish(false) @@ -192,6 +194,9 @@ QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode load , m_shouldForwardData(false) , m_redirectionTries(gMaxRecursionLimit) { + // Make this a direct function call once we require 4.6.1+. + connect(this, SIGNAL(processQueuedItems()), this, SLOT(sendQueuedItems()), SIGNAL_CONN); + const ResourceRequest &r = m_resourceHandle->firstRequest(); if (r.httpMethod() == "GET") @@ -222,6 +227,12 @@ QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode load start(); } +QNetworkReplyHandler::~QNetworkReplyHandler() +{ + if (m_reply) + m_reply->deleteLater(); +} + void QNetworkReplyHandler::setLoadMode(LoadMode mode) { // https://bugs.webkit.org/show_bug.cgi?id=26556 @@ -231,9 +242,13 @@ void QNetworkReplyHandler::setLoadMode(LoadMode mode) case LoadNormal: m_loadMode = LoadResuming; emit processQueuedItems(); + // Restart forwarding only after processQueuedItems to make sure + // our buffered data was handled before any incoming data. + m_reply->setForwardingDefered(false); break; case LoadDeferred: m_loadMode = LoadDeferred; + m_reply->setForwardingDefered(true); break; case LoadResuming: Q_ASSERT(0); // should never happen @@ -245,31 +260,30 @@ void QNetworkReplyHandler::abort() { m_resourceHandle = 0; if (m_reply) { - QNetworkReply* reply = release(); + QtNetworkReplyThreadSafeProxy* reply = release(); reply->abort(); reply->deleteLater(); } deleteLater(); } -QNetworkReply* QNetworkReplyHandler::release() +QtNetworkReplyThreadSafeProxy* QNetworkReplyHandler::release() { - QNetworkReply* reply = m_reply; + QtNetworkReplyThreadSafeProxy* 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; } return reply; } -static bool ignoreHttpError(QNetworkReply* reply, bool receivedData) +static bool ignoreHttpError(QtNetworkReplyThreadSafeProxy* reply, bool receivedData) { - int httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + int httpStatusCode = reply->httpStatusCode(); if (httpStatusCode == 401 || httpStatusCode == 407) return true; @@ -300,29 +314,33 @@ void QNetworkReplyHandler::finish() return; } - QNetworkReply* oldReply = m_reply; + 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->httpStatusCode(); - if (m_redirected) { - resetState(); - start(); - } else if (!m_reply->error() || ignoreHttpError(m_reply, m_responseDataSent)) { - client->didFinishLoading(m_resourceHandle, 0); + if (httpStatusCode) { + ResourceError error("HTTP", httpStatusCode, url.toString(), QString::fromAscii(m_reply->httpReasonPhrase())); + 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 { - 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; } + resetState(); + start(); } - - oldReply->deleteLater(); - if (oldReply == m_reply) - m_reply = 0; } void QNetworkReplyHandler::sendResponseIfNeeded() @@ -331,7 +349,7 @@ void QNetworkReplyHandler::sendResponseIfNeeded() if (m_shouldSendResponse) return; - if (m_reply->error() && !ignoreHttpError(m_reply, m_responseDataSent)) + if (m_reply->error() && !ignoreHttpError(m_reply, m_responseContainsData)) return; if (m_responseSent || !m_resourceHandle) @@ -342,7 +360,7 @@ void QNetworkReplyHandler::sendResponseIfNeeded() if (!client) return; - WTF::String contentType = m_reply->header(QNetworkRequest::ContentTypeHeader).toString(); + WTF::String contentType = m_reply->contentTypeHeader(); WTF::String encoding = extractCharsetFromMediaType(contentType); WTF::String mimeType = extractMIMETypeFromMediaType(contentType); @@ -353,7 +371,7 @@ void QNetworkReplyHandler::sendResponseIfNeeded() KURL url(m_reply->url()); ResourceResponse response(url, mimeType.lower(), - m_reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), + m_reply->contentLengthHeader(), encoding, String()); if (url.isLocalFile()) { @@ -362,10 +380,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_reply->httpStatusCode(); if (url.protocolInHTTPFamily()) { - String suggestedFilename = filenameFromHTTPContentDisposition(QString::fromAscii(m_reply->rawHeader("Content-Disposition"))); + String suggestedFilename = filenameFromHTTPContentDisposition(QString::fromAscii(m_reply->contentDispositionHeader())); if (!suggestedFilename.isEmpty()) response.setSuggestedFilename(suggestedFilename); @@ -373,21 +391,15 @@ void QNetworkReplyHandler::sendResponseIfNeeded() response.setSuggestedFilename(url.lastPathComponent()); response.setHTTPStatusCode(statusCode); - response.setHTTPStatusText(m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray().constData()); + response.setHTTPStatusText(m_reply->httpReasonPhrase().constData()); // Add remaining headers. -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) - foreach (const QNetworkReply::RawHeaderPair& pair, m_reply->rawHeaderPairs()) { + foreach (const QtNetworkReplyThreadSafeProxy::RawHeaderPair& pair, m_reply->rawHeaderPairs()) { response.setHTTPHeaderField(QString::fromAscii(pair.first), QString::fromAscii(pair.second)); } -#else - foreach (const QByteArray& headerName, m_reply->rawHeaderList()) { - response.setHTTPHeaderField(QString::fromAscii(headerName), QString::fromAscii(m_reply->rawHeader(headerName))); - } -#endif } - QUrl redirection = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); + QUrl redirection = m_reply->redirectionTarget(); if (redirection.isValid()) { QUrl newUrl = m_reply->url().resolved(redirection); @@ -432,11 +444,16 @@ void QNetworkReplyHandler::sendResponseIfNeeded() client->didReceiveResponse(m_resourceHandle, response); } -void QNetworkReplyHandler::forwardData() +void QNetworkReplyHandler::forwardData(const QByteArray &data) { m_shouldForwardData = (m_loadMode != LoadNormal); - if (m_shouldForwardData) + if (m_shouldForwardData) { + m_bufferedData += data; return; + } + + if (!data.isEmpty()) + m_responseContainsData = true; sendResponseIfNeeded(); @@ -447,16 +464,12 @@ void QNetworkReplyHandler::forwardData() if (!m_resourceHandle) return; - QByteArray data = m_reply->read(m_reply->bytesAvailable()); - ResourceHandleClient* client = m_resourceHandle->client(); if (!client) return; - if (!data.isEmpty()) { - m_responseDataSent = true; + if (!data.isEmpty()) client->didReceiveData(m_resourceHandle, data.constData(), data.length(), data.length() /*FixMe*/); - } } void QNetworkReplyHandler::uploadProgress(qint64 bytesSent, qint64 bytesTotal) @@ -493,41 +506,53 @@ void QNetworkReplyHandler::start() && (!url.toLocalFile().isEmpty() || url.scheme() == QLatin1String("data"))) m_method = QNetworkAccessManager::GetOperation; + m_reply = new QtNetworkReplyThreadSafeProxy(manager); + 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(dataReceived(const QByteArray&)), this, SLOT(forwardData(const QByteArray&)), SIGNAL_CONN); + + if (m_resourceHandle->firstRequest().reportUploadProgress()) + connect(m_reply, SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(uploadProgress(qint64, qint64)), SIGNAL_CONN); + switch (m_method) { case QNetworkAccessManager::GetOperation: - m_reply = manager->get(m_request); + m_reply->get(m_request); break; case QNetworkAccessManager::PostOperation: { - FormDataIODevice* postDevice = new FormDataIODevice(d->m_firstRequest.httpBody()); + FormDataIODevice* postDevice = new FormDataIODevice(d->m_firstRequest.httpBody(), this); // 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); + m_reply->post(m_request, postDevice); break; } case QNetworkAccessManager::HeadOperation: - m_reply = manager->head(m_request); + m_reply->head(m_request); break; case QNetworkAccessManager::PutOperation: { - FormDataIODevice* putDevice = new FormDataIODevice(d->m_firstRequest.httpBody()); + FormDataIODevice* putDevice = new FormDataIODevice(d->m_firstRequest.httpBody(), this); // 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); + m_reply->put(m_request, putDevice); break; } case QNetworkAccessManager::DeleteOperation: { - m_reply = manager->deleteResource(m_request); + m_reply->deleteResource(m_request); break; } #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) case QNetworkAccessManager::CustomOperation: - m_reply = manager->sendCustomRequest(m_request, m_resourceHandle->firstRequest().httpMethod().latin1().data()); + m_reply->sendCustomRequest(m_request, m_resourceHandle->firstRequest().httpMethod().latin1().data()); break; #endif case QNetworkAccessManager::UnknownOperation: { + m_reply->deleteLater(); m_reply = 0; ResourceHandleClient* client = m_resourceHandle->client(); if (client) { @@ -539,36 +564,13 @@ void QNetworkReplyHandler::start() return; } } - - m_reply->setParent(this); - - 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); - } - - // Make this a direct function call once we require 4.6.1+. - connect(this, SIGNAL(processQueuedItems()), - this, SLOT(sendQueuedItems()), SIGNAL_CONN); } void QNetworkReplyHandler::resetState() { m_redirected = false; m_responseSent = false; - m_responseDataSent = false; + m_responseContainsData = false; m_shouldStart = true; m_shouldFinish = false; m_shouldSendResponse = false; @@ -587,8 +589,10 @@ void QNetworkReplyHandler::sendQueuedItems() if (m_shouldSendResponse) sendResponseIfNeeded(); - if (m_shouldForwardData) - forwardData(); + if (m_shouldForwardData) { + forwardData(m_bufferedData); + m_bufferedData.clear(); + } if (m_shouldFinish) finish(); diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.h b/WebCore/platform/network/qt/QNetworkReplyHandler.h index 884a1a4..11638b3 100644 --- a/WebCore/platform/network/qt/QNetworkReplyHandler.h +++ b/WebCore/platform/network/qt/QNetworkReplyHandler.h @@ -23,6 +23,7 @@ #include <QNetworkRequest> #include <QNetworkAccessManager> +#include <QNetworkReply> #include "FormData.h" @@ -34,6 +35,7 @@ QT_END_NAMESPACE namespace WebCore { class ResourceHandle; +class QtNetworkReplyThreadSafeProxy; class QNetworkReplyHandler : public QObject { @@ -46,13 +48,12 @@ public: }; QNetworkReplyHandler(ResourceHandle *handle, LoadMode); + ~QNetworkReplyHandler(); void setLoadMode(LoadMode); - QNetworkReply* reply() const { return m_reply; } - void abort(); - QNetworkReply* release(); + QtNetworkReplyThreadSafeProxy* release(); signals: void processQueuedItems(); @@ -60,7 +61,7 @@ signals: private slots: void finish(); void sendResponseIfNeeded(); - void forwardData(); + void forwardData(const QByteArray &data); void sendQueuedItems(); void uploadProgress(qint64 bytesSent, qint64 bytesTotal); @@ -69,11 +70,11 @@ private: void resetState(); String httpMethod() const; - QNetworkReply* m_reply; + QtNetworkReplyThreadSafeProxy* m_reply; ResourceHandle* m_resourceHandle; bool m_redirected; bool m_responseSent; - bool m_responseDataSent; + bool m_responseContainsData; LoadMode m_loadMode; QNetworkAccessManager::Operation m_method; QNetworkRequest m_request; @@ -84,6 +85,7 @@ private: bool m_shouldSendResponse; bool m_shouldForwardData; int m_redirectionTries; + QByteArray m_bufferedData; }; // Self destructing QIODevice for FormData @@ -94,7 +96,7 @@ private: class FormDataIODevice : public QIODevice { Q_OBJECT public: - FormDataIODevice(FormData*); + FormDataIODevice(FormData*, QObject* parent = 0); ~FormDataIODevice(); bool isSequential() const; diff --git a/WebCore/platform/network/qt/QtNAMThreadSafeProxy.cpp b/WebCore/platform/network/qt/QtNAMThreadSafeProxy.cpp new file mode 100644 index 0000000..0caeb05 --- /dev/null +++ b/WebCore/platform/network/qt/QtNAMThreadSafeProxy.cpp @@ -0,0 +1,190 @@ +/* + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#include "config.h" +#include "QtNAMThreadSafeProxy.h" + +#include "Assertions.h" +#include <QAbstractNetworkCache> +#include <QNetworkAccessManager> +#include <QNetworkCookieJar> +#include <QStringList> + +// Use unused variables to be able to call qRegisterMetaType statically. +static int dummyStaticVar1 = qRegisterMetaType<QFutureInterface<bool> >("QFutureInterface<bool>"); +static int dummyStaticVar2 = qRegisterMetaType<QFutureInterface<QList<QNetworkCookie> > >("QFutureInterface<QList<QNetworkCookie> >"); + +namespace WebCore { + +QtNAMThreadSafeProxy::QtNAMThreadSafeProxy(QNetworkAccessManager *manager) + : m_manager(manager) +{ + moveToThread(manager->thread()); + + connect(this, SIGNAL(localSetCookiesRequested(const QUrl&, const QString&)), SLOT(localSetCookies(const QUrl&, const QString&))); + connect(this, SIGNAL(localCookiesForUrlRequested(QFutureInterface<QList<QNetworkCookie> >, const QUrl&)), SLOT(localCookiesForUrl(QFutureInterface<QList<QNetworkCookie> >, const QUrl&))); + connect(this, SIGNAL(localWillLoadFromCacheRequested(QFutureInterface<bool>, const QUrl&)), SLOT(localWillLoadFromCache(QFutureInterface<bool>, const QUrl&))); +} + +void QtNAMThreadSafeProxy::localSetCookies(const QUrl& url, const QString& cookies) +{ + QList<QNetworkCookie> cookieList = QNetworkCookie::parseCookies(cookies.toAscii()); + QList<QNetworkCookie>::Iterator it = cookieList.begin(); + while (it != cookieList.end()) { + if (it->isHttpOnly()) + it = cookieList.erase(it); + else + ++it; + } + m_manager->cookieJar()->setCookiesFromUrl(cookieList, url); +} + +void QtNAMThreadSafeProxy::localCookiesForUrl(QFutureInterface<QList<QNetworkCookie> > fi, const QUrl& url) +{ + fi.reportResult(m_manager->cookieJar()->cookiesForUrl(url)); + fi.reportFinished(); +} + +void QtNAMThreadSafeProxy::localWillLoadFromCache(QFutureInterface<bool> fi, const QUrl& url) +{ + bool retVal = false; + if (m_manager->cache()) + retVal = m_manager->cache()->metaData(url).isValid(); + + fi.reportFinished(&retVal); +} + +QtNetworkReplyThreadSafeProxy::QtNetworkReplyThreadSafeProxy(QNetworkAccessManager *manager) + : m_manager(manager) + , m_reply(0) + , m_forwardingDefered(false) + , m_contentLengthHeader(0) + , m_error(QNetworkReply::NoError) + , m_httpStatusCode(0) +{ + moveToThread(manager->thread()); + + // This might be unnecessarily heavy to do for each request while we could have the same wrapper for the manager instead + connect(this, SIGNAL(localGetRequested(const QNetworkRequest&)), SLOT(localGet(const QNetworkRequest&))); + connect(this, SIGNAL(localPostRequested(const QNetworkRequest&, QIODevice*)), SLOT(localPost(const QNetworkRequest&, QIODevice*))); + connect(this, SIGNAL(localHeadRequested(const QNetworkRequest&)), SLOT(localHead(const QNetworkRequest&))); + connect(this, SIGNAL(localPutRequested(const QNetworkRequest&, QIODevice*)), SLOT(localPut(const QNetworkRequest&, QIODevice*))); + connect(this, SIGNAL(localDeleteResourceRequested(const QNetworkRequest&)), SLOT(localDeleteResource(const QNetworkRequest&))); + connect(this, SIGNAL(localCustomRequestRequested(const QNetworkRequest&, const QByteArray&)), SLOT(localCustomRequest(const QNetworkRequest&, const QByteArray&))); + connect(this, SIGNAL(localAbortRequested()), SLOT(localAbort())); + connect(this, SIGNAL(localSetForwardingDeferedRequested(bool)), SLOT(localSetForwardingDefered(bool))); +} + +QtNetworkReplyThreadSafeProxy::~QtNetworkReplyThreadSafeProxy() +{ + delete m_reply; +} + +void QtNetworkReplyThreadSafeProxy::localGet(const QNetworkRequest& request) +{ + localSetReply(m_manager->get(request)); +} + +void QtNetworkReplyThreadSafeProxy::localPost(const QNetworkRequest& request, QIODevice* data) +{ + localSetReply(m_manager->post(request, data)); +} + +void QtNetworkReplyThreadSafeProxy::localHead(const QNetworkRequest& request) +{ + localSetReply(m_manager->head(request)); +} + +void QtNetworkReplyThreadSafeProxy::localPut(const QNetworkRequest& request, QIODevice* data) +{ + localSetReply(m_manager->put(request, data)); +} + +void QtNetworkReplyThreadSafeProxy::localDeleteResource(const QNetworkRequest& request) +{ + localSetReply(m_manager->deleteResource(request)); +} + +void QtNetworkReplyThreadSafeProxy::localCustomRequest(const QNetworkRequest& request, const QByteArray& verb) +{ +#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) + localSetReply(m_manager->sendCustomRequest(request, verb)); +#endif +} + +void QtNetworkReplyThreadSafeProxy::localAbort() +{ + if (m_reply) + m_reply->abort(); +} + +void QtNetworkReplyThreadSafeProxy::localForwardData() +{ + if (m_reply->bytesAvailable()) { + QByteArray data = m_reply->read(m_reply->bytesAvailable()); + emit dataReceived(data); + } +} + +void QtNetworkReplyThreadSafeProxy::localSetForwardingDefered(bool forwardingDefered) +{ + if (m_forwardingDefered && !forwardingDefered) + localForwardData(); + m_forwardingDefered = forwardingDefered; +} + +void QtNetworkReplyThreadSafeProxy::localMirrorMembers() +{ + ASSERT(m_reply); + QMutexLocker lock(&m_mirroredMembersMutex); + + m_contentDispositionHeader = m_reply->rawHeader("Content-Disposition"); + m_contentLengthHeader = m_reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(); + m_contentTypeHeader = m_reply->header(QNetworkRequest::ContentTypeHeader).toString(); + m_error = m_reply->error(); + m_errorString = m_reply->errorString(); + m_httpReasonPhrase = m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray(); + m_httpStatusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + m_url = m_reply->url(); + m_redirectionTarget = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); +#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) + m_rawHeaderPairs = m_reply->rawHeaderPairs(); +#else + m_rawHeaderPairs.clear(); + foreach (const QByteArray& headerName, m_reply->rawHeaderList()) + m_rawHeaderPairs.append(RawHeaderPair(headerName, m_reply->rawHeader(headerName))); +#endif +} + +void QtNetworkReplyThreadSafeProxy::localSetReply(QNetworkReply *reply) +{ + ASSERT(!m_reply); + m_reply = reply; + m_reply->setParent(0); + connect(m_reply, SIGNAL(readyRead()), this, SLOT(localForwardData())); + // Make sure localMirrorMembers() is called before the outward signal + connect(m_reply, SIGNAL(finished()), this, SLOT(localMirrorMembers()), Qt::DirectConnection); + connect(m_reply, SIGNAL(finished()), this, SIGNAL(finished())); + // Make sure localMirrorMembers() is called before the outward signal + connect(m_reply, SIGNAL(metaDataChanged()), this, SLOT(localMirrorMembers()), Qt::DirectConnection); + connect(m_reply, SIGNAL(metaDataChanged()), this, SIGNAL(metaDataChanged())); + connect(m_reply, SIGNAL(uploadProgress(qint64, qint64)), this, SIGNAL(uploadProgress(qint64, qint64))); +} + + +} diff --git a/WebCore/platform/network/qt/QtNAMThreadSafeProxy.h b/WebCore/platform/network/qt/QtNAMThreadSafeProxy.h new file mode 100644 index 0000000..3e0c189 --- /dev/null +++ b/WebCore/platform/network/qt/QtNAMThreadSafeProxy.h @@ -0,0 +1,186 @@ +/* + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef QtNAMThreadSafeProxy_h +#define QtNAMThreadSafeProxy_h + +#include <QFuture> +#include <QMutex> +#include <QNetworkCookie> +#include <QNetworkReply> +#include <QObject> + +class QNetworkAccessManager; +class QNetworkRequest; +class QUrl; + +namespace WebCore { + +class QtNAMThreadSafeProxy : public QObject { + Q_OBJECT +public: + QtNAMThreadSafeProxy(QNetworkAccessManager *manager); + + void setCookies(const QUrl& url, const QString& cookies) + { + emit localSetCookiesRequested(url, cookies); + } + + QFuture<QList<QNetworkCookie> > cookiesForUrl(const QUrl& url) + { + QFutureInterface<QList<QNetworkCookie> > fi; + fi.reportStarted(); + emit localCookiesForUrlRequested(fi, url); + return fi.future(); + } + + QFuture<bool> willLoadFromCache(const QUrl& url) + { + QFutureInterface<bool> fi; + fi.reportStarted(); + emit localWillLoadFromCacheRequested(fi, url); + return fi.future(); + } + +signals: + void localSetCookiesRequested(const QUrl& url, const QString& cookies); + void localCookiesForUrlRequested(QFutureInterface<QList<QNetworkCookie> > fi, const QUrl& url); + void localWillLoadFromCacheRequested(QFutureInterface<bool> fi, const QUrl& url); + +private slots: + void localSetCookies(const QUrl& url, const QString& cookies); + void localCookiesForUrl(QFutureInterface<QList<QNetworkCookie> > fi, const QUrl& url); + void localWillLoadFromCache(QFutureInterface<bool> fi, const QUrl& url); + +private: + QNetworkAccessManager* m_manager; +}; + + +class QtNetworkReplyThreadSafeProxy : public QObject { + Q_OBJECT +public: + typedef QPair<QByteArray, QByteArray> RawHeaderPair; + QtNetworkReplyThreadSafeProxy(QNetworkAccessManager *manager); + ~QtNetworkReplyThreadSafeProxy(); + void abort() + { + emit localAbortRequested(); + } + void setForwardingDefered(bool forwardingDefered) + { + emit localSetForwardingDeferedRequested(forwardingDefered); + } + + QByteArray contentDispositionHeader() { QMutexLocker lock(&m_mirroredMembersMutex); return m_contentDispositionHeader; } + qlonglong contentLengthHeader() { QMutexLocker lock(&m_mirroredMembersMutex); return m_contentLengthHeader; } + QString contentTypeHeader() { QMutexLocker lock(&m_mirroredMembersMutex); return m_contentTypeHeader; } + QNetworkReply::NetworkError error() { QMutexLocker lock(&m_mirroredMembersMutex); return m_error; } + QString errorString() { QMutexLocker lock(&m_mirroredMembersMutex); return m_errorString; } + QByteArray httpReasonPhrase() { QMutexLocker lock(&m_mirroredMembersMutex); return m_httpReasonPhrase; } + int httpStatusCode() { QMutexLocker lock(&m_mirroredMembersMutex); return m_httpStatusCode; } + QUrl url() { QMutexLocker lock(&m_mirroredMembersMutex); return m_url; } + QUrl redirectionTarget() { QMutexLocker lock(&m_mirroredMembersMutex); return m_redirectionTarget; } + QList<RawHeaderPair> rawHeaderPairs() { QMutexLocker lock(&m_mirroredMembersMutex); return m_rawHeaderPairs; } + + QNetworkReply* reply() + { + // Careful, acccessing the reply accross threads might be hazardous to your health + return m_reply; + } +public: + void get(const QNetworkRequest &request) + { + emit localGetRequested(request); + } + void post(const QNetworkRequest &request, QIODevice* data) + { + emit localPostRequested(request, data); + } + void head(const QNetworkRequest &request) + { + emit localHeadRequested(request); + } + void put(const QNetworkRequest &request, QIODevice* data) + { + emit localPutRequested(request, data); + } + void deleteResource(const QNetworkRequest &request) + { + emit localDeleteResourceRequested(request); + } +#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) + void sendCustomRequest(const QNetworkRequest &request, const QByteArray& verb) + { + emit localCustomRequestRequested(request, verb); + } +#endif + +signals: + void localGetRequested(const QNetworkRequest& request); + void localPostRequested(const QNetworkRequest& request, QIODevice* data); + void localHeadRequested(const QNetworkRequest& request); + void localPutRequested(const QNetworkRequest& request, QIODevice* data); + void localDeleteResourceRequested(const QNetworkRequest& request); + void localCustomRequestRequested(const QNetworkRequest& request, const QByteArray& verb); + void localAbortRequested(); + void localSetForwardingDeferedRequested(bool forwardingDefered); + + void finished(); + void readyRead(); + void metaDataChanged(); + void uploadProgress(qint64 bytesSent, qint64 bytesTotal); + void dataReceived(const QByteArray &data); + +private slots: + void localGet(const QNetworkRequest& request); + void localPost(const QNetworkRequest& request, QIODevice* data); + void localHead(const QNetworkRequest& request); + void localPut(const QNetworkRequest& request, QIODevice* data); + void localDeleteResource(const QNetworkRequest& request); + void localCustomRequest(const QNetworkRequest& request, const QByteArray& verb); + void localAbort(); + void localForwardData(); + void localSetForwardingDefered(bool forwardingDefered); + void localMirrorMembers(); + +private: + void localSetReply(QNetworkReply *reply); + + QNetworkAccessManager *m_manager; + QNetworkReply *m_reply; + bool m_forwardingDefered; + + // Mirrored members + QMutex m_mirroredMembersMutex; + QByteArray m_contentDispositionHeader; + qlonglong m_contentLengthHeader; + QString m_contentTypeHeader; + QNetworkReply::NetworkError m_error; + QString m_errorString; + QByteArray m_httpReasonPhrase; + int m_httpStatusCode; + QUrl m_url; + QUrl m_redirectionTarget; + QList<RawHeaderPair> m_rawHeaderPairs; +}; + +} + + +#endif // QtNAMThreadSafeProxy_h diff --git a/WebCore/platform/network/qt/ResourceHandleQt.cpp b/WebCore/platform/network/qt/ResourceHandleQt.cpp index a5ac4c3..f40b828 100644 --- a/WebCore/platform/network/qt/ResourceHandleQt.cpp +++ b/WebCore/platform/network/qt/ResourceHandleQt.cpp @@ -35,6 +35,7 @@ #include "Frame.h" #include "FrameNetworkingContext.h" #include "FrameLoaderClientQt.h" +#include "QtNAMThreadSafeProxy.h" #include "NotImplemented.h" #include "Page.h" #include "QNetworkReplyHandler.h" @@ -156,20 +157,13 @@ bool ResourceHandle::willLoadFromCache(ResourceRequest& request, Frame* frame) if (!frame) return false; - QNetworkAccessManager* manager = 0; - QAbstractNetworkCache* cache = 0; if (frame->loader()->networkingContext()) { - manager = frame->loader()->networkingContext()->networkAccessManager(); - cache = manager->cache(); - } - - if (!cache) - return false; - - QNetworkCacheMetaData data = cache->metaData(request.url()); - if (data.isValid()) { - request.setCachePolicy(ReturnCacheDataDontLoad); - return true; + QNetworkAccessManager* manager = frame->loader()->networkingContext()->networkAccessManager(); + QtNAMThreadSafeProxy managerProxy(manager); + if (managerProxy.willLoadFromCache(request.url())) { + request.setCachePolicy(ReturnCacheDataDontLoad); + return true; + } } return false; diff --git a/WebCore/platform/network/soup/ResourceHandleSoup.cpp b/WebCore/platform/network/soup/ResourceHandleSoup.cpp index c1933e3..a2440d3 100644 --- a/WebCore/platform/network/soup/ResourceHandleSoup.cpp +++ b/WebCore/platform/network/soup/ResourceHandleSoup.cpp @@ -492,7 +492,7 @@ static void sendRequestCallback(GObject* source, GAsyncResult* res, gpointer use if (isTransportError || (error->domain == G_IO_ERROR)) { SoupURI* uri = webkit_soup_request_get_uri(d->m_soupRequest.get()); GOwnPtr<char> uriStr(soup_uri_to_string(uri, false)); - gint errorCode = isTransportError ? soupMsg->status_code : error->code; + gint errorCode = isTransportError ? static_cast<gint>(soupMsg->status_code) : error->code; const gchar* errorMsg = isTransportError ? soupMsg->reason_phrase : error->message; const gchar* quarkStr = isTransportError ? g_quark_to_string(SOUP_HTTP_ERROR) : g_quark_to_string(G_IO_ERROR); ResourceError resourceError(quarkStr, errorCode, uriStr.get(), String::fromUTF8(errorMsg)); @@ -508,8 +508,11 @@ static void sendRequestCallback(GObject* source, GAsyncResult* res, gpointer use fillResponseFromMessage(soupMsg, &d->m_response); client->didReceiveResponse(handle.get(), d->m_response); - // WebCore might have cancelled the job in the while - if (!d->m_cancelled && soupMsg->response_body->data) + // WebCore might have cancelled the job in the while. We + // must check for response_body->length and not + // response_body->data as libsoup always creates the + // SoupBuffer for the body even if the length is 0 + if (!d->m_cancelled && soupMsg->response_body->length) client->didReceiveData(handle.get(), soupMsg->response_body->data, soupMsg->response_body->length, true); } @@ -550,6 +553,9 @@ static void sendRequestCallback(GObject* source, GAsyncResult* res, gpointer use } } + if (d->m_defersLoading) + soup_session_pause_message(handle->defaultSession(), d->m_soupMessage.get()); + g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, READ_BUFFER_SIZE, G_PRIORITY_DEFAULT, d->m_cancellable.get(), readCallback, 0); } @@ -660,8 +666,11 @@ static bool startHttp(ResourceHandle* handle) if (!soup_message_headers_get_one(soupMessage->request_headers, "Accept")) soup_message_headers_append(soupMessage->request_headers, "Accept", "*/*"); - d->m_cancellable = adoptPlatformRef(g_cancellable_new()); - webkit_soup_request_send_async(d->m_soupRequest.get(), d->m_cancellable.get(), sendRequestCallback, 0); + // Send the request only if it's not been explicitely deferred. + if (!d->m_defersLoading) { + d->m_cancellable = adoptPlatformRef(g_cancellable_new()); + webkit_soup_request_send_async(d->m_soupRequest.get(), d->m_cancellable.get(), sendRequestCallback, 0); + } return true; } @@ -734,9 +743,28 @@ bool ResourceHandle::supportsBufferedData() return false; } -void ResourceHandle::platformSetDefersLoading(bool) +void ResourceHandle::platformSetDefersLoading(bool defersLoading) { - notImplemented(); + // Initial implementation of this method was required for bug #44157. + + if (d->m_cancelled) + return; + + if (!defersLoading && !d->m_cancellable && d->m_soupRequest.get()) { + d->m_cancellable = adoptPlatformRef(g_cancellable_new()); + webkit_soup_request_send_async(d->m_soupRequest.get(), d->m_cancellable.get(), sendRequestCallback, 0); + return; + } + + // Only supported for http(s) transfers. Something similar would + // probably be needed for data transfers done with GIO. + if (!d->m_soupMessage) + return; + + if (defersLoading) + soup_session_pause_message(defaultSession(), d->m_soupMessage.get()); + else + soup_session_unpause_message(defaultSession(), d->m_soupMessage.get()); } bool ResourceHandle::loadsBlocked() @@ -758,7 +786,7 @@ void ResourceHandle::loadResourceSynchronously(NetworkingContext* context, const // FIXME: we should use the ResourceHandle::create method here, // but it makes us timeout in a couple of tests. See // https://bugs.webkit.org/show_bug.cgi?id=41823 - RefPtr<ResourceHandle> handle = adoptRef(new ResourceHandle(request, &syncLoader, true, false)); + RefPtr<ResourceHandle> handle = adoptRef(new ResourceHandle(request, &syncLoader, false /*defersLoading*/, false /*shouldContentSniff*/)); handle->start(context); syncLoader.run(); diff --git a/WebCore/platform/network/soup/cache/soup-http-input-stream.c b/WebCore/platform/network/soup/cache/soup-http-input-stream.c index dc95d6e..195c458 100644 --- a/WebCore/platform/network/soup/cache/soup-http-input-stream.c +++ b/WebCore/platform/network/soup/cache/soup-http-input-stream.c @@ -598,6 +598,7 @@ send_async_finished (GInputStream *stream) g_error_free (error); } g_simple_async_result_complete (result); + g_object_unref (result); } static void diff --git a/WebCore/platform/network/soup/cache/soup-request-http.c b/WebCore/platform/network/soup/cache/soup-request-http.c index f3fe2ec..777fd72 100644 --- a/WebCore/platform/network/soup/cache/soup-request-http.c +++ b/WebCore/platform/network/soup/cache/soup-request-http.c @@ -188,6 +188,7 @@ typedef struct { WebKitSoupRequestHTTP *http; GAsyncReadyCallback callback; gpointer user_data; + WebKitSoupHTTPInputStream *httpstream; } SendAsyncHelper; static void webkit_soup_request_http_send_async (WebKitSoupRequest *request, @@ -199,45 +200,34 @@ static gboolean send_async_cb (gpointer data) { GSimpleAsyncResult *simple; - WebKitSoupHTTPInputStream *httpstream; - SoupSession *session; - WebKitSoupCache *cache; SendAsyncHelper *helper = (SendAsyncHelper *)data; + const gchar *content_type; - session = webkit_soup_request_get_session (WEBKIT_SOUP_REQUEST (helper->http)); - cache = (WebKitSoupCache *)soup_session_get_feature (session, WEBKIT_TYPE_SOUP_CACHE); - - httpstream = (WebKitSoupHTTPInputStream *)webkit_soup_cache_send_response (cache, SOUP_MESSAGE (helper->http->priv->msg)); - - if (httpstream) { - const gchar *content_type; - - simple = g_simple_async_result_new (G_OBJECT (helper->http), - helper->callback, helper->user_data, - webkit_soup_request_http_send_async); - g_simple_async_result_set_op_res_gpointer (simple, httpstream, g_object_unref); + simple = g_simple_async_result_new (G_OBJECT (helper->http), + helper->callback, helper->user_data, + webkit_soup_request_http_send_async); + g_simple_async_result_set_op_res_gpointer (simple, helper->httpstream, g_object_unref); - /* Update message status */ - soup_message_set_status (helper->http->priv->msg, SOUP_STATUS_OK); + /* Update message status */ + soup_message_set_status (helper->http->priv->msg, SOUP_STATUS_OK); - /* Issue signals */ - soup_message_got_headers (helper->http->priv->msg); + /* Issue signals */ + soup_message_got_headers (helper->http->priv->msg); - /* FIXME: Uncomment this when this becomes part of libsoup - * if (!soup_message_disables_feature(helper->http->priv->msg, SOUP_TYPE_CONTENT_SNIFFER)) { - * const gchar *content_type = soup_message_headers_get_content_type (helper->http->priv->msg->response_headers, NULL); - * soup_message_content_sniffed (helper->http->priv->msg, content_type, NULL); - * } - */ - content_type = soup_message_headers_get_content_type (helper->http->priv->msg->response_headers, NULL); - soup_message_content_sniffed (helper->http->priv->msg, content_type, NULL); + /* FIXME: Uncomment this when this becomes part of libsoup + * if (!soup_message_disables_feature(helper->http->priv->msg, SOUP_TYPE_CONTENT_SNIFFER)) { + * const gchar *content_type = soup_message_headers_get_content_type (helper->http->priv->msg->response_headers, NULL); + * soup_message_content_sniffed (helper->http->priv->msg, content_type, NULL); + * } + */ + content_type = soup_message_headers_get_content_type (helper->http->priv->msg->response_headers, NULL); + soup_message_content_sniffed (helper->http->priv->msg, content_type, NULL); - g_simple_async_result_complete (simple); + g_simple_async_result_complete (simple); - soup_message_finished (helper->http->priv->msg); + soup_message_finished (helper->http->priv->msg); - g_object_unref (simple); - } + g_object_unref (simple); g_object_unref (helper->http); g_slice_free (SendAsyncHelper, helper); @@ -265,17 +255,28 @@ webkit_soup_request_http_send_async (WebKitSoupRequest *request, response = webkit_soup_cache_has_response (cache, http->priv->msg); if (response == WEBKIT_SOUP_CACHE_RESPONSE_FRESH) { - /* Do return the stream asynchronously as in - the other cases. It's not enough to use - g_simple_async_result_complete_in_idle as - the signals must be also emitted - asynchronously */ - SendAsyncHelper *helper = g_slice_new (SendAsyncHelper); - helper->http = g_object_ref (http); - helper->callback = callback; - helper->user_data = user_data; - g_timeout_add (0, send_async_cb, helper); - return; + WebKitSoupHTTPInputStream *httpstream; + + httpstream = (WebKitSoupHTTPInputStream *) + webkit_soup_cache_send_response (cache, SOUP_MESSAGE (http->priv->msg)); + + /* Cached resource file could have been deleted outside + */ + if (httpstream) { + /* Do return the stream asynchronously as in + * the other cases. It's not enough to use + * g_simple_async_result_complete_in_idle as + * the signals must be also emitted + * asynchronously + */ + SendAsyncHelper *helper = g_slice_new (SendAsyncHelper); + helper->http = g_object_ref (http); + helper->callback = callback; + helper->user_data = user_data; + helper->httpstream = httpstream; + g_timeout_add (0, send_async_cb, helper); + return; + } } else if (response == WEBKIT_SOUP_CACHE_RESPONSE_NEEDS_VALIDATION) { SoupMessage *conditional_msg; ConditionalHelper *helper; diff --git a/WebCore/platform/network/soup/cache/webkit/soup-cache.c b/WebCore/platform/network/soup/cache/webkit/soup-cache.c index 4835750..b96428d 100644 --- a/WebCore/platform/network/soup/cache/webkit/soup-cache.c +++ b/WebCore/platform/network/soup/cache/webkit/soup-cache.c @@ -147,6 +147,8 @@ get_cacheability (WebKitSoupCache *cache, SoupMessage *msg) soup_header_free_param_list (hash); return WEBKIT_SOUP_CACHE_UNCACHEABLE; } + + soup_header_free_param_list (hash); } switch (msg->status_code) { @@ -284,14 +286,12 @@ webkit_soup_cache_entry_set_freshness (WebKitSoupCacheEntry *entry, SoupMessage { const char *cache_control; const char *expires, *date, *last_modified; - GHashTable *hash; - - hash = NULL; cache_control = soup_message_headers_get (entry->headers, "Cache-Control"); if (cache_control) { const char *max_age, *s_maxage; gint64 freshness_lifetime = 0; + GHashTable *hash; WebKitSoupCachePrivate *priv = WEBKIT_SOUP_CACHE_GET_PRIVATE (cache); hash = soup_header_parse_param_list (cache_control); @@ -323,10 +323,9 @@ webkit_soup_cache_entry_set_freshness (WebKitSoupCacheEntry *entry, SoupMessage soup_header_free_param_list (hash); return; } - } - if (hash != NULL) soup_header_free_param_list (hash); + } /* If the 'Expires' response header is present, use its value * minus the value of the 'Date' response header @@ -998,6 +997,7 @@ webkit_soup_cache_send_response (WebKitSoupCache *cache, SoupMessage *msg) key = soup_message_get_cache_key (msg); entry = g_hash_table_lookup (cache->priv->cache, key); + g_free (key); g_return_val_if_fail (entry, NULL); /* If we are told to send a response from cache any validation @@ -1084,11 +1084,12 @@ webkit_soup_cache_init (WebKitSoupCache *cache) } static void -remove_cache_item (gpointer key, - gpointer value, - WebKitSoupCache *cache) +remove_cache_item (gpointer data, + gpointer user_data) { - WebKitSoupCacheEntry *entry = g_hash_table_lookup (cache->priv->cache, (const gchar *)key); + WebKitSoupCache *cache = (WebKitSoupCache *) user_data; + WebKitSoupCacheEntry *entry = (WebKitSoupCacheEntry *) data; + if (webkit_soup_cache_entry_remove (cache, entry)) webkit_soup_cache_entry_free (entry, FALSE); } @@ -1097,10 +1098,15 @@ static void webkit_soup_cache_finalize (GObject *object) { WebKitSoupCachePrivate *priv; + GList *entries; priv = WEBKIT_SOUP_CACHE (object)->priv; - g_hash_table_foreach (priv->cache, (GHFunc)remove_cache_item, object); + // Cannot use g_hash_table_foreach as callbacks must not modify the hash table + entries = g_hash_table_get_values (priv->cache); + g_list_foreach (entries, remove_cache_item, object); + g_list_free (entries); + g_hash_table_destroy (priv->cache); g_free (priv->cache_dir); @@ -1257,7 +1263,6 @@ webkit_soup_cache_has_response (WebKitSoupCache *cache, SoupMessage *msg) char *key; WebKitSoupCacheEntry *entry; const char *cache_control; - GHashTable *hash; gpointer value; gboolean must_revalidate; int max_age, max_stale, min_fresh; @@ -1265,6 +1270,7 @@ webkit_soup_cache_has_response (WebKitSoupCache *cache, SoupMessage *msg) key = soup_message_get_cache_key (msg); entry = g_hash_table_lookup (cache->priv->cache, key); + g_free (key); /* 1. The presented Request-URI and that of stored response * match @@ -1321,10 +1327,10 @@ webkit_soup_cache_has_response (WebKitSoupCache *cache, SoupMessage *msg) cache_control = soup_message_headers_get (msg->request_headers, "Cache-Control"); if (cache_control) { - hash = soup_header_parse_param_list (cache_control); + GHashTable *hash = soup_header_parse_param_list (cache_control); if (g_hash_table_lookup_extended (hash, "no-store", NULL, NULL)) { - g_hash_table_destroy (hash); + soup_header_free_param_list (hash); return WEBKIT_SOUP_CACHE_RESPONSE_STALE; } @@ -1348,7 +1354,7 @@ webkit_soup_cache_has_response (WebKitSoupCache *cache, SoupMessage *msg) if (value) min_fresh = (int)MIN (g_ascii_strtoll (value, NULL, 10), G_MAXINT32); - g_hash_table_destroy (hash); + soup_header_free_param_list (hash); if (max_age != -1) { guint current_age = webkit_soup_cache_entry_get_current_age (entry); @@ -1449,11 +1455,12 @@ webkit_soup_cache_flush (WebKitSoupCache *cache) } static void -clear_cache_item (gpointer key, - gpointer value, - WebKitSoupCache *cache) +clear_cache_item (gpointer data, + gpointer user_data) { - WebKitSoupCacheEntry *entry = g_hash_table_lookup (cache->priv->cache, (const gchar *)key); + WebKitSoupCache *cache = (WebKitSoupCache *) user_data; + WebKitSoupCacheEntry *entry = (WebKitSoupCacheEntry *) data; + if (webkit_soup_cache_entry_remove (cache, entry)) webkit_soup_cache_entry_free (entry, TRUE); } @@ -1469,13 +1476,17 @@ void webkit_soup_cache_clear (WebKitSoupCache *cache) { GHashTable *hash; + GList *entries; g_return_if_fail (WEBKIT_IS_SOUP_CACHE (cache)); hash = cache->priv->cache; g_return_if_fail (hash); - g_hash_table_foreach (hash, (GHFunc)clear_cache_item, cache); + // Cannot use g_hash_table_foreach as callbacks must not modify the hash table + entries = g_hash_table_get_values (hash); + g_list_foreach (entries, clear_cache_item, cache); + g_list_free (entries); } SoupMessage * @@ -1604,12 +1615,13 @@ webkit_soup_cache_load (WebKitSoupCache *cache) filename = g_build_filename (priv->cache_dir, WEBKIT_SOUP_CACHE_FILE, NULL); if (!g_file_get_contents (filename, &contents, &length, NULL)) { g_free (filename); + g_free (contents); return; } g_free (filename); variant_format = g_variant_type_new (WEBKIT_SOUP_CACHE_ENTRIES_FORMAT); - cache_variant = g_variant_new_from_data (variant_format, (const gchar *)contents, length, FALSE, NULL, NULL); + cache_variant = g_variant_new_from_data (variant_format, (const gchar *)contents, length, FALSE, g_free, contents); g_variant_type_free (variant_format); g_variant_get (cache_variant, WEBKIT_SOUP_CACHE_ENTRIES_FORMAT, &entries_iter); diff --git a/WebCore/platform/qt/ClipboardQt.cpp b/WebCore/platform/qt/ClipboardQt.cpp index 20cf62b..c14d362 100644 --- a/WebCore/platform/qt/ClipboardQt.cpp +++ b/WebCore/platform/qt/ClipboardQt.cpp @@ -2,6 +2,7 @@ * Copyright (C) 2007 Apple Inc. All rights reserved. * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2010 Sencha, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -204,8 +205,20 @@ HashSet<String> ClipboardQt::types() const PassRefPtr<FileList> ClipboardQt::files() const { - notImplemented(); - return 0; + if (policy() != ClipboardReadable || !m_readableData->hasUrls()) + return FileList::create(); + + RefPtr<FileList> fileList = FileList::create(); + QList<QUrl> urls = m_readableData->urls(); + + for (int i = 0; i < urls.size(); i++) { + QUrl url = urls[i]; + if (url.scheme() != QLatin1String("file")) + continue; + fileList->append(File::create(url.toLocalFile())); + } + + return fileList.release(); } void ClipboardQt::setDragImage(CachedImage* image, const IntPoint& point) diff --git a/WebCore/platform/qt/ContextMenuQt.cpp b/WebCore/platform/qt/ContextMenuQt.cpp index e3715c9..c877642 100644 --- a/WebCore/platform/qt/ContextMenuQt.cpp +++ b/WebCore/platform/qt/ContextMenuQt.cpp @@ -35,8 +35,7 @@ namespace WebCore { -ContextMenu::ContextMenu(const HitTestResult& result) - : m_hitTestResult(result) +ContextMenu::ContextMenu() { } diff --git a/WebCore/platform/qt/CookieJarQt.cpp b/WebCore/platform/qt/CookieJarQt.cpp index 049ee0f..e5d36ba 100644 --- a/WebCore/platform/qt/CookieJarQt.cpp +++ b/WebCore/platform/qt/CookieJarQt.cpp @@ -31,6 +31,7 @@ #include "Cookie.h" #include "Document.h" #include "KURL.h" +#include "QtNAMThreadSafeProxy.h" #include "NetworkingContext.h" #include "PlatformString.h" @@ -43,7 +44,8 @@ namespace WebCore { -static QNetworkCookieJar *cookieJar(const Document *document) + +static QNetworkAccessManager *networkAccessManager(const Document *document) { if (!document) return 0; @@ -53,38 +55,30 @@ static QNetworkCookieJar *cookieJar(const Document *document) FrameLoader *loader = frame->loader(); if (!loader) return 0; - QNetworkAccessManager* manager = loader->networkingContext()->networkAccessManager(); - QNetworkCookieJar* jar = manager->cookieJar(); - return jar; + return loader->networkingContext()->networkAccessManager(); } void setCookies(Document* document, const KURL& url, const String& value) { - QUrl u(url); - QUrl p(document->firstPartyForCookies()); - QNetworkCookieJar* jar = cookieJar(document); - if (!jar) + QNetworkAccessManager* manager = networkAccessManager(document); + if (!manager) return; - QList<QNetworkCookie> cookies = QNetworkCookie::parseCookies(QString(value).toAscii()); - QList<QNetworkCookie>::Iterator it = cookies.begin(); - while (it != cookies.end()) { - if (it->isHttpOnly()) - it = cookies.erase(it); - else - ++it; - } - jar->setCookiesFromUrl(cookies, u); + // Create the manipulator on the heap to let it live until the + // async request is picked by the other thread's event loop. + QtNAMThreadSafeProxy* managerProxy = new QtNAMThreadSafeProxy(manager); + managerProxy->setCookies(url, value); + managerProxy->deleteLater(); } String cookies(const Document* document, const KURL& url) { - QUrl u(url); - QNetworkCookieJar* jar = cookieJar(document); - if (!jar) + QNetworkAccessManager* manager = networkAccessManager(document); + if (!manager) return String(); - QList<QNetworkCookie> cookies = jar->cookiesForUrl(u); + QtNAMThreadSafeProxy managerProxy(manager); + QList<QNetworkCookie> cookies = managerProxy.cookiesForUrl(url); if (cookies.isEmpty()) return String(); @@ -101,12 +95,12 @@ String cookies(const Document* document, const KURL& url) String cookieRequestHeaderFieldValue(const Document* document, const KURL &url) { - QUrl u(url); - QNetworkCookieJar* jar = cookieJar(document); - if (!jar) + QNetworkAccessManager* manager = networkAccessManager(document); + if (!manager) return String(); - QList<QNetworkCookie> cookies = jar->cookiesForUrl(u); + QtNAMThreadSafeProxy managerProxy(manager); + QList<QNetworkCookie> cookies = managerProxy.cookiesForUrl(url); if (cookies.isEmpty()) return String(); @@ -121,8 +115,7 @@ String cookieRequestHeaderFieldValue(const Document* document, const KURL &url) bool cookiesEnabled(const Document* document) { - QNetworkCookieJar* jar = cookieJar(document); - return (jar != 0); + return networkAccessManager(document); } bool getRawCookies(const Document*, const KURL&, Vector<Cookie>& rawCookies) diff --git a/WebCore/platform/qt/FileSystemQt.cpp b/WebCore/platform/qt/FileSystemQt.cpp index b384091..d88a967 100644 --- a/WebCore/platform/qt/FileSystemQt.cpp +++ b/WebCore/platform/qt/FileSystemQt.cpp @@ -3,6 +3,7 @@ * Copyright (C) 2007 Holger Hans Peter Freyther * Copyright (C) 2008 Apple, Inc. All rights reserved. * Copyright (C) 2008 Collabora, Ltd. All rights reserved. + * Copyright (C) 2010 Sencha, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -94,7 +95,7 @@ String pathGetFileName(const String& path) String directoryName(const String& path) { - return String(QFileInfo(path).absolutePath()); + return QFileInfo(path).absolutePath(); } Vector<String> listDirectory(const String& path, const String& filter) @@ -128,7 +129,6 @@ CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle) return CString(); } -#if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE) PlatformFileHandle openFile(const String& path, FileOpenMode mode) { QIODevice::OpenMode platformMode; @@ -153,7 +153,6 @@ int readFromFile(PlatformFileHandle handle, char* data, int length) return handle->read(data, length); return 0; } -#endif void closeFile(PlatformFileHandle& handle) { @@ -163,6 +162,34 @@ void closeFile(PlatformFileHandle& handle) } } +long long seekFile(PlatformFileHandle handle, long long offset, FileSeekOrigin origin) +{ + if (handle) { + long long current = 0; + + switch (origin) { + case SeekFromBeginning: + break; + case SeekFromCurrent: + current = handle->pos(); + break; + case SeekFromEnd: + current = handle->size(); + break; + } + + // Add the offset to the current position and seek to the new position + // Return our new position if the seek is successful + current += offset; + if (handle->seek(current)) + return current; + else + return -1; + } + + return -1; +} + int writeToFile(PlatformFileHandle handle, const char* data, int length) { if (handle && handle->exists() && handle->isWritable()) diff --git a/WebCore/platform/qt/GeolocationServiceQt.cpp b/WebCore/platform/qt/GeolocationServiceQt.cpp index 3562eb9..f4379b2 100644 --- a/WebCore/platform/qt/GeolocationServiceQt.cpp +++ b/WebCore/platform/qt/GeolocationServiceQt.cpp @@ -83,7 +83,13 @@ void GeolocationServiceQt::positionUpdated(const QGeoPositionInfo &geoPosition) RefPtr<Coordinates> coordinates = Coordinates::create(latitude, longitude, providesAltitude, altitude, accuracy, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed); - m_lastPosition = Geoposition::create(coordinates.release(), geoPosition.timestamp().toTime_t()); + +#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) + m_lastPosition = Geoposition::create(coordinates.release(), geoPosition.timestamp().toMSecsSinceEpoch()); +#else + QDateTime timestamp = geoPosition.timestamp(); + m_lastPosition = Geoposition::create(coordinates.release(), (timestamp.toTime_t() * 1000.00) + timestamp.time().msec()); +#endif positionChanged(); } diff --git a/WebCore/platform/qt/PlatformScreenQt.cpp b/WebCore/platform/qt/PlatformScreenQt.cpp index db34e21..4db8bd1 100644 --- a/WebCore/platform/qt/PlatformScreenQt.cpp +++ b/WebCore/platform/qt/PlatformScreenQt.cpp @@ -86,7 +86,7 @@ int screenDepthPerComponent(Widget* w) bool screenIsMonochrome(Widget* w) { - return QApplication::desktop()->screen(screenNumber(w))->numColors() < 2; + return QApplication::desktop()->screen(screenNumber(w))->colorCount() == 2; } FloatRect screenRect(Widget* w) diff --git a/WebCore/platform/qt/TemporaryLinkStubsQt.cpp b/WebCore/platform/qt/TemporaryLinkStubsQt.cpp index d7b5104..a46b82c 100644 --- a/WebCore/platform/qt/TemporaryLinkStubsQt.cpp +++ b/WebCore/platform/qt/TemporaryLinkStubsQt.cpp @@ -62,7 +62,6 @@ #include "SystemTime.h" #include "TextBoundaries.h" #include "Widget.h" -#include "loader.h" #include <float.h> #include <stdio.h> diff --git a/WebCore/platform/text/BidiResolver.h b/WebCore/platform/text/BidiResolver.h index 6018c3f..1f87115 100644 --- a/WebCore/platform/text/BidiResolver.h +++ b/WebCore/platform/text/BidiResolver.h @@ -314,13 +314,23 @@ void BidiResolver<Iterator, Run>::checkDirectionInLowerRaiseEmbeddingLevel() using namespace WTF::Unicode; ASSERT(m_status.eor != OtherNeutral || eor.atEnd()); - ASSERT(m_status.last != NonSpacingMark - && m_status.last != BoundaryNeutral - && m_status.last != RightToLeftEmbedding - && m_status.last != LeftToRightEmbedding - && m_status.last != RightToLeftOverride - && m_status.last != LeftToRightOverride - && m_status.last != PopDirectionalFormat); + // bidi.sor ... bidi.eor ... bidi.last eor; need to append the bidi.sor-bidi.eor run or extend it through bidi.last + // Bidi control characters are included into BidiRun, so last direction + // could be one of the bidi embeddings when there are nested embeddings. + // For example: "‪‫....." + ASSERT(m_status.last == EuropeanNumberSeparator + || m_status.last == EuropeanNumberTerminator + || m_status.last == CommonNumberSeparator + || m_status.last == BoundaryNeutral + || m_status.last == BlockSeparator + || m_status.last == SegmentSeparator + || m_status.last == WhiteSpaceNeutral + || m_status.last == OtherNeutral + || m_status.last == RightToLeftEmbedding + || m_status.last == LeftToRightEmbedding + || m_status.last == RightToLeftOverride + || m_status.last == LeftToRightOverride + || m_status.last == PopDirectionalFormat); if (m_direction == OtherNeutral) m_direction = m_status.lastStrong == LeftToRight ? LeftToRight : RightToLeft; } @@ -332,7 +342,6 @@ void BidiResolver<Iterator, Run>::lowerExplicitEmbeddingLevel(WTF::Unicode::Dire if (!emptyRun && eor != 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) { // bidi.sor ... bidi.eor ... bidi.last L if (m_status.eor == EuropeanNumber) { @@ -368,7 +377,6 @@ void BidiResolver<Iterator, Run>::raiseExplicitEmbeddingLevel(WTF::Unicode::Dire if (!emptyRun && eor != 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) { // bidi.sor ... bidi.eor ... bidi.last L if (m_status.eor == EuropeanNumber) { @@ -858,11 +866,6 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, boo break; case NonSpacingMark: case BoundaryNeutral: - case RightToLeftEmbedding: - case LeftToRightEmbedding: - case RightToLeftOverride: - case LeftToRightOverride: - case PopDirectionalFormat: // ignore these break; case EuropeanNumber: diff --git a/WebCore/platform/text/CharacterNames.h b/WebCore/platform/text/CharacterNames.h index 9f8f807..c4b496e 100644 --- a/WebCore/platform/text/CharacterNames.h +++ b/WebCore/platform/text/CharacterNames.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2009, 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 @@ -32,13 +32,20 @@ namespace WebCore { // Names here are taken from the Unicode standard. -// Note, these are UChar constants, not UChar32, which makes them +// Most of these are UChar constants, not UChar32, which makes them // more convenient for WebCore code that mostly uses UTF-16. +const UChar32 aegeanWordSeparatorLine = 0x10100; +const UChar32 aegeanWordSeparatorDot = 0x10101; +const UChar blackCircle = 0x25CF; const UChar blackSquare = 0x25A0; +const UChar blackUpPointingTriangle = 0x25B2; const UChar bullet = 0x2022; +const UChar bullseye = 0x25CE; const UChar carriageReturn = 0x000D; const UChar ethiopicPrefaceColon = 0x1366; +const UChar ethiopicWordspace = 0x1361; +const UChar fisheye = 0x25C9; const UChar hebrewPunctuationGeresh = 0x05F3; const UChar hebrewPunctuationGershayim = 0x05F4; const UChar horizontalEllipsis = 0x2026; @@ -63,9 +70,16 @@ const UChar rightSingleQuotationMark = 0x2019; const UChar rightToLeftEmbed = 0x202B; const UChar rightToLeftMark = 0x200F; const UChar rightToLeftOverride = 0x202E; +const UChar sesameDot = 0xFE45; const UChar softHyphen = 0x00AD; const UChar space = 0x0020; +const UChar tibetanMarkIntersyllabicTsheg = 0x0F0B; +const UChar tibetanMarkDelimiterTshegBstar = 0x0F0C; +const UChar32 ugariticWordDivider = 0x1039F; const UChar whiteBullet = 0x25E6; +const UChar whiteCircle = 0x25CB; +const UChar whiteSesameDot = 0xFE46; +const UChar whiteUpPointingTriangle = 0x25B3; const UChar yenSign = 0x00A5; const UChar zeroWidthJoiner = 0x200D; const UChar zeroWidthNonJoiner = 0x200C; diff --git a/WebCore/platform/text/TextBoundaries.cpp b/WebCore/platform/text/TextBoundaries.cpp index 8eaffca..fbb261b 100644 --- a/WebCore/platform/text/TextBoundaries.cpp +++ b/WebCore/platform/text/TextBoundaries.cpp @@ -36,6 +36,32 @@ using namespace Unicode; namespace WebCore { +int endOfFirstWordBoundaryContext(const UChar* characters, int length) +{ + for (int i = 0; i < length; ) { + int first = i; + UChar32 ch; + U16_NEXT(characters, i, length, ch); + if (!requiresContextForWordBoundary(ch)) + return first; + } + return length; +} + +int startOfLastWordBoundaryContext(const UChar* characters, int length) +{ + for (int i = length; i > 0; ) { + int last = i; + UChar32 ch; + U16_PREV(characters, 0, i, ch); + if (!requiresContextForWordBoundary(ch)) + return last; + } + return 0; +} + +#if !PLATFORM(BREWMP) && !PLATFORM(MAC) && !PLATFORM(QT) + int findNextWordFromIndex(const UChar* chars, int len, int position, bool forward) { TextBreakIterator* it = wordBreakIterator(chars, len); @@ -76,4 +102,6 @@ void findWordBoundary(const UChar* chars, int len, int position, int* start, int *start = textBreakPrevious(it); } +#endif // !PLATFORM(BREWMP) && !PLATFORM(MAC) && !PLATFORM(QT) + } // namespace WebCore diff --git a/WebCore/platform/text/TextBoundaries.h b/WebCore/platform/text/TextBoundaries.h index 7eb9cab..870ab62 100644 --- a/WebCore/platform/text/TextBoundaries.h +++ b/WebCore/platform/text/TextBoundaries.h @@ -35,6 +35,9 @@ namespace WebCore { return WTF::Unicode::hasLineBreakingPropertyComplexContext(ch); } + int endOfFirstWordBoundaryContext(const UChar* characters, int length); + int startOfLastWordBoundaryContext(const UChar* characters, int length); + void findWordBoundary(const UChar*, int len, int position, int* start, int* end); int findNextWordFromIndex(const UChar*, int len, int position, bool forward); diff --git a/WebCore/platform/text/TextCodecUTF16.cpp b/WebCore/platform/text/TextCodecUTF16.cpp index 95f4dc4..e88e83b 100644 --- a/WebCore/platform/text/TextCodecUTF16.cpp +++ b/WebCore/platform/text/TextCodecUTF16.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2006, 2008, 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 @@ -117,8 +117,13 @@ String TextCodecUTF16::decode(const char* bytes, size_t length, bool, bool, bool CString TextCodecUTF16::encode(const UChar* characters, size_t length, UnencodableHandling) { - if (length > numeric_limits<size_t>::max() / 2) - CRASH(); + // We need to be sure we can double the length without overflowing. + // Since the passed-in length is the length of an actual existing + // character buffer, each character is two bytes, and we know + // the buffer doesn't occupy the entire address space, we can + // assert here that doubling the length does not overflow size_t + // and there's no need for a runtime check. + ASSERT(length <= numeric_limits<size_t>::max() / 2); char* bytes; CString string = CString::newUninitialized(length * 2, bytes); diff --git a/WebCore/platform/text/TextEncoding.cpp b/WebCore/platform/text/TextEncoding.cpp index 58e691f..33313a0 100644 --- a/WebCore/platform/text/TextEncoding.cpp +++ b/WebCore/platform/text/TextEncoding.cpp @@ -40,19 +40,11 @@ #include "GOwnPtr.h" #endif #include <wtf/text/CString.h> -#include <wtf/HashSet.h> #include <wtf/OwnPtr.h> #include <wtf/StdLibExtras.h> namespace WebCore { -static void addEncodingName(HashSet<const char*>& set, const char* name) -{ - const char* atomicName = atomicCanonicalTextEncodingName(name); - if (atomicName) - set.add(atomicName); -} - static const TextEncoding& UTF7Encoding() { static TextEncoding globalUTF7Encoding("UTF-7"); @@ -173,39 +165,12 @@ bool TextEncoding::usesVisualOrdering() const bool TextEncoding::isJapanese() const { - if (noExtendedTextEncodingNameUsed()) - return false; - - DEFINE_STATIC_LOCAL(HashSet<const char*>, set, ()); - if (set.isEmpty()) { - addEncodingName(set, "x-mac-japanese"); - addEncodingName(set, "cp932"); - addEncodingName(set, "JIS_X0201"); - addEncodingName(set, "JIS_X0208-1983"); - addEncodingName(set, "JIS_X0208-1990"); - addEncodingName(set, "JIS_X0212-1990"); - addEncodingName(set, "JIS_C6226-1978"); - addEncodingName(set, "Shift_JIS_X0213-2000"); - addEncodingName(set, "ISO-2022-JP"); - addEncodingName(set, "ISO-2022-JP-2"); - addEncodingName(set, "ISO-2022-JP-1"); - addEncodingName(set, "ISO-2022-JP-3"); - addEncodingName(set, "EUC-JP"); - addEncodingName(set, "Shift_JIS"); - } - return m_name && set.contains(m_name); + return isJapaneseEncoding(m_name); } UChar TextEncoding::backslashAsCurrencySymbol() const { - if (noExtendedTextEncodingNameUsed()) - return '\\'; - - // The text encodings below treat backslash as a currency symbol. - // See http://blogs.msdn.com/michkap/archive/2005/09/17/469941.aspx for more information. - static const char* const a = atomicCanonicalTextEncodingName("Shift_JIS_X0213-2000"); - static const char* const b = atomicCanonicalTextEncodingName("EUC-JP"); - return (m_name == a || m_name == b) ? 0x00A5 : '\\'; + return shouldShowBackslashAsCurrencySymbolIn(m_name) ? 0x00A5 : '\\'; } bool TextEncoding::isNonByteBasedEncoding() const diff --git a/WebCore/platform/text/TextEncodingRegistry.cpp b/WebCore/platform/text/TextEncodingRegistry.cpp index 6bf5552..c0c0255 100644 --- a/WebCore/platform/text/TextEncodingRegistry.cpp +++ b/WebCore/platform/text/TextEncodingRegistry.cpp @@ -36,6 +36,7 @@ #include <wtf/Assertions.h> #include <wtf/HashFunctions.h> #include <wtf/HashMap.h> +#include <wtf/HashSet.h> #include <wtf/StdLibExtras.h> #include <wtf/StringExtras.h> #include <wtf/Threading.h> @@ -125,6 +126,8 @@ static Mutex& encodingRegistryMutex() static TextEncodingNameMap* textEncodingNameMap; static TextCodecMap* textCodecMap; static bool didExtendTextCodecMaps; +static HashSet<const char*>* japaneseEncodings; +static HashSet<const char*>* nonBackslashEncodings; static const char* const textEncodingNameBlacklist[] = { "UTF-7" @@ -249,6 +252,59 @@ static void buildBaseTextCodecMaps() #endif } +static void addEncodingName(HashSet<const char*>* set, const char* name) +{ + // We must not use atomicCanonicalTextEncodingName() because this function is called in it. + const char* atomicName = textEncodingNameMap->get(name); + if (atomicName) + set->add(atomicName); +} + +static void buildQuirksSets() +{ + // FIXME: Having isJapaneseEncoding() and shouldShowBackslashAsCurrencySymbolIn() + // and initializing the sets for them in TextEncodingRegistry.cpp look strange. + + ASSERT(!japaneseEncodings); + ASSERT(!nonBackslashEncodings); + + japaneseEncodings = new HashSet<const char*>(); + addEncodingName(japaneseEncodings, "EUC-JP"); + addEncodingName(japaneseEncodings, "ISO-2022-JP"); + addEncodingName(japaneseEncodings, "ISO-2022-JP-1"); + addEncodingName(japaneseEncodings, "ISO-2022-JP-2"); + addEncodingName(japaneseEncodings, "ISO-2022-JP-3"); + addEncodingName(japaneseEncodings, "JIS_C6226-1978"); + addEncodingName(japaneseEncodings, "JIS_X0201"); + addEncodingName(japaneseEncodings, "JIS_X0208-1983"); + addEncodingName(japaneseEncodings, "JIS_X0208-1990"); + addEncodingName(japaneseEncodings, "JIS_X0212-1990"); + addEncodingName(japaneseEncodings, "Shift_JIS"); + addEncodingName(japaneseEncodings, "Shift_JIS_X0213-2000"); + addEncodingName(japaneseEncodings, "cp932"); + addEncodingName(japaneseEncodings, "x-mac-japanese"); + + nonBackslashEncodings = new HashSet<const char*>(); + // The text encodings below treat backslash as a currency symbol for IE compatibility. + // See http://blogs.msdn.com/michkap/archive/2005/09/17/469941.aspx for more information. + addEncodingName(nonBackslashEncodings, "x-mac-japanese"); + addEncodingName(nonBackslashEncodings, "ISO-2022-JP"); + addEncodingName(nonBackslashEncodings, "EUC-JP"); + // Shift_JIS_X0213-2000 is not the same encoding as Shift_JIS on Mac. We need to register both of them. + addEncodingName(nonBackslashEncodings, "Shift_JIS"); + addEncodingName(nonBackslashEncodings, "Shift_JIS_X0213-2000"); +} + +bool isJapaneseEncoding(const char* canonicalEncodingName) +{ + return canonicalEncodingName && japaneseEncodings && japaneseEncodings->contains(canonicalEncodingName); +} + +bool shouldShowBackslashAsCurrencySymbolIn(const char* canonicalEncodingName) +{ + return canonicalEncodingName && nonBackslashEncodings && nonBackslashEncodings->contains(canonicalEncodingName); +} + static void extendTextCodecMaps() { #if USE(ICU_UNICODE) @@ -277,6 +333,7 @@ static void extendTextCodecMaps() #endif pruneBlacklistedCodecs(); + buildQuirksSets(); } PassOwnPtr<TextCodec> newTextCodec(const TextEncoding& encoding) diff --git a/WebCore/platform/text/TextEncodingRegistry.h b/WebCore/platform/text/TextEncodingRegistry.h index 81b7c4c..16844c6 100644 --- a/WebCore/platform/text/TextEncodingRegistry.h +++ b/WebCore/platform/text/TextEncodingRegistry.h @@ -39,12 +39,12 @@ namespace WebCore { // Use TextEncoding::encode to encode, since it takes care of normalization. PassOwnPtr<TextCodec> newTextCodec(const TextEncoding&); - // Only TextEncoding should use this function directly. + // Only TextEncoding should use the following functions directly. const char* atomicCanonicalTextEncodingName(const char* alias); const char* atomicCanonicalTextEncodingName(const UChar* aliasCharacters, size_t aliasLength); - - // Only TextEncoding should use this function directly. bool noExtendedTextEncodingNameUsed(); + bool isJapaneseEncoding(const char* canonicalEncodingName); + bool shouldShowBackslashAsCurrencySymbolIn(const char* canonicalEncodingName); #ifndef NDEBUG void dumpTextEncodingNameMap(); diff --git a/WebCore/platform/text/brew/StringBrew.cpp b/WebCore/platform/text/brew/StringBrew.cpp deleted file mode 100644 index 2da81e3..0000000 --- a/WebCore/platform/text/brew/StringBrew.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2010 Company 100, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "PlatformString.h" - -#include <AEEstd.h> - -namespace WTF { - -// String conversions -String::String(const AECHAR* string) -{ - // It is safe to cast AECHAR to UChar as both of them use 16 bits representation. - const UChar* str = reinterpret_cast<const UChar*>(string); - const size_t len = std_wstrlen(string); - - m_impl = StringImpl::create(str, len); -} - -} // namespace WebCore - diff --git a/WebCore/platform/text/cf/HyphenationCF.cpp b/WebCore/platform/text/cf/HyphenationCF.cpp index dbc11ae..3adacad 100644 --- a/WebCore/platform/text/cf/HyphenationCF.cpp +++ b/WebCore/platform/text/cf/HyphenationCF.cpp @@ -33,46 +33,16 @@ #include <wtf/ListHashSet.h> #include <wtf/RetainPtr.h> -#if PLATFORM(WIN) - -#include "SoftLinking.h" - -#ifdef DEBUG_ALL -SOFT_LINK_DEBUG_LIBRARY(CoreFoundation) -#else -SOFT_LINK_LIBRARY(CoreFoundation) -#endif - -SOFT_LINK_OPTIONAL(CoreFoundation, CFStringGetHyphenationLocationBeforeIndex, CFIndex, , (CFStringRef string, CFIndex location, CFRange limitRange, CFOptionFlags options, CFLocaleRef locale, UTF32Char *character)) -SOFT_LINK_OPTIONAL(CoreFoundation, CFStringIsHyphenationAvailableForLocale, Boolean, , (CFLocaleRef locale)) - -static CFIndex wkCFStringGetHyphenationLocationBeforeIndex(CFStringRef string, CFIndex location, CFRange limitRange, CFOptionFlags options, CFLocaleRef locale, UTF32Char *character) -{ - static CFStringGetHyphenationLocationBeforeIndexPtrType cfStringGetHyphenationLocationBeforeIndex = CFStringGetHyphenationLocationBeforeIndexPtr(); - if (!cfStringGetHyphenationLocationBeforeIndex) - return kCFNotFound; - return cfStringGetHyphenationLocationBeforeIndex(string, location, limitRange, options, locale, character); -} - -static Boolean wkCFStringIsHyphenationAvailableForLocale(CFLocaleRef locale) -{ - static CFStringIsHyphenationAvailableForLocalePtrType cfStringIsHyphenationAvailableForLocale = CFStringIsHyphenationAvailableForLocalePtr(); - return cfStringIsHyphenationAvailableForLocale && cfStringIsHyphenationAvailableForLocale(locale); -} - -#define CFStringGetHyphenationLocationBeforeIndex wkCFStringGetHyphenationLocationBeforeIndex -#define CFStringIsHyphenationAvailableForLocale wkCFStringIsHyphenationAvailableForLocale - -#endif // PLATFORM(WIN) - namespace WebCore { +#if !PLATFORM(WIN) || (defined(MAC_OS_X_VERSION_10_7) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7) + template<> RetainPtr<CFLocaleRef> AtomicStringKeyedMRUCache<RetainPtr<CFLocaleRef> >::createValueForNullKey() { - RetainPtr<CFStringRef> cfLocaleIdentifier(AdoptCF, CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(currentSearchLocaleID()), strlen(currentSearchLocaleID()), kCFStringEncodingASCII, false, kCFAllocatorNull)); - RetainPtr<CFLocaleRef> locale(AdoptCF, CFLocaleCreate(kCFAllocatorDefault, cfLocaleIdentifier.get())); - return locale; + RetainPtr<CFLocaleRef> locale(AdoptCF, CFLocaleCopyCurrent()); + + return CFStringIsHyphenationAvailableForLocale(locale.get()) ? locale : 0; } template<> @@ -80,7 +50,7 @@ RetainPtr<CFLocaleRef> AtomicStringKeyedMRUCache<RetainPtr<CFLocaleRef> >::creat { RetainPtr<CFStringRef> cfLocaleIdentifier(AdoptCF, localeIdentifier.createCFString()); RetainPtr<CFLocaleRef> locale(AdoptCF, CFLocaleCreate(kCFAllocatorDefault, cfLocaleIdentifier.get())); - + return CFStringIsHyphenationAvailableForLocale(locale.get()) ? locale : 0; } @@ -106,6 +76,21 @@ size_t lastHyphenLocation(const UChar* characters, size_t length, size_t beforeI return result == kCFNotFound ? 0 : result; } +#else + +bool canHyphenate(const AtomicString&) +{ + return false; +} + +size_t lastHyphenLocation(const UChar*, size_t, size_t, const AtomicString&) +{ + ASSERT_NOT_REACHED(); + return 0; +} + +#endif // PLATFORM(WIN) && (!defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7) + } // namespace WebCore #endif // !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) diff --git a/WebCore/platform/text/haiku/StringHaiku.cpp b/WebCore/platform/text/haiku/StringHaiku.cpp deleted file mode 100644 index 96d6676..0000000 --- a/WebCore/platform/text/haiku/StringHaiku.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "PlatformString.h" -#include <wtf/text/CString.h> - -#include <String.h> - -namespace WTF { - -// String conversions -String::String(const BString& string) -{ - if (string.Length()) - m_impl = String::fromUTF8(string.String(), string.Length()).impl(); - else - m_impl = StringImpl::empty(); -} - -String::operator BString() const -{ - BString string; - string.SetTo(utf8().data()); - - return string; -} - -} // namespace WebCore - diff --git a/WebCore/platform/text/wince/TextCodecWinCE.cpp b/WebCore/platform/text/wince/TextCodecWinCE.cpp index da6d5a5..3532e74 100644 --- a/WebCore/platform/text/wince/TextCodecWinCE.cpp +++ b/WebCore/platform/text/wince/TextCodecWinCE.cpp @@ -333,8 +333,7 @@ String TextCodecWinCE::decode(const char* bytes, size_t length, bool flush, bool result.append(L'?'); sawError = true; if (stopOnError) - return String(result.data(), result.size()); - + return String::adopt(result); if (left == 1) break; @@ -351,7 +350,8 @@ String TextCodecWinCE::decode(const char* bytes, size_t length, bool flush, bool } } else m_decodeBuffer.clear(); - return String(result.data(), result.size()); + + return String::adopt(result); } CString TextCodecWinCE::encode(const UChar* characters, size_t length, UnencodableHandling) diff --git a/WebCore/platform/text/wx/StringWx.cpp b/WebCore/platform/text/wx/StringWx.cpp deleted file mode 100644 index 7302edc..0000000 --- a/WebCore/platform/text/wx/StringWx.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2007 Vaclav Slavik, Kevin Ollivier <kevino@theolliviers.com> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "PlatformString.h" - -#include "unicode/ustring.h" -#include <wtf/text/CString.h> - -#include <wx/defs.h> -#include <wx/string.h> - -namespace WTF { - -// String conversions -String::String(const wxString& wxstr) -{ -#if !wxUSE_UNICODE - #error "This code only works in Unicode build of wxWidgets" -#endif - - // ICU's UChar is 16bit wide, UTF-16, and the code below counts on it, so - // it would break if the definition changed: - wxCOMPILE_TIME_ASSERT(sizeof(UChar) == 2, UCharSizeMustBe16Bit); - -#if SIZEOF_WCHAR_T == 2 // wchar_t==UChar - - const UChar* str = wxstr.wc_str(); - const size_t len = wxstr.length(); - -#else // SIZEOF_WCHAR_T == 4 - - // NB: we can't simply use wxstr.mb_str(wxMBConvUTF16()) here because - // the number of characters in UTF-16 encoding of the string may differ - // from the number of UTF-32 values and we can't get the length from - // returned buffer: - -#if defined(wxUSE_UNICODE_UTF8) && wxUSE_UNICODE_UTF8 - // in wx3's UTF8 mode, wc_str() returns a buffer, not raw pointer - wxWCharBuffer widestr(wxstr.wc_str()); -#else - const wxChar *widestr = wxstr.wc_str(); -#endif - const size_t widelen = wxstr.length(); - - // allocate buffer for the UTF-16 string: - wxMBConvUTF16 conv; - const size_t utf16bufLen = conv.FromWChar(NULL, 0, widestr, widelen); - wxCharBuffer utf16buf(utf16bufLen); - - // and convert wxString to UTF-16 (=UChar*): - const UChar* str = (const UChar*)utf16buf.data(); - size_t len = conv.FromWChar(utf16buf.data(), utf16bufLen, widestr, widelen) / 2; - -#endif // SIZEOF_WCHAR_T == 4 - - // conversion to UTF-16 or getting internal buffer isn't supposed to fail: - wxASSERT_MSG(str != NULL, _T("failed string conversion?")); - - m_impl = StringImpl::create(str, len); -} - -String::operator wxString() const -{ - return wxString(utf8().data(), wxConvUTF8); -} - -} - -// vim: ts=4 sw=4 et diff --git a/WebCore/platform/win/ContextMenuItemWin.cpp b/WebCore/platform/win/ContextMenuItemWin.cpp index 8d1c175..59aedcd 100644 --- a/WebCore/platform/win/ContextMenuItemWin.cpp +++ b/WebCore/platform/win/ContextMenuItemWin.cpp @@ -28,198 +28,66 @@ #include "ContextMenu.h" -#include <wtf/text/CString.h> -#include <windows.h> - -#if OS(WINCE) -#ifndef MFS_DISABLED -#define MFS_DISABLED MF_GRAYED -#endif -#ifndef MIIM_FTYPE -#define MIIM_FTYPE MIIM_TYPE -#endif -#ifndef MIIM_STRING -#define MIIM_STRING 0 -#endif -#endif - namespace WebCore { -ContextMenuItem::ContextMenuItem(LPMENUITEMINFO item) - : m_platformDescription(item) -{ -} - -ContextMenuItem::ContextMenuItem(ContextMenu* subMenu) +ContextMenuItem::ContextMenuItem(const MENUITEMINFO& info) { - m_platformDescription = (LPMENUITEMINFO)malloc(sizeof(MENUITEMINFO)); - if (!m_platformDescription) - return; + if (info.fMask & MIIM_FTYPE) + m_type = info.fType == MFT_SEPARATOR ? SeparatorType : ActionType; + else + m_type = SeparatorType; - memset(m_platformDescription, 0, sizeof(MENUITEMINFO)); - m_platformDescription->cbSize = sizeof(MENUITEMINFO); + if (m_type == ActionType && info.fMask & MIIM_STRING) + m_title = String(info.dwTypeData, info.cch); - m_platformDescription->wID = ContextMenuItemTagNoAction; - if (subMenu) { - m_platformDescription->fMask |= MIIM_SUBMENU; - m_platformDescription->hSubMenu = subMenu->platformDescription(); + if ((info.fMask & MIIM_SUBMENU) && info.hSubMenu) { + m_type = SubmenuType; + ContextMenu::getContextMenuItems(info.hSubMenu, m_subMenuItems); } -} - -ContextMenuItem::ContextMenuItem(ContextMenuItemType type, ContextMenuAction action, const String& title, ContextMenu* subMenu) -{ - m_platformDescription = (LPMENUITEMINFO)malloc(sizeof(MENUITEMINFO)); - if (!m_platformDescription) - return; - memset(m_platformDescription, 0, sizeof(MENUITEMINFO)); - m_platformDescription->cbSize = sizeof(MENUITEMINFO); - m_platformDescription->fMask = MIIM_FTYPE; + if (info.fMask & MIIM_ID) + m_action = static_cast<ContextMenuAction>(info.wID); + else + m_action = ContextMenuItemTagNoAction; - if (type == SeparatorType) { - m_platformDescription->fType = MFT_SEPARATOR; - return; + if (info.fMask & MIIM_STATE) { + m_checked = info.fState & MFS_CHECKED; + m_enabled = !(info.fState & MFS_DISABLED); + } else { + m_checked = false; + m_enabled = false; } - - if (subMenu) { - m_platformDescription->fMask |= MIIM_STRING | MIIM_SUBMENU; - m_platformDescription->hSubMenu = subMenu->platformDescription(); - } else - m_platformDescription->fMask |= MIIM_STRING | MIIM_ID; - - m_platformDescription->fType = MFT_STRING; - m_platformDescription->wID = action; - - String t = title; - m_platformDescription->cch = t.length(); - m_platformDescription->dwTypeData = wcsdup(t.charactersWithNullTermination()); } -ContextMenuItem::ContextMenuItem(ContextMenuItemType, ContextMenuAction, const String&, bool, bool) +// ContextMenuItem::nativeMenuItem doesn't set the info.dwTypeData. This is +// done to make the lifetime handling of the returned MENUITEMINFO easier on +// callers. Callers can set dwTypeData themselves (and make their own decisions +// about its lifetime) if they need it. +MENUITEMINFO ContextMenuItem::nativeMenuItem() const { - // FIXME: Implement -} + MENUITEMINFO info = {0}; + info.cbSize = sizeof(MENUITEMINFO); -ContextMenuItem::ContextMenuItem(ContextMenuAction, const String&, bool, bool, Vector<ContextMenuItem>&) -{ - // FIXME: Implement -} - -ContextMenuItem::~ContextMenuItem() -{ - if (m_platformDescription) { - if (m_platformDescription->fType == MFT_STRING) - free(m_platformDescription->dwTypeData); - free(m_platformDescription); + if (m_type == SeparatorType) { + info.fMask = MIIM_FTYPE; + info.fType = MFT_SEPARATOR; + return info; } -} - -LPMENUITEMINFO ContextMenuItem::releasePlatformDescription() -{ - LPMENUITEMINFO info = m_platformDescription; - m_platformDescription = 0; - return info; -} - -ContextMenuItemType ContextMenuItem::type() const -{ - ContextMenuItemType type = ActionType; - if (((m_platformDescription->fType & ~MFT_OWNERDRAW) == MFT_STRING) && m_platformDescription->hSubMenu) - type = SubmenuType; - else if (m_platformDescription->fType & MFT_SEPARATOR) - type = SeparatorType; - - return type; -} - -ContextMenuAction ContextMenuItem::action() const -{ - return static_cast<ContextMenuAction>(m_platformDescription->wID); -} - -String ContextMenuItem::title() const -{ - return String(m_platformDescription->dwTypeData, wcslen(m_platformDescription->dwTypeData)); -} - -PlatformMenuDescription ContextMenuItem::platformSubMenu() const -{ - return m_platformDescription->hSubMenu; -} - -void ContextMenuItem::setType(ContextMenuItemType type) -{ - if (type == SeparatorType) - m_platformDescription->fType = MFT_SEPARATOR; - else - m_platformDescription->fType = MFT_STRING; -} - -void ContextMenuItem::setAction(ContextMenuAction action) -{ - m_platformDescription->wID = action; -} - -void ContextMenuItem::setTitle(const String& title) -{ - if (m_platformDescription->dwTypeData) - free(m_platformDescription->dwTypeData); - - m_platformDescription->cch = title.length(); - String titleCopy = title; - m_platformDescription->dwTypeData = wcsdup(titleCopy.charactersWithNullTermination()); -} - -void ContextMenuItem::setSubMenu(ContextMenu* subMenu) -{ - if (subMenu->platformDescription() == m_platformDescription->hSubMenu) - return; - - if (m_platformDescription->hSubMenu) - ::DestroyMenu(m_platformDescription->hSubMenu); - m_platformDescription->fMask |= MIIM_SUBMENU; - m_platformDescription->hSubMenu = subMenu->releasePlatformDescription(); -} + info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STATE; + info.fType = MFT_STRING; -void ContextMenuItem::setSubMenu(Vector<ContextMenuItem>&) -{ - // FIXME: Implement -} + info.wID = m_action; -void ContextMenuItem::setChecked(bool checked) -{ - m_platformDescription->fMask |= MIIM_STATE; - if (checked) { - m_platformDescription->fState &= ~MFS_UNCHECKED; - m_platformDescription->fState |= MFS_CHECKED; - } else { - m_platformDescription->fState &= ~MFS_CHECKED; - m_platformDescription->fState |= MFS_UNCHECKED; + if (m_type == SubmenuType) { + info.fMask |= MIIM_SUBMENU; + info.hSubMenu = ContextMenu::createNativeMenuFromItems(m_subMenuItems); } -} -bool ContextMenuItem::checked() const -{ - // FIXME - Implement - return false; -} + info.fState |= m_enabled ? MFS_ENABLED : MFS_DISABLED; + info.fState |= m_checked ? MFS_CHECKED : MFS_UNCHECKED; -void ContextMenuItem::setEnabled(bool enabled) -{ - m_platformDescription->fMask |= MIIM_STATE; - if (enabled) { - m_platformDescription->fState &= ~MFS_DISABLED; - m_platformDescription->fState |= MFS_ENABLED; - } else { - m_platformDescription->fState &= ~MFS_ENABLED; - m_platformDescription->fState |= MFS_DISABLED; - } -} - -bool ContextMenuItem::enabled() const -{ - return !(m_platformDescription->fState & MFS_DISABLED); + return info; } } diff --git a/WebCore/platform/win/ContextMenuWin.cpp b/WebCore/platform/win/ContextMenuWin.cpp index 10443aa..24c355d 100644 --- a/WebCore/platform/win/ContextMenuWin.cpp +++ b/WebCore/platform/win/ContextMenuWin.cpp @@ -32,6 +32,7 @@ #include "Node.h" #include <tchar.h> #include <windows.h> +#include <wtf/Vector.h> #include <wtf/text/CString.h> #ifndef MIIM_FTYPE @@ -43,184 +44,67 @@ namespace WebCore { -ContextMenu::ContextMenu(const HitTestResult& result) - : m_hitTestResult(result) - , m_platformDescription(0) -#if OS(WINCE) - , m_itemCount(0) -#endif +ContextMenu::ContextMenu(HMENU menu) { - setPlatformDescription(::CreatePopupMenu()); -} - -ContextMenu::ContextMenu(const HitTestResult& result, const PlatformMenuDescription menu) - : m_hitTestResult(result) - , m_platformDescription(0) -#if OS(WINCE) - , m_itemCount(0) -#endif -{ - setPlatformDescription(menu); -} - -ContextMenu::~ContextMenu() -{ - if (m_platformDescription) - ::DestroyMenu(m_platformDescription); -} - -unsigned ContextMenu::itemCount() const -{ -#if OS(WINCE) - return m_itemCount; -#else - if (!m_platformDescription) - return 0; - - return ::GetMenuItemCount(m_platformDescription); -#endif + getContextMenuItems(menu, m_items); } -#if OS(WINCE) -static bool insertMenuItem(PlatformMenuDescription menu, unsigned int position, ContextMenuItem& item) +void ContextMenu::getContextMenuItems(HMENU menu, Vector<ContextMenuItem>& items) { - UINT flags = MF_BYPOSITION; - UINT newItem = 0; - LPCWSTR title = 0; - - if (item.type() == SeparatorType) - flags |= MF_SEPARATOR; - else { - flags |= MF_STRING; - flags |= item.checked() ? MF_CHECKED : MF_UNCHECKED; - flags |= item.enabled() ? MF_ENABLED : MF_GRAYED; - - PlatformMenuItemDescription description = item.releasePlatformDescription(); - title = description->dwTypeData; - description->dwTypeData = 0; - - if (description->hSubMenu) { - flags |= MF_POPUP; - newItem = reinterpret_cast<UINT>(description->hSubMenu); - description->hSubMenu = 0; - } else - newItem = description->wID; - - free(description); - } - - return ::InsertMenuW(menu, position, flags, newItem, title); -} -#endif - -void ContextMenu::insertItem(unsigned int position, ContextMenuItem& item) -{ - if (!m_platformDescription) + int count = ::GetMenuItemCount(menu); + if (count <= 0) return; - checkOrEnableIfNeeded(item); + for (int i = 0; i < count; ++i) { + MENUITEMINFO info = {0}; + info.cbSize = sizeof(MENUITEMINFO); + info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING | MIIM_STATE | MIIM_SUBMENU; -#if OS(WINCE) - if (insertMenuItem(m_platformDescription, position, item)) - ++m_itemCount; -#else - ::InsertMenuItem(m_platformDescription, position, TRUE, item.releasePlatformDescription()); -#endif -} - -void ContextMenu::appendItem(ContextMenuItem& item) -{ - insertItem(itemCount(), item); -} + if (!::GetMenuItemInfo(menu, i, TRUE, &info)) + continue; -static ContextMenuItem* contextMenuItemByIdOrPosition(HMENU menu, unsigned id, BOOL byPosition) -{ - if (!menu) - return 0; - LPMENUITEMINFO info = static_cast<LPMENUITEMINFO>(malloc(sizeof(MENUITEMINFO))); - if (!info) - return 0; - - memset(info, 0, sizeof(MENUITEMINFO)); - - info->cbSize = sizeof(MENUITEMINFO); - - // Setting MIIM_DATA which is useful for WebKit clients who store data in this member for their custom menu items. - info->fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING | MIIM_DATA; - - if (!::GetMenuItemInfo(menu, id, byPosition, info)) { - free(info); - return 0; - } - - if (info->fType & MFT_STRING) { - LPTSTR buffer = static_cast<LPTSTR>(malloc(++info->cch * sizeof(TCHAR))); - if (!buffer) { - free(info); - return 0; + if (info.fType == MFT_SEPARATOR) { + items.append(ContextMenuItem(SeparatorType, ContextMenuItemTagNoAction, String())); + continue; } - info->dwTypeData = buffer; - ::GetMenuItemInfo(menu, id, byPosition, info); - } - - return new ContextMenuItem(info); -} -ContextMenuItem* ContextMenu::itemWithAction(unsigned action) -{ - return contextMenuItemByIdOrPosition(m_platformDescription, action, FALSE); -} + int menuStringLength = info.cch + 1; + OwnArrayPtr<WCHAR> menuString(new WCHAR[menuStringLength]); + info.dwTypeData = menuString.get(); + info.cch = menuStringLength; -ContextMenuItem* ContextMenu::itemAtIndex(unsigned index, const PlatformMenuDescription platformDescription) -{ - return contextMenuItemByIdOrPosition(platformDescription, index, TRUE); + if (::GetMenuItemInfo(menu, i, TRUE, &info)) + items.append(ContextMenuItem(info)); + } } -void ContextMenu::setPlatformDescription(HMENU menu) +HMENU ContextMenu::createNativeMenuFromItems(const Vector<ContextMenuItem>& items) { - if (menu == m_platformDescription) - return; - - if (m_platformDescription) - ::DestroyMenu(m_platformDescription); + HMENU menu = ::CreatePopupMenu(); - m_platformDescription = menu; - if (!m_platformDescription) - return; + for (size_t i = 0; i < items.size(); ++i) { + const ContextMenuItem& item = items[i]; -#if !OS(WINCE) - MENUINFO menuInfo = {0}; - menuInfo.cbSize = sizeof(MENUINFO); - menuInfo.fMask = MIM_STYLE; - ::GetMenuInfo(m_platformDescription, &menuInfo); - menuInfo.fMask = MIM_STYLE; - menuInfo.dwStyle |= MNS_NOTIFYBYPOS; - ::SetMenuInfo(m_platformDescription, &menuInfo); -#endif -} + MENUITEMINFO menuItem = item.nativeMenuItem(); -HMENU ContextMenu::platformDescription() const -{ - return m_platformDescription; -} + // ContextMenuItem::nativeMenuItem doesn't set the title of the MENUITEMINFO to make the + // lifetime handling easier for callers. + String itemTitle = item.title(); + if (item.type() != SeparatorType) { + menuItem.fMask |= MIIM_STRING; + menuItem.cch = itemTitle.length(); + menuItem.dwTypeData = const_cast<LPWSTR>(itemTitle.charactersWithNullTermination()); + } -HMENU ContextMenu::releasePlatformDescription() -{ - HMENU description = m_platformDescription; - m_platformDescription = 0; - return description; -} + ::InsertMenuItem(menu, i, TRUE, &menuItem); + } -Vector<ContextMenuItem> contextMenuItemVector(PlatformMenuDescription) -{ - // FIXME - Implement - return Vector<ContextMenuItem>(); + return menu; } -PlatformMenuDescription platformMenuDescription(Vector<ContextMenuItem>& menuItemVector) +HMENU ContextMenu::nativeMenu() const { - // FIXME - Implement - return 0; + return createNativeMenuFromItems(m_items); } } // namespace WebCore diff --git a/WebCore/platform/win/FileSystemWin.cpp b/WebCore/platform/win/FileSystemWin.cpp index cef7196..5ee3b8e 100644 --- a/WebCore/platform/win/FileSystemWin.cpp +++ b/WebCore/platform/win/FileSystemWin.cpp @@ -134,10 +134,7 @@ String pathGetFileName(const String& path) String directoryName(const String& path) { - String fileName = pathGetFileName(path); - String dirName = String(path); - dirName.truncate(dirName.length() - pathGetFileName(path).length()); - return dirName; + return path.left(path.length() - pathGetFileName(path).length()); } static String bundleName() diff --git a/WebCore/platform/wince/FileSystemWinCE.cpp b/WebCore/platform/wince/FileSystemWinCE.cpp index 90b278e..49acf12 100644 --- a/WebCore/platform/wince/FileSystemWinCE.cpp +++ b/WebCore/platform/wince/FileSystemWinCE.cpp @@ -33,13 +33,26 @@ #include "NotImplemented.h" #include "PlatformString.h" -#include <wtf/text/CString.h> - -#include <windows.h> #include <wincrypt.h> +#include <windows.h> +#include <wtf/text/CString.h> namespace WebCore { +static size_t reverseFindPathSeparator(const String& path, unsigned start = UINT_MAX) +{ + size_t positionSlash = path.reverseFind('/', start); + size_t positionBackslash = path.reverseFind('\\', start); + + if (positionSlash == notFound) + return positionBackslash; + + if (positionBackslash == notFound) + return positionSlash; + + return std::max(positionSlash, positionBackslash); +} + static bool getFileInfo(const String& path, BY_HANDLE_FILE_INFORMATION& fileInfo) { String filename = path; @@ -133,14 +146,14 @@ CString fileSystemRepresentation(const String&) bool makeAllDirectories(const String& path) { - int lastDivPos = std::max(path.reverseFind('/'), path.reverseFind('\\')); - int endPos = path.length(); - if (lastDivPos == path.length() - 1) { - endPos -= 1; - lastDivPos = std::max(path.reverseFind('/', lastDivPos), path.reverseFind('\\', lastDivPos)); + size_t lastDivPos = reverseFindPathSeparator(path); + unsigned endPos = path.length(); + if (lastDivPos == endPos - 1) { + --endPos; + lastDivPos = reverseFindPathSeparator(path, lastDivPos); } - if (lastDivPos > 0) { + if (lastDivPos != notFound) { if (!makeAllDirectories(path.substring(0, lastDivPos))) return false; } @@ -160,13 +173,18 @@ String homeDirectoryPath() String pathGetFileName(const String& path) { - return path.substring(std::max(path.reverseFind('/'), path.reverseFind('\\')) + 1); + size_t pos = reverseFindPathSeparator(path); + if (pos == notFound) + return path; + return path.substring(pos + 1); } String directoryName(const String& path) { - notImplemented(); - return String(); + size_t pos = reverseFindPathSeparator(path); + if (pos == notFound) + return String(); + return path.left(pos); } CString openTemporaryFile(const char*, PlatformFileHandle& handle) diff --git a/WebCore/platform/wx/ContextMenuWx.cpp b/WebCore/platform/wx/ContextMenuWx.cpp index b20d29e..a1bab37 100644 --- a/WebCore/platform/wx/ContextMenuWx.cpp +++ b/WebCore/platform/wx/ContextMenuWx.cpp @@ -42,7 +42,7 @@ ContextMenuItem* ContextMenu::itemWithId(int id) return new ContextMenuItem(ActionType, s_itemActions.get(id), ""); } -ContextMenu::ContextMenu(const HitTestResult& result) : m_hitTestResult(result) +ContextMenu::ContextMenu() { m_platformDescription = new wxMenu(0); } @@ -57,8 +57,6 @@ void ContextMenu::appendItem(ContextMenuItem& item) { if (!m_platformDescription) return; - - checkOrEnableIfNeeded(item); PlatformMenuItemDescription itemDescription = item.releasePlatformDescription(); wxItemKind menuKindWx = ( itemDescription.type == CheckableActionType ) ? wxITEM_CHECK : wxITEM_NORMAL; diff --git a/WebCore/platform/wx/LocalizedStringsWx.cpp b/WebCore/platform/wx/LocalizedStringsWx.cpp index 3c90f6b..4b56394 100644 --- a/WebCore/platform/wx/LocalizedStringsWx.cpp +++ b/WebCore/platform/wx/LocalizedStringsWx.cpp @@ -47,7 +47,7 @@ String resetButtonDefaultLabel() return String("Reset"); } -String defaultLanguage() +String platformDefaultLanguage() { return String("en"); } |