diff options
Diffstat (limited to 'WebCore/page')
77 files changed, 2941 insertions, 1260 deletions
diff --git a/WebCore/page/AbstractView.idl b/WebCore/page/AbstractView.idl index 5b7ce89..36865de 100644 --- a/WebCore/page/AbstractView.idl +++ b/WebCore/page/AbstractView.idl @@ -31,6 +31,7 @@ module views { ObjCCustomImplementation ] AbstractView { readonly attribute Document document; + readonly attribute Media media; }; } diff --git a/WebCore/page/BarInfo.cpp b/WebCore/page/BarInfo.cpp index f6a1210..0f6cad5 100644 --- a/WebCore/page/BarInfo.cpp +++ b/WebCore/page/BarInfo.cpp @@ -62,20 +62,20 @@ bool BarInfo::visible() const return false; switch (m_type) { - case Locationbar: - return m_frame->page()->chrome()->toolbarsVisible(); - case Toolbar: - return m_frame->page()->chrome()->toolbarsVisible(); - case Personalbar: - return m_frame->page()->chrome()->toolbarsVisible(); - case Menubar: - return m_frame->page()->chrome()->menubarVisible(); - case Scrollbars: - return m_frame->page()->chrome()->scrollbarsVisible(); - case Statusbar: - return m_frame->page()->chrome()->statusbarVisible(); - default: - return false; + case Locationbar: + return m_frame->page()->chrome()->toolbarsVisible(); + case Toolbar: + return m_frame->page()->chrome()->toolbarsVisible(); + case Personalbar: + return m_frame->page()->chrome()->toolbarsVisible(); + case Menubar: + return m_frame->page()->chrome()->menubarVisible(); + case Scrollbars: + return m_frame->page()->chrome()->scrollbarsVisible(); + case Statusbar: + return m_frame->page()->chrome()->statusbarVisible(); + default: + return false; } } diff --git a/WebCore/page/Chrome.cpp b/WebCore/page/Chrome.cpp index 86de82e..5a5670e 100644 --- a/WebCore/page/Chrome.cpp +++ b/WebCore/page/Chrome.cpp @@ -36,6 +36,7 @@ #include "InspectorController.h" #include "Page.h" #include "PageGroupLoadDeferrer.h" +#include "RenderObject.h" #include "ResourceHandle.h" #include "ScriptController.h" #include "SecurityOrigin.h" @@ -46,7 +47,7 @@ #include <wtf/Vector.h> #if ENABLE(DOM_STORAGE) -#include "SessionStorage.h" +#include "StorageNamespace.h" #endif namespace WebCore { @@ -115,12 +116,12 @@ FloatRect Chrome::pageRect() const { return m_client->pageRect(); } - + float Chrome::scaleFactor() { return m_client->scaleFactor(); } - + void Chrome::focus() const { m_client->focus(); @@ -140,15 +141,15 @@ void Chrome::takeFocus(FocusDirection direction) const { m_client->takeFocus(direction); } - + Page* Chrome::createWindow(Frame* frame, const FrameLoadRequest& request, const WindowFeatures& features) const { Page* newPage = m_client->createWindow(frame, request, features); #if ENABLE(DOM_STORAGE) if (newPage) { - if (SessionStorage* oldSessionStorage = m_page->sessionStorage(false)) - newPage->setSessionStorage(oldSessionStorage->copy(newPage)); + if (StorageNamespace* oldSessionStorage = m_page->sessionStorage(false)) + newPage->setSessionStorage(oldSessionStorage->copy()); } #endif @@ -234,7 +235,7 @@ bool Chrome::canRunBeforeUnloadConfirmPanel() bool Chrome::runBeforeUnloadConfirmPanel(const String& message, Frame* frame) { - // Defer loads in case the client method runs a new event loop that would + // Defer loads in case the client method runs a new event loop that would // otherwise cause the load to continue while we're in the middle of executing JavaScript. PageGroupLoadDeferrer deferrer(m_page, true); @@ -248,7 +249,7 @@ void Chrome::closeWindowSoon() void Chrome::runJavaScriptAlert(Frame* frame, const String& message) { - // Defer loads in case the client method runs a new event loop that would + // Defer loads in case the client method runs a new event loop that would // otherwise cause the load to continue while we're in the middle of executing JavaScript. PageGroupLoadDeferrer deferrer(m_page, true); @@ -258,7 +259,7 @@ void Chrome::runJavaScriptAlert(Frame* frame, const String& message) bool Chrome::runJavaScriptConfirm(Frame* frame, const String& message) { - // Defer loads in case the client method runs a new event loop that would + // Defer loads in case the client method runs a new event loop that would // otherwise cause the load to continue while we're in the middle of executing JavaScript. PageGroupLoadDeferrer deferrer(m_page, true); @@ -268,16 +269,16 @@ bool Chrome::runJavaScriptConfirm(Frame* frame, const String& message) bool Chrome::runJavaScriptPrompt(Frame* frame, const String& prompt, const String& defaultValue, String& result) { - // Defer loads in case the client method runs a new event loop that would + // Defer loads in case the client method runs a new event loop that would // otherwise cause the load to continue while we're in the middle of executing JavaScript. PageGroupLoadDeferrer deferrer(m_page, true); ASSERT(frame); bool ok = m_client->runJavaScriptPrompt(frame, frame->displayStringModifiedByEncoding(prompt), frame->displayStringModifiedByEncoding(defaultValue), result); - + if (ok) result = frame->displayStringModifiedByEncoding(result); - + return ok; } @@ -289,7 +290,7 @@ void Chrome::setStatusbarText(Frame* frame, const String& status) bool Chrome::shouldInterruptJavaScript() { - // Defer loads in case the client method runs a new event loop that would + // Defer loads in case the client method runs a new event loop that would // otherwise cause the load to continue while we're in the middle of executing JavaScript. PageGroupLoadDeferrer deferrer(m_page, true); @@ -317,7 +318,8 @@ void Chrome::mouseDidMoveOverElement(const HitTestResult& result, unsigned modif void Chrome::setToolTip(const HitTestResult& result) { // First priority is a potential toolTip representing a spelling or grammar error - String toolTip = result.spellingToolTip(); + TextDirection toolTipDirection; + String toolTip = result.spellingToolTip(toolTipDirection); // Next priority is a toolTip from a URL beneath the mouse (if preference is set to show those). if (toolTip.isEmpty() && m_page->settings()->showsURLsInToolTips()) { @@ -326,20 +328,28 @@ void Chrome::setToolTip(const HitTestResult& result) if (node->hasTagName(inputTag)) { HTMLInputElement* input = static_cast<HTMLInputElement*>(node); if (input->inputType() == HTMLInputElement::SUBMIT) - if (HTMLFormElement* form = input->form()) + if (HTMLFormElement* form = input->form()) { toolTip = form->action(); + if (form->renderer()) + toolTipDirection = form->renderer()->style()->direction(); + else + toolTipDirection = LTR; + } } } // Get tooltip representing link's URL - if (toolTip.isEmpty()) + if (toolTip.isEmpty()) { // FIXME: Need to pass this URL through userVisibleString once that's in WebCore toolTip = result.absoluteLinkURL().string(); + // URL always display as LTR. + toolTipDirection = LTR; + } } // Next we'll consider a tooltip for element with "title" attribute if (toolTip.isEmpty()) - toolTip = result.title(); + toolTip = result.title(toolTipDirection); // Lastly, for <input type="file"> that allow multiple files, we'll consider a tooltip for the selected filenames if (toolTip.isEmpty()) { @@ -357,13 +367,15 @@ void Chrome::setToolTip(const HitTestResult& result) names.append('\n'); } toolTip = String::adopt(names); + // filename always display as LTR. + toolTipDirection = LTR; } } } } } - - m_client->setToolTip(toolTip); + + m_client->setToolTip(toolTip, toolTipDirection); } void Chrome::print(Frame* frame) @@ -373,7 +385,7 @@ void Chrome::print(Frame* frame) void Chrome::requestGeolocationPermissionForFrame(Frame* frame, Geolocation* geolocation) { - // Defer loads in case the client method runs a new event loop that would + // Defer loads in case the client method runs a new event loop that would // otherwise cause the load to continue while we're in the middle of executing JavaScript. PageGroupLoadDeferrer deferrer(m_page, true); @@ -420,10 +432,10 @@ bool ChromeClient::shouldReplaceWithGeneratedFileForUpload(const String&, String String ChromeClient::generateReplacementFile(const String&) { ASSERT_NOT_REACHED(); - return String(); + return String(); } -bool ChromeClient::paintCustomScrollbar(GraphicsContext*, const FloatRect&, ScrollbarControlSize, +bool ChromeClient::paintCustomScrollbar(GraphicsContext*, const FloatRect&, ScrollbarControlSize, ScrollbarControlState, ScrollbarPart, bool, float, float, ScrollbarControlPartMask) { diff --git a/WebCore/page/ChromeClient.h b/WebCore/page/ChromeClient.h index 46f37f3..409a492 100644 --- a/WebCore/page/ChromeClient.h +++ b/WebCore/page/ChromeClient.h @@ -103,7 +103,7 @@ namespace WebCore { virtual void setResizable(bool) = 0; - virtual void addMessageToConsole(MessageSource, MessageLevel, const String& message, unsigned int lineNumber, const String& sourceID) = 0; + virtual void addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message, unsigned int lineNumber, const String& sourceID) = 0; virtual bool canRunBeforeUnloadConfirmPanel() = 0; virtual bool runBeforeUnloadConfirmPanel(const String& message, Frame* frame) = 0; @@ -131,7 +131,7 @@ namespace WebCore { virtual void mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags) = 0; - virtual void setToolTip(const String&) = 0; + virtual void setToolTip(const String&, TextDirection) = 0; virtual void print(Frame*) = 0; @@ -177,6 +177,9 @@ namespace WebCore { // Notification that the given form element has changed. This function // will be called frequently, so handling should be very fast. virtual void formStateDidChange(const Node*) = 0; + + virtual void formDidFocus(const Node*) { }; + virtual void formDidBlur(const Node*) { }; virtual PassOwnPtr<HTMLParserQuirks> createHTMLParserQuirks() = 0; @@ -188,7 +191,7 @@ namespace WebCore { virtual void setNeedsOneShotDrawingSynchronization() = 0; // Sets a flag to specify that the view needs to be updated, so we need // to do an eager layout before the drawing. - virtual void scheduleViewUpdate() = 0; + virtual void scheduleCompositingLayerSync() = 0; #endif #if PLATFORM(MAC) diff --git a/WebCore/page/Console.cpp b/WebCore/page/Console.cpp index 99a0fc8..b5c9bb2 100644 --- a/WebCore/page/Console.cpp +++ b/WebCore/page/Console.cpp @@ -29,8 +29,9 @@ #include "config.h" #include "Console.h" -#include "ChromeClient.h" #include "CString.h" +#include "ChromeClient.h" +#include "ConsoleMessage.h" #include "Frame.h" #include "FrameLoader.h" #include "FrameTree.h" @@ -90,75 +91,63 @@ static void printMessageSourceAndLevelPrefix(MessageSource source, MessageLevel { const char* sourceString; switch (source) { - case HTMLMessageSource: - sourceString = "HTML"; - break; - case WMLMessageSource: - sourceString = "WML"; - break; - case XMLMessageSource: - sourceString = "XML"; - break; - case JSMessageSource: - sourceString = "JS"; - break; - case CSSMessageSource: - sourceString = "CSS"; - break; - case OtherMessageSource: - sourceString = "OTHER"; - break; - default: - ASSERT_NOT_REACHED(); - sourceString = "UNKNOWN"; - break; + case HTMLMessageSource: + sourceString = "HTML"; + break; + case WMLMessageSource: + sourceString = "WML"; + break; + case XMLMessageSource: + sourceString = "XML"; + break; + case JSMessageSource: + sourceString = "JS"; + break; + case CSSMessageSource: + sourceString = "CSS"; + break; + case OtherMessageSource: + sourceString = "OTHER"; + break; + default: + ASSERT_NOT_REACHED(); + sourceString = "UNKNOWN"; + break; } const char* levelString; switch (level) { - case TipMessageLevel: - levelString = "TIP"; - break; - case LogMessageLevel: - levelString = "LOG"; - break; - case WarningMessageLevel: - levelString = "WARN"; - break; - case ErrorMessageLevel: - levelString = "ERROR"; - break; - case ObjectMessageLevel: - levelString = "OBJECT"; - break; - case TraceMessageLevel: - levelString = "TRACE"; - break; - case StartGroupMessageLevel: - levelString = "START GROUP"; - break; - case EndGroupMessageLevel: - levelString = "END GROUP"; - break; - default: - ASSERT_NOT_REACHED(); - levelString = "UNKNOWN"; - break; + case TipMessageLevel: + levelString = "TIP"; + break; + case LogMessageLevel: + levelString = "LOG"; + break; + case WarningMessageLevel: + levelString = "WARN"; + break; + case ErrorMessageLevel: + levelString = "ERROR"; + break; + default: + ASSERT_NOT_REACHED(); + levelString = "UNKNOWN"; + break; } printf("%s %s:", sourceString, levelString); } -void Console::addMessage(MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceURL) +void Console::addMessage(MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceURL) { Page* page = this->page(); if (!page) return; - if (source == JSMessageSource || source == WMLMessageSource) - page->chrome()->client()->addMessageToConsole(source, level, message, lineNumber, sourceURL); + if (source == JSMessageSource) + page->chrome()->client()->addMessageToConsole(source, type, level, message, lineNumber, sourceURL); - page->inspectorController()->addMessageToConsole(source, level, message, lineNumber, sourceURL); + page->inspectorController()->addMessageToConsole(source, type, level, message, lineNumber, sourceURL); if (!Console::shouldPrintExceptions()) return; @@ -169,7 +158,8 @@ void Console::addMessage(MessageSource source, MessageLevel level, const String& printf(" %s\n", message.utf8().data()); } -void Console::addMessage(MessageLevel level, ScriptCallStack* callStack, bool acceptNoArguments) { +void Console::addMessage(MessageType type, MessageLevel level, ScriptCallStack* callStack, bool acceptNoArguments) +{ Page* page = this->page(); if (!page) return; @@ -181,9 +171,9 @@ void Console::addMessage(MessageLevel level, ScriptCallStack* callStack, bool ac String message; if (getFirstArgumentAsString(callStack->state(), lastCaller, message)) - page->chrome()->client()->addMessageToConsole(JSMessageSource, level, message, lastCaller.lineNumber(), lastCaller.sourceURL().prettyURL()); + page->chrome()->client()->addMessageToConsole(JSMessageSource, type, level, message, lastCaller.lineNumber(), lastCaller.sourceURL().prettyURL()); - page->inspectorController()->addMessageToConsole(JSMessageSource, level, callStack); + page->inspectorController()->addMessageToConsole(JSMessageSource, type, level, callStack); if (!Console::shouldPrintExceptions()) return; @@ -207,7 +197,7 @@ void Console::debug(ScriptCallStack* callStack) void Console::error(ScriptCallStack* callStack) { - addMessage(ErrorMessageLevel, callStack); + addMessage(LogMessageType, ErrorMessageLevel, callStack); } void Console::info(ScriptCallStack* callStack) @@ -217,12 +207,12 @@ void Console::info(ScriptCallStack* callStack) void Console::log(ScriptCallStack* callStack) { - addMessage(LogMessageLevel, callStack); + addMessage(LogMessageType, LogMessageLevel, callStack); } void Console::dir(ScriptCallStack* callStack) { - addMessage(ObjectMessageLevel, callStack); + addMessage(ObjectMessageType, LogMessageLevel, callStack); } void Console::dirxml(ScriptCallStack* callStack) @@ -233,7 +223,7 @@ void Console::dirxml(ScriptCallStack* callStack) void Console::trace(ScriptCallStack* callStack) { - addMessage(TraceMessageLevel, callStack, true); + addMessage(TraceMessageType, LogMessageLevel, callStack, true); if (!shouldPrintExceptions()) return; @@ -251,7 +241,7 @@ void Console::assertCondition(bool condition, ScriptCallStack* callStack) return; // FIXME: <https://bugs.webkit.org/show_bug.cgi?id=19135> It would be nice to prefix assertion failures with a message like "Assertion failed: ". - addMessage(ErrorMessageLevel, callStack, true); + addMessage(LogMessageType, ErrorMessageLevel, callStack, true); } void Console::count(ScriptCallStack* callStack) @@ -269,6 +259,32 @@ void Console::count(ScriptCallStack* callStack) page->inspectorController()->count(title, lastCaller.lineNumber(), lastCaller.sourceURL().string()); } +#if ENABLE(WML) +String Console::lastWMLErrorMessage() const +{ + Page* page = this->page(); + if (!page) + return String(); + + const Vector<ConsoleMessage*>& consoleMessages = page->inspectorController()->consoleMessages(); + if (consoleMessages.isEmpty()) + return String(); + + Vector<ConsoleMessage*>::const_iterator it = consoleMessages.begin(); + const Vector<ConsoleMessage*>::const_iterator end = consoleMessages.end(); + + for (; it != end; ++it) { + ConsoleMessage* message = *it; + if (message->source() != WMLMessageSource) + continue; + + return message->message(); + } + + return String(); +} +#endif + #if ENABLE(JAVASCRIPT_DEBUGGER) void Console::profile(const JSC::UString& title, ScriptCallStack* callStack) @@ -277,16 +293,19 @@ void Console::profile(const JSC::UString& title, ScriptCallStack* callStack) if (!page) return; + InspectorController* controller = page->inspectorController(); // FIXME: log a console message when profiling is disabled. - if (!page->inspectorController()->profilerEnabled()) + if (!controller->profilerEnabled()) return; - if (title.isNull()) { // no title so give it the next user initiated profile title. - page->inspectorController()->startUserInitiatedProfiling(0); - return; - } + JSC::UString resolvedTitle = title; + if (title.isNull()) // no title so give it the next user initiated profile title. + resolvedTitle = controller->getCurrentUserInitiatedProfileName(true); + + JSC::Profiler::profiler()->startProfiling(callStack->state(), resolvedTitle); - JSC::Profiler::profiler()->startProfiling(callStack->state(), title); + const ScriptCallFrame& lastCaller = callStack->at(0); + controller->addStartProfilingMessageToConsole(resolvedTitle, lastCaller.lineNumber(), lastCaller.sourceURL()); } void Console::profileEnd(const JSC::UString& title, ScriptCallStack* callStack) @@ -295,7 +314,11 @@ void Console::profileEnd(const JSC::UString& title, ScriptCallStack* callStack) if (!page) return; - if (!page->inspectorController()->profilerEnabled()) + if (!this->page()) + return; + + InspectorController* controller = page->inspectorController(); + if (!controller->profilerEnabled()) return; RefPtr<JSC::Profile> profile = JSC::Profiler::profiler()->stopProfiling(callStack->state(), title); @@ -304,14 +327,12 @@ void Console::profileEnd(const JSC::UString& title, ScriptCallStack* callStack) m_profiles.append(profile); - if (Page* page = this->page()) { - const ScriptCallFrame& lastCaller = callStack->at(0); - page->inspectorController()->addProfile(profile, lastCaller.lineNumber(), lastCaller.sourceURL()); - } + const ScriptCallFrame& lastCaller = callStack->at(0); + controller->addProfile(profile, lastCaller.lineNumber(), lastCaller.sourceURL()); } #endif - + void Console::time(const String& title) { Page* page = this->page(); @@ -322,7 +343,7 @@ void Console::time(const String& title) // undefined for timing functions if (title.isNull()) return; - + page->inspectorController()->startTiming(title); } @@ -344,7 +365,7 @@ void Console::timeEnd(const String& title, ScriptCallStack* callStack) String message = title + String::format(": %.0fms", elapsed); const ScriptCallFrame& lastCaller = callStack->at(0); - page->inspectorController()->addMessageToConsole(JSMessageSource, LogMessageLevel, message, lastCaller.lineNumber(), lastCaller.sourceURL().string()); + page->inspectorController()->addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lastCaller.lineNumber(), lastCaller.sourceURL().string()); } void Console::group(ScriptCallStack* callStack) @@ -367,7 +388,7 @@ void Console::groupEnd() void Console::warn(ScriptCallStack* callStack) { - addMessage(WarningMessageLevel, callStack); + addMessage(LogMessageType, WarningMessageLevel, callStack); } static bool printExceptions = false; diff --git a/WebCore/page/Console.h b/WebCore/page/Console.h index 79396ea..6d4dbce 100644 --- a/WebCore/page/Console.h +++ b/WebCore/page/Console.h @@ -59,16 +59,19 @@ namespace WebCore { OtherMessageSource }; + enum MessageType { + LogMessageType, + ObjectMessageType, + TraceMessageType, + StartGroupMessageType, + EndGroupMessageType + }; + enum MessageLevel { TipMessageLevel, LogMessageLevel, WarningMessageLevel, - ErrorMessageLevel, - // FIXME: the remaining levels should become a new MessageType enum. - ObjectMessageLevel, - TraceMessageLevel, - StartGroupMessageLevel, - EndGroupMessageLevel + ErrorMessageLevel }; class Console : public RefCounted<Console> { @@ -78,7 +81,7 @@ namespace WebCore { Frame* frame() const; void disconnectFrame(); - void addMessage(MessageSource, MessageLevel, const String& message, unsigned lineNumber, const String& sourceURL); + void addMessage(MessageSource, MessageType, MessageLevel, const String& message, unsigned lineNumber, const String& sourceURL); void debug(ScriptCallStack*); void error(ScriptCallStack*); @@ -90,6 +93,9 @@ namespace WebCore { void trace(ScriptCallStack*); void assertCondition(bool condition, ScriptCallStack*); void count(ScriptCallStack*); +#if ENABLE(WML) + String lastWMLErrorMessage() const; +#endif #if ENABLE(JAVASCRIPT_DEBUGGER) void profile(const JSC::UString&, ScriptCallStack*); void profileEnd(const JSC::UString&, ScriptCallStack*); @@ -108,7 +114,7 @@ namespace WebCore { private: inline Page* page() const; - void addMessage(MessageLevel, ScriptCallStack*, bool acceptNoArguments = false); + void addMessage(MessageType, MessageLevel, ScriptCallStack*, bool acceptNoArguments = false); Console(Frame*); diff --git a/WebCore/page/Console.idl b/WebCore/page/Console.idl index 4803508..0e9f3dc 100644 --- a/WebCore/page/Console.idl +++ b/WebCore/page/Console.idl @@ -45,6 +45,10 @@ module window { [CustomArgumentHandling, ImplementationFunction=assertCondition] void assert(in boolean condition); [CustomArgumentHandling] void count(); +#if defined(ENABLE_WML) && ENABLE_WML + [DontEnum] DOMString lastWMLErrorMessage(); +#endif + #if defined(ENABLE_JAVASCRIPT_DEBUGGER) && ENABLE_JAVASCRIPT_DEBUGGER [CustomArgumentHandling] void profile(in [ConvertUndefinedOrNullToNullString] DOMString title); [CustomArgumentHandling] void profileEnd(in [ConvertUndefinedOrNullToNullString] DOMString title); diff --git a/WebCore/page/ContextMenuClient.h b/WebCore/page/ContextMenuClient.h index 775adc5..1997cd0 100644 --- a/WebCore/page/ContextMenuClient.h +++ b/WebCore/page/ContextMenuClient.h @@ -47,6 +47,7 @@ namespace WebCore { virtual void downloadURL(const KURL& url) = 0; virtual void searchWithGoogle(const Frame*) = 0; virtual void lookUpInDictionary(Frame*) = 0; + virtual bool isSpeaking() = 0; virtual void speak(const String&) = 0; virtual void stopSpeaking() = 0; diff --git a/WebCore/page/ContextMenuController.cpp b/WebCore/page/ContextMenuController.cpp index 58e6519..0ec9d1c 100644 --- a/WebCore/page/ContextMenuController.cpp +++ b/WebCore/page/ContextMenuController.cpp @@ -39,11 +39,11 @@ #include "EventNames.h" #include "FormState.h" #include "Frame.h" -#include "FrameLoader.h" #include "FrameLoadRequest.h" +#include "FrameLoader.h" +#include "HTMLFormElement.h" #include "HitTestRequest.h" #include "HitTestResult.h" -#include "HTMLFormElement.h" #include "InspectorController.h" #include "MouseEvent.h" #include "Node.h" @@ -108,8 +108,7 @@ static void openNewWindow(const KURL& urlToLoad, Frame* frame) { if (Page* oldPage = frame->page()) { WindowFeatures features; - if (Page* newPage = oldPage->chrome()->createWindow(frame, - FrameLoadRequest(ResourceRequest(urlToLoad, frame->loader()->outgoingReferrer())), features)) + if (Page* newPage = oldPage->chrome()->createWindow(frame, FrameLoadRequest(ResourceRequest(urlToLoad, frame->loader()->outgoingReferrer())), features)) newPage->chrome()->show(); } } @@ -127,215 +126,211 @@ void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item) Frame* frame = result.innerNonSharedNode()->document()->frame(); if (!frame) return; - + switch (item->action()) { - case ContextMenuItemTagOpenLinkInNewWindow: - openNewWindow(result.absoluteLinkURL(), frame); - break; - case ContextMenuItemTagDownloadLinkToDisk: - // FIXME: Some day we should be able to do this from within WebCore. - m_client->downloadURL(result.absoluteLinkURL()); - break; - case ContextMenuItemTagCopyLinkToClipboard: - frame->editor()->copyURL(result.absoluteLinkURL(), result.textContent()); - break; - case ContextMenuItemTagOpenImageInNewWindow: - openNewWindow(result.absoluteImageURL(), frame); - break; - case ContextMenuItemTagDownloadImageToDisk: - // FIXME: Some day we should be able to do this from within WebCore. - m_client->downloadURL(result.absoluteImageURL()); - break; - case ContextMenuItemTagCopyImageToClipboard: - // FIXME: The Pasteboard class is not written yet - // For now, call into the client. This is temporary! - frame->editor()->copyImage(result); - break; - case ContextMenuItemTagOpenFrameInNewWindow: { - DocumentLoader* loader = frame->loader()->documentLoader(); - if (!loader->unreachableURL().isEmpty()) - openNewWindow(loader->unreachableURL(), frame); - else - openNewWindow(loader->url(), frame); - break; - } - case ContextMenuItemTagCopy: - frame->editor()->copy(); - break; - case ContextMenuItemTagGoBack: - frame->loader()->goBackOrForward(-1); - break; - case ContextMenuItemTagGoForward: - frame->loader()->goBackOrForward(1); - break; - case ContextMenuItemTagStop: - frame->loader()->stop(); - break; - case ContextMenuItemTagReload: - frame->loader()->reload(); - break; - case ContextMenuItemTagCut: - frame->editor()->cut(); - break; - case ContextMenuItemTagPaste: - frame->editor()->paste(); - break; + case ContextMenuItemTagOpenLinkInNewWindow: + openNewWindow(result.absoluteLinkURL(), frame); + break; + case ContextMenuItemTagDownloadLinkToDisk: + // FIXME: Some day we should be able to do this from within WebCore. + m_client->downloadURL(result.absoluteLinkURL()); + break; + case ContextMenuItemTagCopyLinkToClipboard: + frame->editor()->copyURL(result.absoluteLinkURL(), result.textContent()); + break; + case ContextMenuItemTagOpenImageInNewWindow: + openNewWindow(result.absoluteImageURL(), frame); + break; + case ContextMenuItemTagDownloadImageToDisk: + // FIXME: Some day we should be able to do this from within WebCore. + m_client->downloadURL(result.absoluteImageURL()); + break; + case ContextMenuItemTagCopyImageToClipboard: + // FIXME: The Pasteboard class is not written yet + // For now, call into the client. This is temporary! + frame->editor()->copyImage(result); + break; + case ContextMenuItemTagOpenFrameInNewWindow: { + DocumentLoader* loader = frame->loader()->documentLoader(); + if (!loader->unreachableURL().isEmpty()) + openNewWindow(loader->unreachableURL(), frame); + else + openNewWindow(loader->url(), frame); + break; + } + case ContextMenuItemTagCopy: + frame->editor()->copy(); + break; + case ContextMenuItemTagGoBack: + frame->loader()->goBackOrForward(-1); + break; + case ContextMenuItemTagGoForward: + frame->loader()->goBackOrForward(1); + break; + case ContextMenuItemTagStop: + frame->loader()->stop(); + break; + case ContextMenuItemTagReload: + frame->loader()->reload(); + break; + case ContextMenuItemTagCut: + frame->editor()->cut(); + break; + case ContextMenuItemTagPaste: + frame->editor()->paste(); + break; #if PLATFORM(GTK) - case ContextMenuItemTagDelete: - frame->editor()->performDelete(); - break; - case ContextMenuItemTagSelectAll: - frame->editor()->command("SelectAll").execute(); - break; + case ContextMenuItemTagDelete: + frame->editor()->performDelete(); + break; + case ContextMenuItemTagSelectAll: + frame->editor()->command("SelectAll").execute(); + break; #endif - case ContextMenuItemTagSpellingGuess: - ASSERT(frame->selectedText().length()); - if (frame->editor()->shouldInsertText(item->title(), frame->selection()->toNormalizedRange().get(), - EditorInsertActionPasted)) { - Document* document = frame->document(); - RefPtr<ReplaceSelectionCommand> command = - ReplaceSelectionCommand::create(document, createFragmentFromMarkup(document, item->title(), ""), - true, false, true); - applyCommand(command); - frame->revealSelection(ScrollAlignment::alignToEdgeIfNeeded); - } - break; - case ContextMenuItemTagIgnoreSpelling: - frame->editor()->ignoreSpelling(); - break; - case ContextMenuItemTagLearnSpelling: - frame->editor()->learnSpelling(); - break; - case ContextMenuItemTagSearchWeb: - m_client->searchWithGoogle(frame); - break; - case ContextMenuItemTagLookUpInDictionary: - // FIXME: Some day we may be able to do this from within WebCore. - m_client->lookUpInDictionary(frame); - break; - case ContextMenuItemTagOpenLink: - if (Frame* targetFrame = result.targetFrame()) { - targetFrame->loader()->loadFrameRequest(FrameLoadRequest(ResourceRequest(result.absoluteLinkURL(), - frame->loader()->outgoingReferrer())), false, false, 0, 0); - } else - openNewWindow(result.absoluteLinkURL(), frame); - break; - case ContextMenuItemTagBold: - frame->editor()->command("ToggleBold").execute(); - break; - case ContextMenuItemTagItalic: - frame->editor()->command("ToggleItalic").execute(); - break; - case ContextMenuItemTagUnderline: - frame->editor()->toggleUnderline(); - break; - case ContextMenuItemTagOutline: - // We actually never enable this because CSS does not have a way to specify an outline font, - // which may make this difficult to implement. Maybe a special case of text-shadow? - break; - case ContextMenuItemTagStartSpeaking: { - ExceptionCode ec; - RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange(); - if (!selectedRange || selectedRange->collapsed(ec)) { - Document* document = result.innerNonSharedNode()->document(); - selectedRange = document->createRange(); - selectedRange->selectNode(document->documentElement(), ec); - } - m_client->speak(plainText(selectedRange.get())); - break; + case ContextMenuItemTagSpellingGuess: + ASSERT(frame->selectedText().length()); + if (frame->editor()->shouldInsertText(item->title(), frame->selection()->toNormalizedRange().get(), EditorInsertActionPasted)) { + Document* document = frame->document(); + RefPtr<ReplaceSelectionCommand> command = ReplaceSelectionCommand::create(document, createFragmentFromMarkup(document, item->title(), ""), true, false, true); + applyCommand(command); + frame->revealSelection(ScrollAlignment::alignToEdgeIfNeeded); } - case ContextMenuItemTagStopSpeaking: - m_client->stopSpeaking(); - break; - case ContextMenuItemTagDefaultDirection: - frame->editor()->setBaseWritingDirection(NaturalWritingDirection); - break; - case ContextMenuItemTagLeftToRight: - frame->editor()->setBaseWritingDirection(LeftToRightWritingDirection); - break; - case ContextMenuItemTagRightToLeft: - frame->editor()->setBaseWritingDirection(RightToLeftWritingDirection); - break; - case ContextMenuItemTagTextDirectionDefault: - frame->editor()->command("MakeTextWritingDirectionNatural").execute(); - break; - case ContextMenuItemTagTextDirectionLeftToRight: - frame->editor()->command("MakeTextWritingDirectionLeftToRight").execute(); - break; - case ContextMenuItemTagTextDirectionRightToLeft: - frame->editor()->command("MakeTextWritingDirectionRightToLeft").execute(); - break; + break; + case ContextMenuItemTagIgnoreSpelling: + frame->editor()->ignoreSpelling(); + break; + case ContextMenuItemTagLearnSpelling: + frame->editor()->learnSpelling(); + break; + case ContextMenuItemTagSearchWeb: + m_client->searchWithGoogle(frame); + break; + case ContextMenuItemTagLookUpInDictionary: + // FIXME: Some day we may be able to do this from within WebCore. + m_client->lookUpInDictionary(frame); + break; + case ContextMenuItemTagOpenLink: + if (Frame* targetFrame = result.targetFrame()) + targetFrame->loader()->loadFrameRequest(FrameLoadRequest(ResourceRequest(result.absoluteLinkURL(), frame->loader()->outgoingReferrer())), false, false, 0, 0); + else + openNewWindow(result.absoluteLinkURL(), frame); + break; + case ContextMenuItemTagBold: + frame->editor()->command("ToggleBold").execute(); + break; + case ContextMenuItemTagItalic: + frame->editor()->command("ToggleItalic").execute(); + break; + case ContextMenuItemTagUnderline: + frame->editor()->toggleUnderline(); + break; + case ContextMenuItemTagOutline: + // We actually never enable this because CSS does not have a way to specify an outline font, + // which may make this difficult to implement. Maybe a special case of text-shadow? + break; + case ContextMenuItemTagStartSpeaking: { + ExceptionCode ec; + RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange(); + if (!selectedRange || selectedRange->collapsed(ec)) { + Document* document = result.innerNonSharedNode()->document(); + selectedRange = document->createRange(); + selectedRange->selectNode(document->documentElement(), ec); + } + m_client->speak(plainText(selectedRange.get())); + break; + } + case ContextMenuItemTagStopSpeaking: + m_client->stopSpeaking(); + break; + case ContextMenuItemTagDefaultDirection: + frame->editor()->setBaseWritingDirection(NaturalWritingDirection); + break; + case ContextMenuItemTagLeftToRight: + frame->editor()->setBaseWritingDirection(LeftToRightWritingDirection); + break; + case ContextMenuItemTagRightToLeft: + frame->editor()->setBaseWritingDirection(RightToLeftWritingDirection); + break; + case ContextMenuItemTagTextDirectionDefault: + frame->editor()->command("MakeTextWritingDirectionNatural").execute(); + break; + case ContextMenuItemTagTextDirectionLeftToRight: + frame->editor()->command("MakeTextWritingDirectionLeftToRight").execute(); + break; + case ContextMenuItemTagTextDirectionRightToLeft: + frame->editor()->command("MakeTextWritingDirectionRightToLeft").execute(); + break; #if PLATFORM(MAC) - case ContextMenuItemTagSearchInSpotlight: - m_client->searchWithSpotlight(); - break; + case ContextMenuItemTagSearchInSpotlight: + m_client->searchWithSpotlight(); + break; #endif - case ContextMenuItemTagShowSpellingPanel: - frame->editor()->showSpellingGuessPanel(); - break; - case ContextMenuItemTagCheckSpelling: - frame->editor()->advanceToNextMisspelling(); - break; - case ContextMenuItemTagCheckSpellingWhileTyping: - frame->editor()->toggleContinuousSpellChecking(); - break; + case ContextMenuItemTagShowSpellingPanel: + frame->editor()->showSpellingGuessPanel(); + break; + case ContextMenuItemTagCheckSpelling: + frame->editor()->advanceToNextMisspelling(); + break; + case ContextMenuItemTagCheckSpellingWhileTyping: + frame->editor()->toggleContinuousSpellChecking(); + break; #ifndef BUILDING_ON_TIGER - case ContextMenuItemTagCheckGrammarWithSpelling: - frame->editor()->toggleGrammarChecking(); - break; + case ContextMenuItemTagCheckGrammarWithSpelling: + frame->editor()->toggleGrammarChecking(); + break; #endif #if PLATFORM(MAC) - case ContextMenuItemTagShowFonts: - frame->editor()->showFontPanel(); - break; - case ContextMenuItemTagStyles: - frame->editor()->showStylesPanel(); - break; - case ContextMenuItemTagShowColors: - frame->editor()->showColorPanel(); - break; + case ContextMenuItemTagShowFonts: + frame->editor()->showFontPanel(); + break; + case ContextMenuItemTagStyles: + frame->editor()->showStylesPanel(); + break; + case ContextMenuItemTagShowColors: + frame->editor()->showColorPanel(); + break; #endif #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) - case ContextMenuItemTagMakeUpperCase: - frame->editor()->uppercaseWord(); - break; - case ContextMenuItemTagMakeLowerCase: - frame->editor()->lowercaseWord(); - break; - case ContextMenuItemTagCapitalize: - frame->editor()->capitalizeWord(); - break; - case ContextMenuItemTagShowSubstitutions: - frame->editor()->showSubstitutionsPanel(); - break; - case ContextMenuItemTagSmartCopyPaste: - frame->editor()->toggleSmartInsertDelete(); - break; - case ContextMenuItemTagSmartQuotes: - frame->editor()->toggleAutomaticQuoteSubstitution(); - break; - case ContextMenuItemTagSmartDashes: - frame->editor()->toggleAutomaticDashSubstitution(); - break; - case ContextMenuItemTagSmartLinks: - frame->editor()->toggleAutomaticLinkDetection(); - break; - case ContextMenuItemTagTextReplacement: - frame->editor()->toggleAutomaticTextReplacement(); - break; - case ContextMenuItemTagCorrectSpellingAutomatically: - frame->editor()->toggleAutomaticSpellingCorrection(); - break; - case ContextMenuItemTagChangeBack: - frame->editor()->changeBackToReplacedString(result.replacedString()); - break; + case ContextMenuItemTagMakeUpperCase: + frame->editor()->uppercaseWord(); + break; + case ContextMenuItemTagMakeLowerCase: + frame->editor()->lowercaseWord(); + break; + case ContextMenuItemTagCapitalize: + frame->editor()->capitalizeWord(); + break; + case ContextMenuItemTagShowSubstitutions: + frame->editor()->showSubstitutionsPanel(); + break; + case ContextMenuItemTagSmartCopyPaste: + frame->editor()->toggleSmartInsertDelete(); + break; + case ContextMenuItemTagSmartQuotes: + frame->editor()->toggleAutomaticQuoteSubstitution(); + break; + case ContextMenuItemTagSmartDashes: + frame->editor()->toggleAutomaticDashSubstitution(); + break; + case ContextMenuItemTagSmartLinks: + frame->editor()->toggleAutomaticLinkDetection(); + break; + case ContextMenuItemTagTextReplacement: + frame->editor()->toggleAutomaticTextReplacement(); + break; + case ContextMenuItemTagCorrectSpellingAutomatically: + frame->editor()->toggleAutomaticSpellingCorrection(); + break; + case ContextMenuItemTagChangeBack: + frame->editor()->changeBackToReplacedString(result.replacedString()); + break; #endif - case ContextMenuItemTagInspectElement: - if (Page* page = frame->page()) - page->inspectorController()->inspect(result.innerNonSharedNode()); - break; - default: - break; + case ContextMenuItemTagInspectElement: + if (Page* page = frame->page()) + page->inspectorController()->inspect(result.innerNonSharedNode()); + break; + default: + break; } } diff --git a/WebCore/page/ContextMenuController.h b/WebCore/page/ContextMenuController.h index cb7e6ee..38095f6 100644 --- a/WebCore/page/ContextMenuController.h +++ b/WebCore/page/ContextMenuController.h @@ -37,7 +37,7 @@ namespace WebCore { class Event; class Page; - class ContextMenuController : Noncopyable { + class ContextMenuController : public Noncopyable { public: ContextMenuController(Page*, ContextMenuClient*); ~ContextMenuController(); diff --git a/WebCore/page/Coordinates.cpp b/WebCore/page/Coordinates.cpp index 637a8c2..728882a 100644 --- a/WebCore/page/Coordinates.cpp +++ b/WebCore/page/Coordinates.cpp @@ -31,7 +31,7 @@ namespace WebCore { String Coordinates::toString() const { return String::format("coordinate(%.6lg, %.6lg, %.6lg, %.6lg, %.6lg, %.6lg, %.6lg)", - m_latitude, m_longitude, m_altitude, m_accuracy, + m_latitude, m_longitude, m_altitude, m_accuracy, m_altitudeAccuracy, m_heading, m_speed); } diff --git a/WebCore/page/DOMSelection.cpp b/WebCore/page/DOMSelection.cpp index 3b54f02..0d21c56 100644 --- a/WebCore/page/DOMSelection.cpp +++ b/WebCore/page/DOMSelection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,15 +32,26 @@ #include "ExceptionCode.h" #include "Frame.h" -#include "htmlediting.h" #include "Node.h" #include "PlatformString.h" #include "Range.h" #include "SelectionController.h" #include "TextIterator.h" +#include "htmlediting.h" namespace WebCore { +static Node* selectionShadowAncestor(Frame* frame) +{ + Node* node = frame->selection()->selection().base().anchorNode(); + if (!node) + return 0; + Node* shadowAncestor = node->shadowAncestorNode(); + if (shadowAncestor == node) + return 0; + return shadowAncestor; +} + DOMSelection::DOMSelection(Frame* frame) : m_frame(frame) { @@ -88,6 +99,8 @@ Node* DOMSelection::anchorNode() const { if (!m_frame) return 0; + if (Node* shadowAncestor = selectionShadowAncestor(m_frame)) + return shadowAncestor->parentNode(); return anchorPosition(visibleSelection()).node(); } @@ -95,6 +108,8 @@ int DOMSelection::anchorOffset() const { if (!m_frame) return 0; + if (Node* shadowAncestor = selectionShadowAncestor(m_frame)) + return shadowAncestor->nodeIndex(); return anchorPosition(visibleSelection()).deprecatedEditingOffset(); } @@ -102,6 +117,8 @@ Node* DOMSelection::focusNode() const { if (!m_frame) return 0; + if (Node* shadowAncestor = selectionShadowAncestor(m_frame)) + return shadowAncestor->parentNode(); return focusPosition(visibleSelection()).node(); } @@ -109,6 +126,8 @@ int DOMSelection::focusOffset() const { if (!m_frame) return 0; + if (Node* shadowAncestor = selectionShadowAncestor(m_frame)) + return shadowAncestor->nodeIndex(); return focusPosition(visibleSelection()).deprecatedEditingOffset(); } @@ -116,6 +135,8 @@ Node* DOMSelection::baseNode() const { if (!m_frame) return 0; + if (Node* shadowAncestor = selectionShadowAncestor(m_frame)) + return shadowAncestor->parentNode(); return basePosition(visibleSelection()).node(); } @@ -123,14 +144,17 @@ int DOMSelection::baseOffset() const { if (!m_frame) return 0; + if (Node* shadowAncestor = selectionShadowAncestor(m_frame)) + return shadowAncestor->nodeIndex(); return basePosition(visibleSelection()).deprecatedEditingOffset(); } - Node* DOMSelection::extentNode() const { if (!m_frame) return 0; + if (Node* shadowAncestor = selectionShadowAncestor(m_frame)) + return shadowAncestor->parentNode(); return extentPosition(visibleSelection()).node(); } @@ -138,13 +162,15 @@ int DOMSelection::extentOffset() const { if (!m_frame) return 0; + if (Node* shadowAncestor = selectionShadowAncestor(m_frame)) + return shadowAncestor->nodeIndex(); return extentPosition(visibleSelection()).deprecatedEditingOffset(); } bool DOMSelection::isCollapsed() const { - if (!m_frame) - return false; + if (!m_frame || selectionShadowAncestor(m_frame)) + return true; return !m_frame->selection()->isRange(); } @@ -206,7 +232,7 @@ void DOMSelection::empty() { if (!m_frame) return; - m_frame->selection()->moveTo(VisiblePosition()); + m_frame->selection()->clear(); } void DOMSelection::setBaseAndExtent(Node* baseNode, int baseOffset, Node* extentNode, int extentOffset, ExceptionCode& ec) @@ -220,7 +246,7 @@ void DOMSelection::setBaseAndExtent(Node* baseNode, int baseOffset, Node* extent } VisiblePosition visibleBase = VisiblePosition(baseNode, baseOffset, DOWNSTREAM); VisiblePosition visibleExtent = VisiblePosition(extentNode, extentOffset, DOWNSTREAM); - + m_frame->selection()->moveTo(visibleBase, visibleExtent); } @@ -245,9 +271,9 @@ void DOMSelection::modify(const String& alterString, const String& directionStri alter = SelectionController::EXTEND; else if (equalIgnoringCase(alterString, "move")) alter = SelectionController::MOVE; - else + else return; - + SelectionController::EDirection direction; if (equalIgnoringCase(directionString, "forward")) direction = SelectionController::FORWARD; @@ -259,7 +285,7 @@ void DOMSelection::modify(const String& alterString, const String& directionStri direction = SelectionController::RIGHT; else return; - + TextGranularity granularity; if (equalIgnoringCase(granularityString, "character")) granularity = CharacterGranularity; @@ -317,6 +343,12 @@ PassRefPtr<Range> DOMSelection::getRangeAt(int index, ExceptionCode& ec) // If you're hitting this, you've added broken multi-range selection support ASSERT(rangeCount() == 1); + if (Node* shadowAncestor = selectionShadowAncestor(m_frame)) { + Node* container = shadowAncestor->parentNode(); + int offset = shadowAncestor->nodeIndex(); + return Range::create(shadowAncestor->document(), container, offset, container, offset); + } + const VisibleSelection& selection = m_frame->selection()->selection(); return selection.firstRange(); } @@ -336,7 +368,7 @@ void DOMSelection::addRange(Range* r) return; SelectionController* selection = m_frame->selection(); - + if (selection->isNone()) { selection->setSelection(VisibleSelection(r)); return; @@ -385,7 +417,7 @@ void DOMSelection::deleteFromDocument() ExceptionCode ec = 0; selectedRange->deleteContents(ec); ASSERT(!ec); - + setBaseAndExtent(selectedRange->startContainer(ec), selectedRange->startOffset(ec), selectedRange->startContainer(ec), selectedRange->startOffset(ec), ec); ASSERT(!ec); } diff --git a/WebCore/page/DOMSelection.h b/WebCore/page/DOMSelection.h index 6a914d6..e0fe1e3 100644 --- a/WebCore/page/DOMSelection.h +++ b/WebCore/page/DOMSelection.h @@ -30,9 +30,9 @@ #ifndef DOMSelection_h #define DOMSelection_h -#include <wtf/RefCounted.h> #include <wtf/Forward.h> #include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> namespace WebCore { diff --git a/WebCore/page/DOMTimer.cpp b/WebCore/page/DOMTimer.cpp index 1cc7730..c42a0dc 100644 --- a/WebCore/page/DOMTimer.cpp +++ b/WebCore/page/DOMTimer.cpp @@ -54,7 +54,7 @@ DOMTimer::DOMTimer(ScriptExecutionContext* context, ScheduledAction* action, int if (lastUsedTimeoutId <= 0) lastUsedTimeoutId = 1; m_timeoutId = lastUsedTimeoutId; - + m_nestingLevel = timerNestingLevel + 1; scriptExecutionContext()->addTimeout(m_timeoutId, this); @@ -74,11 +74,10 @@ DOMTimer::DOMTimer(ScriptExecutionContext* context, ScheduledAction* action, int DOMTimer::~DOMTimer() { - if (scriptExecutionContext()) { + if (scriptExecutionContext()) scriptExecutionContext()->removeTimeout(m_timeoutId); - } } - + int DOMTimer::install(ScriptExecutionContext* context, ScheduledAction* action, int timeout, bool singleShot) { // DOMTimer constructor links the new timer into a list of ActiveDOMObjects held by the 'context'. @@ -110,7 +109,7 @@ void DOMTimer::fired() if (m_nestingLevel >= maxTimerNestingLevel) augmentRepeatInterval(s_minTimerInterval - repeatInterval()); } - + // No access to member variables after this point, it can delete the timer. m_action->execute(context); return; @@ -121,7 +120,7 @@ void DOMTimer::fired() // No access to member variables after this point. delete this; - + action->execute(context); delete action; timerNestingLevel = 0; @@ -147,24 +146,24 @@ void DOMTimer::stop() m_action.clear(); } -void DOMTimer::suspend() -{ - ASSERT(m_nextFireInterval == 0 && m_repeatInterval == 0); +void DOMTimer::suspend() +{ + ASSERT(!m_nextFireInterval && !m_repeatInterval); m_nextFireInterval = nextFireInterval(); m_repeatInterval = repeatInterval(); TimerBase::stop(); -} - -void DOMTimer::resume() -{ +} + +void DOMTimer::resume() +{ start(m_nextFireInterval, m_repeatInterval); m_nextFireInterval = 0; m_repeatInterval = 0; -} - - -bool DOMTimer::canSuspend() const -{ +} + + +bool DOMTimer::canSuspend() const +{ return true; } diff --git a/WebCore/page/DOMTimer.h b/WebCore/page/DOMTimer.h index f6343fc..6d6271f 100644 --- a/WebCore/page/DOMTimer.h +++ b/WebCore/page/DOMTimer.h @@ -33,41 +33,41 @@ namespace WebCore { -class ScheduledAction; + class ScheduledAction; -class DOMTimer : public TimerBase, public ActiveDOMObject { -public: - virtual ~DOMTimer(); - // Creates a new timer owned by specified ScriptExecutionContext, starts it - // and returns its Id. - static int install(ScriptExecutionContext*, ScheduledAction*, int timeout, bool singleShot); - static void removeById(ScriptExecutionContext*, int timeoutId); + class DOMTimer : public TimerBase, public ActiveDOMObject { + public: + virtual ~DOMTimer(); + // Creates a new timer owned by specified ScriptExecutionContext, starts it + // and returns its Id. + static int install(ScriptExecutionContext*, ScheduledAction*, int timeout, bool singleShot); + static void removeById(ScriptExecutionContext*, int timeoutId); - // ActiveDOMObject - virtual bool hasPendingActivity() const; - virtual void contextDestroyed(); - virtual void stop(); - virtual bool canSuspend() const; - virtual void suspend(); - virtual void resume(); + // ActiveDOMObject + virtual bool hasPendingActivity() const; + virtual void contextDestroyed(); + virtual void stop(); + virtual bool canSuspend() const; + virtual void suspend(); + virtual void resume(); - // The lowest allowable timer setting (in seconds, 0.001 == 1 ms). - // Default is 10ms. - // Chromium uses a non-default timeout. - static double minTimerInterval() { return s_minTimerInterval; } - static void setMinTimerInterval(double value) { s_minTimerInterval = value; } + // The lowest allowable timer setting (in seconds, 0.001 == 1 ms). + // Default is 10ms. + // Chromium uses a non-default timeout. + static double minTimerInterval() { return s_minTimerInterval; } + static void setMinTimerInterval(double value) { s_minTimerInterval = value; } -private: - DOMTimer(ScriptExecutionContext*, ScheduledAction*, int timeout, bool singleShot); - virtual void fired(); + private: + DOMTimer(ScriptExecutionContext*, ScheduledAction*, int timeout, bool singleShot); + virtual void fired(); - int m_timeoutId; - int m_nestingLevel; - OwnPtr<ScheduledAction> m_action; - double m_nextFireInterval; - double m_repeatInterval; - static double s_minTimerInterval; -}; + int m_timeoutId; + int m_nestingLevel; + OwnPtr<ScheduledAction> m_action; + double m_nextFireInterval; + double m_repeatInterval; + static double s_minTimerInterval; + }; } // namespace WebCore diff --git a/WebCore/page/DOMWindow.cpp b/WebCore/page/DOMWindow.cpp index b4f3dee..e50b488 100644 --- a/WebCore/page/DOMWindow.cpp +++ b/WebCore/page/DOMWindow.cpp @@ -51,6 +51,7 @@ #include "History.h" #include "InspectorController.h" #include "Location.h" +#include "Media.h" #include "MessageEvent.h" #include "Navigator.h" #include "Page.h" @@ -70,10 +71,9 @@ #endif #if ENABLE(DOM_STORAGE) -#include "LocalStorage.h" -#include "SessionStorage.h" #include "Storage.h" #include "StorageArea.h" +#include "StorageNamespace.h" #endif #if ENABLE(OFFLINE_WEB_APPLICATIONS) @@ -87,14 +87,25 @@ namespace WebCore { class PostMessageTimer : public TimerBase { public: - PostMessageTimer(DOMWindow* window, PassRefPtr<MessageEvent> event, SecurityOrigin* targetOrigin) + PostMessageTimer(DOMWindow* window, const String& message, const String& sourceOrigin, PassRefPtr<DOMWindow> source, PassOwnPtr<MessagePortChannel> channel, SecurityOrigin* targetOrigin) : m_window(window) - , m_event(event) + , m_message(message) + , m_origin(sourceOrigin) + , m_source(source) + , m_channel(channel) , m_targetOrigin(targetOrigin) { } - MessageEvent* event() const { return m_event.get(); } + PassRefPtr<MessageEvent> event(ScriptExecutionContext* context) + { + RefPtr<MessagePort> messagePort; + if (m_channel) { + messagePort = MessagePort::create(*context); + messagePort->entangle(m_channel.release()); + } + return MessageEvent::create(m_message, m_origin, "", m_source, messagePort.release()); + } SecurityOrigin* targetOrigin() const { return m_targetOrigin.get(); } private: @@ -104,7 +115,10 @@ private: } RefPtr<DOMWindow> m_window; - RefPtr<MessageEvent> m_event; + String m_message; + String m_origin; + RefPtr<DOMWindow> m_source; + OwnPtr<MessagePortChannel> m_channel; RefPtr<SecurityOrigin> m_targetOrigin; }; @@ -508,7 +522,7 @@ Console* DOMWindow::console() const #if ENABLE(OFFLINE_WEB_APPLICATIONS) DOMApplicationCache* DOMWindow::applicationCache() const { - if (!m_applicationCache) + if (!m_applicationCache && m_frame && m_frame->settings() && m_frame->settings()->offlineWebApplicationCacheEnabled()) m_applicationCache = DOMApplicationCache::create(m_frame); return m_applicationCache.get(); } @@ -533,12 +547,17 @@ Storage* DOMWindow::sessionStorage() const { if (m_sessionStorage) return m_sessionStorage.get(); - - Page* page = m_frame->page(); + + Document* document = this->document(); + if (!document) + return 0; + + Page* page = document->page(); if (!page) return 0; - Document* document = m_frame->document(); + if (!page->settings()->sessionStorageEnabled()) + return 0; RefPtr<StorageArea> storageArea = page->sessionStorage()->storageArea(document->securityOrigin()); page->inspectorController()->didUseDOMStorage(storageArea.get(), false, m_frame); @@ -560,11 +579,10 @@ Storage* DOMWindow::localStorage() const if (!page) return 0; - Settings* settings = document->settings(); - if (!settings || !settings->localStorageEnabled()) + if (!page->settings()->localStorageEnabled()) return 0; - LocalStorage* localStorage = page->group().localStorage(); + StorageNamespace* localStorage = page->group().localStorage(); RefPtr<StorageArea> storageArea = localStorage ? localStorage->storageArea(document->securityOrigin()) : 0; if (storageArea) { page->inspectorController()->didUseDOMStorage(storageArea.get(), true, m_frame); @@ -591,9 +609,9 @@ void DOMWindow::postMessage(const String& message, MessagePort* messagePort, con } } - RefPtr<MessagePort> newMessagePort; + OwnPtr<MessagePortChannel> channel; if (messagePort) - newMessagePort = messagePort->clone(ec); + channel = messagePort->disentangle(ec); if (ec) return; @@ -605,7 +623,7 @@ void DOMWindow::postMessage(const String& message, MessagePort* messagePort, con String sourceOrigin = sourceDocument->securityOrigin()->toString(); // Schedule the message. - PostMessageTimer* timer = new PostMessageTimer(this, MessageEvent::create(message, sourceOrigin, "", source, newMessagePort), target.get()); + PostMessageTimer* timer = new PostMessageTimer(this, message, sourceOrigin, source, channel.release(), target.get()); timer->startOneShot(0); } @@ -621,18 +639,13 @@ void DOMWindow::postMessageTimerFired(PostMessageTimer* t) if (!timer->targetOrigin()->isSameSchemeHostPort(document()->securityOrigin())) { String message = String::format("Unable to post message to %s. Recipient has origin %s.\n", timer->targetOrigin()->toString().utf8().data(), document()->securityOrigin()->toString().utf8().data()); - console()->addMessage(JSMessageSource, ErrorMessageLevel, message, 0, String()); + console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, 0, String()); return; } } - MessagePort* messagePort = timer->event()->messagePort(); - ASSERT(!messagePort || !messagePort->scriptExecutionContext()); - if (messagePort) - messagePort->attachToContext(document()); - ExceptionCode ec = 0; - dispatchEvent(timer->event(), ec); + dispatchEvent(timer->event(document()), ec); } DOMSelection* DOMWindow::getSelection() @@ -997,6 +1010,11 @@ Document* DOMWindow::document() const return m_frame->document(); } +PassRefPtr<Media> DOMWindow::media() const +{ + return Media::create(const_cast<DOMWindow*>(this)); +} + PassRefPtr<CSSStyleDeclaration> DOMWindow::getComputedStyle(Element* elt, const String&) const { if (!elt) diff --git a/WebCore/page/DOMWindow.h b/WebCore/page/DOMWindow.h index 7d97445..12caf7e 100644 --- a/WebCore/page/DOMWindow.h +++ b/WebCore/page/DOMWindow.h @@ -52,6 +52,7 @@ namespace WebCore { class Frame; class History; class Location; + class Media; class MessagePort; class Navigator; class Node; @@ -61,7 +62,6 @@ namespace WebCore { class WebKitPoint; #if ENABLE(DOM_STORAGE) - class SessionStorage; class Storage; #endif @@ -175,6 +175,8 @@ namespace WebCore { // DOM Level 2 AbstractView Interface Document* document() const; + // CSSOM View Module + PassRefPtr<Media> media() const; // DOM Level 2 Style Interface PassRefPtr<CSSStyleDeclaration> getComputedStyle(Element*, const String& pseudoElt) const; @@ -383,7 +385,7 @@ namespace WebCore { void captureEvents(); void releaseEvents(); - // These methods are used for GC marking. See JSDOMWindow::mark() in + // These methods are used for GC marking. See JSDOMWindow::markChildren(MarkStack&) in // JSDOMWindowCustom.cpp. Screen* optionalScreen() const { return m_screen.get(); } DOMSelection* optionalSelection() const { return m_selection.get(); } diff --git a/WebCore/page/DOMWindow.idl b/WebCore/page/DOMWindow.idl index 612ae42..aba92f0 100644 --- a/WebCore/page/DOMWindow.idl +++ b/WebCore/page/DOMWindow.idl @@ -136,12 +136,15 @@ module window { attribute [Replaceable, DoNotCheckDomainSecurityOnGet] DOMWindow frames; attribute [Replaceable, DoNotCheckDomainSecurityOnGet, V8CustomSetter] DOMWindow opener; - attribute [Replaceable, DoNotCheckDomainSecurity] DOMWindow parent; - attribute [Replaceable, DoNotCheckDomainSecurity, V8DisallowShadowing, V8ReadOnly] DOMWindow top; + attribute [Replaceable, DoNotCheckDomainSecurityOnGet] DOMWindow parent; + attribute [Replaceable, DoNotCheckDomainSecurityOnGet, V8DisallowShadowing, V8ReadOnly] DOMWindow top; // DOM Level 2 AbstractView Interface readonly attribute Document document; + // CSSOM View Module + readonly attribute Media media; + // DOM Level 2 Style Interface CSSStyleDeclaration getComputedStyle(in Element element, in DOMString pseudoElement); @@ -257,7 +260,6 @@ module window { // Not implemented yet. // attribute EventListener onafterprint; // attribute EventListener onbeforeprint; - // attribute EventListener ondataunavailable; // attribute EventListener onformchange; // attribute EventListener onforminput; // attribute EventListener onhashchange; @@ -315,11 +317,12 @@ module window { attribute CounterConstructor Counter; attribute CSSRuleListConstructor CSSRuleList; attribute RectConstructor Rect; + attribute RGBColorConstructor RGBColor; attribute StyleSheetListConstructor StyleSheetList; // FIXME: Implement the commented-out global constructors for interfaces listed in DOM Level 3 Core specification. attribute DOMCoreExceptionConstructor DOMException; - attribute DOMStringListConstructor DOMStringList; +// attribute DOMStringListConstructor DOMStringList; // attribute NameListConstructor NameList; // attribute DOMImplementationListConstructor DOMImplementationList; // attribute DOMImplementationSourceConstructor DOMImplementationSource; @@ -360,6 +363,9 @@ module window { attribute HTMLBodyElementConstructor HTMLBodyElement; attribute HTMLButtonElementConstructor HTMLButtonElement; attribute HTMLCanvasElementConstructor HTMLCanvasElement; + attribute [Conditional=DATAGRID] HTMLDataGridElementConstructor HTMLDataGridElement; + attribute [Conditional=DATAGRID] HTMLDataGridCellElementConstructor HTMLDataGridCellElement; + attribute [Conditional=DATAGRID] HTMLDataGridColElementConstructor HTMLDataGridColElement; attribute HTMLDListElementConstructor HTMLDListElement; attribute HTMLDirectoryElementConstructor HTMLDirectoryElement; attribute HTMLDivElementConstructor HTMLDivElement; @@ -472,6 +478,10 @@ module window { attribute [JSCCustomGetter] WorkerConstructor Worker; // Usable with the new operator #endif +#if defined(ENABLE_SHARED_WORKERS) && ENABLE_SHARED_WORKERS + attribute [JSCCustomGetter] SharedWorkerConstructor SharedWorker; // Usable with the new operator +#endif + attribute PluginConstructor Plugin; attribute PluginArrayConstructor PluginArray; diff --git a/WebCore/page/DragController.cpp b/WebCore/page/DragController.cpp index e1b5ea7..08fb872 100644 --- a/WebCore/page/DragController.cpp +++ b/WebCore/page/DragController.cpp @@ -72,7 +72,7 @@ static PlatformMouseEvent createMouseEvent(DragData* dragData) LeftButton, MouseEventMoved, 0, false, false, false, false, currentTime()); } - + DragController::DragController(Page* page, DragClient* client) : m_page(page) , m_client(client) @@ -85,12 +85,12 @@ DragController::DragController(Page* page, DragClient* client) , m_sourceDragOperation(DragOperationNone) { } - + DragController::~DragController() -{ +{ m_client->dragControllerDestroyed(); } - + static PassRefPtr<DocumentFragment> documentFragmentFromDragData(DragData* dragData, RefPtr<Range> context, bool allowPlainText, bool& chosePlainText) { @@ -122,7 +122,7 @@ static PassRefPtr<DocumentFragment> documentFragmentFromDragData(DragData* dragD chosePlainText = true; return createFragmentFromText(context.get(), dragData->asPlainText()).get(); } - + return 0; } @@ -140,20 +140,20 @@ void DragController::cancelDrag() void DragController::dragEnded() { m_dragInitiator = 0; - m_didInitiateDrag = false; - m_page->dragCaretController()->clear(); -} + m_didInitiateDrag = false; + m_page->dragCaretController()->clear(); +} -DragOperation DragController::dragEntered(DragData* dragData) +DragOperation DragController::dragEntered(DragData* dragData) { return dragEnteredOrUpdated(dragData); } - -void DragController::dragExited(DragData* dragData) -{ + +void DragController::dragExited(DragData* dragData) +{ ASSERT(dragData); Frame* mainFrame = m_page->mainFrame(); - + if (RefPtr<FrameView> v = mainFrame->view()) { ClipboardAccessPolicy policy = (!m_documentUnderMouse || m_documentUnderMouse->securityOrigin()->isLocal()) ? ClipboardReadable : ClipboardTypesReadable; RefPtr<Clipboard> clipboard = dragData->createClipboard(policy); @@ -164,14 +164,13 @@ void DragController::dragExited(DragData* dragData) mouseMovedIntoDocument(0); } - -DragOperation DragController::dragUpdated(DragData* dragData) +DragOperation DragController::dragUpdated(DragData* dragData) { return dragEnteredOrUpdated(dragData); } - + bool DragController::performDrag(DragData* dragData) -{ +{ ASSERT(dragData); m_documentUnderMouse = m_page->mainFrame()->documentAtPoint(dragData->clientPosition()); if (m_isHandlingDrag) { @@ -187,13 +186,13 @@ bool DragController::performDrag(DragData* dragData) } m_documentUnderMouse = 0; return true; - } - + } + if ((m_dragDestinationAction & DragDestinationActionEdit) && concludeEditDrag(dragData)) { m_documentUnderMouse = 0; return true; } - + m_documentUnderMouse = 0; if (operationForLoad(dragData) == DragOperationNone) @@ -222,60 +221,72 @@ DragOperation DragController::dragEnteredOrUpdated(DragData* dragData) mouseMovedIntoDocument(m_page->mainFrame()->documentAtPoint(dragData->clientPosition())); m_dragDestinationAction = m_client->actionMaskForDrag(dragData); - - DragOperation operation = DragOperationNone; - - if (m_dragDestinationAction == DragDestinationActionNone) + if (m_dragDestinationAction == DragDestinationActionNone) { cancelDrag(); // FIXME: Why not call mouseMovedIntoDocument(0)? - else { - operation = tryDocumentDrag(dragData, m_dragDestinationAction); - if (operation == DragOperationNone && (m_dragDestinationAction & DragDestinationActionLoad)) - return operationForLoad(dragData); + return DragOperationNone; } - + + DragOperation operation = DragOperationNone; + bool handledByDocument = tryDocumentDrag(dragData, m_dragDestinationAction, operation); + if (!handledByDocument && (m_dragDestinationAction & DragDestinationActionLoad)) + return operationForLoad(dragData); return operation; } static HTMLInputElement* asFileInput(Node* node) { ASSERT(node); - + // The button for a FILE input is a sub element with no set input type // In order to get around this problem we assume any non-FILE input element // is this internal button, and try querying the shadow parent node. if (node->hasTagName(HTMLNames::inputTag) && node->isShadowNode() && static_cast<HTMLInputElement*>(node)->inputType() != HTMLInputElement::FILE) node = node->shadowParentNode(); - + if (!node || !node->hasTagName(HTMLNames::inputTag)) return 0; - + HTMLInputElement* inputElem = static_cast<HTMLInputElement*>(node); if (inputElem->inputType() == HTMLInputElement::FILE) return inputElem; - + return 0; } - -DragOperation DragController::tryDocumentDrag(DragData* dragData, DragDestinationAction actionMask) + +bool DragController::tryDocumentDrag(DragData* dragData, DragDestinationAction actionMask, DragOperation& operation) { ASSERT(dragData); - + if (!m_documentUnderMouse) - return DragOperationNone; - - DragOperation operation = DragOperationNone; - if (actionMask & DragDestinationActionDHTML) - operation = tryDHTMLDrag(dragData); - m_isHandlingDrag = operation != DragOperationNone; + return false; + m_isHandlingDrag = false; + if (actionMask & DragDestinationActionDHTML) { + m_isHandlingDrag = tryDHTMLDrag(dragData, operation); + // Do not continue if m_documentUnderMouse has been reset by tryDHTMLDrag. + // tryDHTMLDrag fires dragenter event. The event listener that listens + // to this event may create a nested message loop (open a modal dialog), + // which could process dragleave event and reset m_documentUnderMouse in + // dragExited. + if (!m_documentUnderMouse) + return false; + } + + // It's unclear why this check is after tryDHTMLDrag. + // We send drag events in tryDHTMLDrag and that may be the reason. RefPtr<FrameView> frameView = m_documentUnderMouse->view(); if (!frameView) - return operation; - - if ((actionMask & DragDestinationActionEdit) && !m_isHandlingDrag && canProcessDrag(dragData)) { - if (dragData->containsColor()) - return DragOperationGeneric; - + return false; + + if (m_isHandlingDrag) { + m_page->dragCaretController()->clear(); + return true; + } else if ((actionMask & DragDestinationActionEdit) && canProcessDrag(dragData)) { + if (dragData->containsColor()) { + operation = DragOperationGeneric; + return true; + } + IntPoint dragPos = dragData->clientPosition(); IntPoint point = frameView->windowToContents(dragPos); Element* element = m_documentUnderMouse->elementFromPoint(point.x(), point.y()); @@ -286,19 +297,20 @@ DragOperation DragController::tryDocumentDrag(DragData* dragData, DragDestinatio } Frame* innerFrame = element->document()->frame(); - return dragIsMove(innerFrame->selection()) ? DragOperationMove : DragOperationCopy; - } - + operation = dragIsMove(innerFrame->selection()) ? DragOperationMove : DragOperationCopy; + return true; + } + // If we're not over an editable region, make sure we're clearing any prior drag cursor. m_page->dragCaretController()->clear(); - return operation; + return false; } DragSourceAction DragController::delegateDragSourceAction(const IntPoint& windowPoint) -{ +{ m_dragSourceAction = m_client->dragSourceActionMaskForPoint(windowPoint); return m_dragSourceAction; } - + DragOperation DragController::operationForLoad(DragData* dragData) { ASSERT(dragData); @@ -323,15 +335,15 @@ bool DragController::concludeEditDrag(DragData* dragData) { ASSERT(dragData); ASSERT(!m_isHandlingDrag); - + if (!m_documentUnderMouse) return false; - + IntPoint point = m_documentUnderMouse->view()->windowToContents(dragData->clientPosition()); Element* element = m_documentUnderMouse->elementFromPoint(point.x(), point.y()); ASSERT(element); Frame* innerFrame = element->ownerDocument()->frame(); - ASSERT(innerFrame); + ASSERT(innerFrame); if (dragData->containsColor()) { Color color = dragData->asColor(); @@ -349,32 +361,31 @@ bool DragController::concludeEditDrag(DragData* dragData) innerFrame->editor()->applyStyle(style.get(), EditActionSetColor); return true; } - + if (!m_page->dragController()->canProcessDrag(dragData)) { m_page->dragCaretController()->clear(); return false; } - + if (HTMLInputElement* fileInput = asFileInput(element)) { if (!fileInput->isEnabledFormControl()) return false; - + if (!dragData->containsFiles()) return false; - + Vector<String> filenames; dragData->asFilenames(filenames); if (filenames.isEmpty()) return false; - - // Ugly. For security none of the API's available to us to set the input value - // on file inputs. Even forcing a change in HTMLInputElement doesn't work as - // RenderFileUploadControl clears the file when doing updateFromElement() - RenderFileUploadControl* renderer = static_cast<RenderFileUploadControl*>(fileInput->renderer()); - + + // Ugly. For security none of the APIs available to us can set the input value + // on file inputs. Even forcing a change in HTMLInputElement doesn't work as + // RenderFileUploadControl clears the file when doing updateFromElement(). + RenderFileUploadControl* renderer = toRenderFileUploadControl(fileInput->renderer()); if (!renderer) return false; - + renderer->receiveDroppedFiles(filenames); return true; } @@ -382,114 +393,121 @@ bool DragController::concludeEditDrag(DragData* dragData) VisibleSelection dragCaret(m_page->dragCaretController()->selection()); m_page->dragCaretController()->clear(); RefPtr<Range> range = dragCaret.toNormalizedRange(); - + // For range to be null a WebKit client must have done something bad while // manually controlling drag behaviour - if (!range) + if (!range) return false; DocLoader* loader = range->ownerDocument()->docLoader(); loader->setAllowStaleResources(true); - if (dragIsMove(innerFrame->selection()) || dragCaret.isContentRichlyEditable()) { + if (dragIsMove(innerFrame->selection()) || dragCaret.isContentRichlyEditable()) { bool chosePlainText = false; RefPtr<DocumentFragment> fragment = documentFragmentFromDragData(dragData, range, true, chosePlainText); if (!fragment || !innerFrame->editor()->shouldInsertFragment(fragment, range, EditorInsertActionDropped)) { loader->setAllowStaleResources(false); return false; } - + m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData); if (dragIsMove(innerFrame->selection())) { - bool smartMove = innerFrame->selectionGranularity() == WordGranularity - && innerFrame->editor()->smartInsertDeleteEnabled() + bool smartMove = innerFrame->selectionGranularity() == WordGranularity + && innerFrame->editor()->smartInsertDeleteEnabled() && dragData->canSmartReplace(); applyCommand(MoveSelectionCommand::create(fragment, dragCaret.base(), smartMove)); } else { if (setSelectionToDragCaret(innerFrame, dragCaret, range, point)) - applyCommand(ReplaceSelectionCommand::create(m_documentUnderMouse, fragment, true, dragData->canSmartReplace(), chosePlainText)); - } + applyCommand(ReplaceSelectionCommand::create(m_documentUnderMouse, fragment, true, dragData->canSmartReplace(), chosePlainText)); + } } else { String text = dragData->asPlainText(); if (text.isEmpty() || !innerFrame->editor()->shouldInsertText(text, range.get(), EditorInsertActionDropped)) { loader->setAllowStaleResources(false); return false; } - + m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData); if (setSelectionToDragCaret(innerFrame, dragCaret, range, point)) - applyCommand(ReplaceSelectionCommand::create(m_documentUnderMouse, createFragmentFromText(range.get(), text), true, false, true)); + applyCommand(ReplaceSelectionCommand::create(m_documentUnderMouse, createFragmentFromText(range.get(), text), true, false, true)); } loader->setAllowStaleResources(false); return true; } - - -bool DragController::canProcessDrag(DragData* dragData) + +bool DragController::canProcessDrag(DragData* dragData) { ASSERT(dragData); if (!dragData->containsCompatibleContent()) return false; - + IntPoint point = m_page->mainFrame()->view()->windowToContents(dragData->clientPosition()); HitTestResult result = HitTestResult(point); if (!m_page->mainFrame()->contentRenderer()) return false; result = m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, true); - - if (!result.innerNonSharedNode()) + + if (!result.innerNonSharedNode()) return false; - + if (dragData->containsFiles() && asFileInput(result.innerNonSharedNode())) return true; - + if (!result.innerNonSharedNode()->isContentEditable()) return false; - + if (m_didInitiateDrag && m_documentUnderMouse == m_dragInitiator && result.isSelected()) return false; return true; } -DragOperation DragController::tryDHTMLDrag(DragData* dragData) -{ +static DragOperation defaultOperationForDrag(DragOperation srcOpMask) +{ + // This is designed to match IE's operation fallback for the case where + // the page calls preventDefault() in a drag event but doesn't set dropEffect. + if (srcOpMask & DragOperationCopy) + return DragOperationCopy; + if (srcOpMask & DragOperationMove || srcOpMask & DragOperationGeneric) + return DragOperationMove; + if (srcOpMask & DragOperationLink) + return DragOperationLink; + + // FIXME: Does IE really return "generic" even if no operations were allowed by the source? + return DragOperationGeneric; +} + +bool DragController::tryDHTMLDrag(DragData* dragData, DragOperation& operation) +{ ASSERT(dragData); ASSERT(m_documentUnderMouse); - DragOperation op = DragOperationNone; RefPtr<Frame> mainFrame = m_page->mainFrame(); RefPtr<FrameView> viewProtector = mainFrame->view(); if (!viewProtector) - return DragOperationNone; - + return false; + ClipboardAccessPolicy policy = m_documentUnderMouse->securityOrigin()->isLocal() ? ClipboardReadable : ClipboardTypesReadable; RefPtr<Clipboard> clipboard = dragData->createClipboard(policy); - DragOperation srcOp = dragData->draggingSourceOperationMask(); - clipboard->setSourceOperation(srcOp); - - PlatformMouseEvent event = createMouseEvent(dragData); - if (mainFrame->eventHandler()->updateDragAndDrop(event, clipboard.get())) { - // *op unchanged if no source op was set - if (!clipboard->destinationOperation(op)) { - // The element accepted but they didn't pick an operation, so we pick one for them - // (as does WinIE). - if (srcOp & DragOperationCopy) - op = DragOperationCopy; - else if (srcOp & DragOperationMove || srcOp & DragOperationGeneric) - op = DragOperationMove; - else if (srcOp & DragOperationLink) - op = DragOperationLink; - else - op = DragOperationGeneric; - } else if (!(op & srcOp)) { - op = DragOperationNone; - } + DragOperation srcOpMask = dragData->draggingSourceOperationMask(); + clipboard->setSourceOperation(srcOpMask); + PlatformMouseEvent event = createMouseEvent(dragData); + if (!mainFrame->eventHandler()->updateDragAndDrop(event, clipboard.get())) { clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard here for security - return op; + return false; } - return op; + + if (!clipboard->destinationOperation(operation)) { + // The element accepted but they didn't pick an operation, so we pick one (to match IE). + operation = defaultOperationForDrag(srcOpMask); + } else if (!(srcOpMask & operation)) { + // The element picked an operation which is not supported by the source + operation = DragOperationNone; + } + + clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard here for security + return true; } bool DragController::mayStartDragAtEventLocation(const Frame* frame, const IntPoint& framePos) @@ -504,7 +522,7 @@ bool DragController::mayStartDragAtEventLocation(const Frame* frame, const IntPo mouseDownTarget = frame->eventHandler()->hitTestResultAtPoint(framePos, true); - if (mouseDownTarget.image() + if (mouseDownTarget.image() && !mouseDownTarget.absoluteImageURL().isEmpty() && frame->settings()->loadsImagesAutomatically() && m_dragSourceAction & DragSourceActionImage) @@ -522,56 +540,56 @@ bool DragController::mayStartDragAtEventLocation(const Frame* frame, const IntPo return false; } - + static CachedImage* getCachedImage(Element* element) { ASSERT(element); RenderObject* renderer = element->renderer(); - if (!renderer || !renderer->isImage()) + if (!renderer || !renderer->isImage()) return 0; RenderImage* image = toRenderImage(renderer); return image->cachedImage(); } - + static Image* getImage(Element* element) { ASSERT(element); RenderObject* renderer = element->renderer(); - if (!renderer || !renderer->isImage()) + if (!renderer || !renderer->isImage()) return 0; - + RenderImage* image = toRenderImage(renderer); if (image->cachedImage() && !image->cachedImage()->errorOccurred()) return image->cachedImage()->image(); return 0; } - + static void prepareClipboardForImageDrag(Frame* src, Clipboard* clipboard, Element* node, const KURL& linkURL, const KURL& imageURL, const String& label) { RefPtr<Range> range = src->document()->createRange(); ExceptionCode ec = 0; range->selectNode(node, ec); - ASSERT(ec == 0); - src->selection()->setSelection(VisibleSelection(range.get(), DOWNSTREAM)); + ASSERT(!ec); + src->selection()->setSelection(VisibleSelection(range.get(), DOWNSTREAM)); clipboard->declareAndWriteDragImage(node, !linkURL.isEmpty() ? linkURL : imageURL, label, src); } - + static IntPoint dragLocForDHTMLDrag(const IntPoint& mouseDraggedPoint, const IntPoint& dragOrigin, const IntPoint& dragImageOffset, bool isLinkImage) { // dragImageOffset is the cursor position relative to the lower-left corner of the image. -#if PLATFORM(MAC) - // We add in the Y dimension because we are a flipped view, so adding moves the image down. +#if PLATFORM(MAC) + // We add in the Y dimension because we are a flipped view, so adding moves the image down. const int yOffset = dragImageOffset.y(); #else const int yOffset = -dragImageOffset.y(); #endif - + if (isLinkImage) return IntPoint(mouseDraggedPoint.x() - dragImageOffset.x(), mouseDraggedPoint.y() + yOffset); - + return IntPoint(dragOrigin.x() - dragImageOffset.x(), dragOrigin.y() + yOffset); } - + static IntPoint dragLocForSelectionDrag(Frame* src) { IntRect draggingRect = enclosingIntRect(src->selectionBounds()); @@ -586,63 +604,63 @@ static IntPoint dragLocForSelectionDrag(Frame* src) #endif return IntPoint(xpos, ypos); } - + bool DragController::startDrag(Frame* src, Clipboard* clipboard, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin, bool isDHTMLDrag) -{ +{ ASSERT(src); ASSERT(clipboard); - + if (!src->view() || !src->contentRenderer()) return false; - + HitTestResult dragSource = HitTestResult(dragOrigin); dragSource = src->eventHandler()->hitTestResultAtPoint(dragOrigin, true); KURL linkURL = dragSource.absoluteLinkURL(); KURL imageURL = dragSource.absoluteImageURL(); bool isSelected = dragSource.isSelected(); - + IntPoint mouseDraggedPoint = src->view()->windowToContents(dragEvent.pos()); - + m_draggingImageURL = KURL(); m_sourceDragOperation = srcOp; - + DragImageRef dragImage = 0; IntPoint dragLoc(0, 0); IntPoint dragImageOffset(0, 0); - - if (isDHTMLDrag) + + if (isDHTMLDrag) dragImage = clipboard->createDragImage(dragImageOffset); - + // We allow DHTML/JS to set the drag image, even if its a link, image or text we're dragging. // This is in the spirit of the IE API, which allows overriding of pasteboard data and DragOp. if (dragImage) { dragLoc = dragLocForDHTMLDrag(mouseDraggedPoint, dragOrigin, dragImageOffset, !linkURL.isEmpty()); m_dragOffset = dragImageOffset; } - + bool startedDrag = true; // optimism - we almost always manage to start the drag - + Node* node = dragSource.innerNonSharedNode(); - + Image* image = getImage(static_cast<Element*>(node)); if (!imageURL.isEmpty() && node && node->isElementNode() && image && (m_dragSourceAction & DragSourceActionImage)) { - // We shouldn't be starting a drag for an image that can't provide an extension. + // We shouldn't be starting a drag for an image that can't provide an extension. // This is an early detection for problems encountered later upon drop. ASSERT(!image->filenameExtension().isEmpty()); Element* element = static_cast<Element*>(node); if (!clipboard->hasData()) { - m_draggingImageURL = imageURL; + m_draggingImageURL = imageURL; prepareClipboardForImageDrag(src, clipboard, element, linkURL, imageURL, dragSource.altDisplayString()); } - + m_client->willPerformDragSourceAction(DragSourceActionImage, dragOrigin, clipboard); - + if (!dragImage) { IntRect imageRect = dragSource.imageRect(); imageRect.setLocation(m_page->mainFrame()->view()->windowToContents(src->view()->contentsToWindow(imageRect.location()))); doImageDrag(element, dragOrigin, dragSource.imageRect(), clipboard, src, m_dragOffset); - } else + } else // DHTML defined drag image doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false); @@ -668,12 +686,12 @@ bool DragController::startDrag(Frame* src, Clipboard* clipboard, DragOperation s IntSize size = dragImageSize(dragImage); m_dragOffset = IntPoint(-size.width() / 2, -LinkDragBorderInset); dragLoc = IntPoint(mouseDraggedPoint.x() + m_dragOffset.x(), mouseDraggedPoint.y() + m_dragOffset.y()); - } + } doSystemDrag(dragImage, dragLoc, mouseDraggedPoint, clipboard, src, true); } else if (isSelected && (m_dragSourceAction & DragSourceActionSelection)) { RefPtr<Range> selectionRange = src->selection()->toNormalizedRange(); ASSERT(selectionRange); - if (!clipboard->hasData()) + if (!clipboard->hasData()) clipboard->writeRange(selectionRange.get(), src); m_client->willPerformDragSourceAction(DragSourceActionSelection, dragOrigin, clipboard); if (!dragImage) { @@ -691,7 +709,7 @@ bool DragController::startDrag(Frame* src, Clipboard* clipboard, DragOperation s // under the mousedown point, so linkURL, imageURL and isSelected are all false/empty. startedDrag = false; } - + if (dragImage) deleteDragImage(dragImage); return startedDrag; @@ -702,17 +720,17 @@ void DragController::doImageDrag(Element* element, const IntPoint& dragOrigin, c IntPoint mouseDownPoint = dragOrigin; DragImageRef dragImage; IntPoint origin; - + Image* image = getImage(element); if (image && image->size().height() * image->size().width() <= MaxOriginalImageArea && (dragImage = createDragImageFromImage(image))) { IntSize originalSize = rect.size(); origin = rect.location(); - + dragImage = fitDragImageToMaxSize(dragImage, rect.size(), maxDragImageSize()); dragImage = dissolveDragImageToFraction(dragImage, DragImageAlpha); IntSize newSize = dragImageSize(dragImage); - + // Properly orient the drag image and orient it differently if it's smaller than the original float scale = newSize.width() / (float)originalSize.width(); float dx = origin.x() - mouseDownPoint.x(); @@ -730,14 +748,14 @@ void DragController::doImageDrag(Element* element, const IntPoint& dragOrigin, c if (dragImage) origin = IntPoint(DragIconRightInset - dragImageSize(dragImage).width(), DragIconBottomInset); } - + dragImageOffset.setX(mouseDownPoint.x() + origin.x()); dragImageOffset.setY(mouseDownPoint.y() + origin.y()); doSystemDrag(dragImage, dragImageOffset, dragOrigin, clipboard, frame, false); - + deleteDragImage(dragImage); } - + void DragController::doSystemDrag(DragImageRef image, const IntPoint& dragLoc, const IntPoint& eventPos, Clipboard* clipboard, Frame* frame, bool forLink) { m_didInitiateDrag = true; @@ -747,10 +765,10 @@ void DragController::doSystemDrag(DragImageRef image, const IntPoint& dragLoc, c RefPtr<FrameView> viewProtector = frameProtector->view(); m_client->startDrag(image, viewProtector->windowToContents(frame->view()->contentsToWindow(dragLoc)), viewProtector->windowToContents(frame->view()->contentsToWindow(eventPos)), clipboard, frameProtector.get(), forLink); - + cleanupAfterSystemDrag(); } - + // Manual drag caret manipulation void DragController::placeDragCaret(const IntPoint& windowPoint) { @@ -762,8 +780,8 @@ void DragController::placeDragCaret(const IntPoint& windowPoint) if (!frameView) return; IntPoint framePoint = frameView->windowToContents(windowPoint); - VisibleSelection dragCaret(frame->visiblePositionForPoint(framePoint)); + VisibleSelection dragCaret(frame->visiblePositionForPoint(framePoint)); m_page->dragCaretController()->setSelection(dragCaret); } - + } // namespace WebCore diff --git a/WebCore/page/DragController.h b/WebCore/page/DragController.h index 6fe1f7f..9472589 100644 --- a/WebCore/page/DragController.h +++ b/WebCore/page/DragController.h @@ -96,8 +96,8 @@ namespace WebCore { bool concludeEditDrag(DragData*); DragOperation dragEnteredOrUpdated(DragData*); DragOperation operationForLoad(DragData*); - DragOperation tryDocumentDrag(DragData*, DragDestinationAction); - DragOperation tryDHTMLDrag(DragData*); + bool tryDocumentDrag(DragData*, DragDestinationAction, DragOperation&); + bool tryDHTMLDrag(DragData*, DragOperation&); DragOperation dragOperation(DragData*); void cancelDrag(); bool dragIsMove(SelectionController*); diff --git a/WebCore/page/EventHandler.cpp b/WebCore/page/EventHandler.cpp index c59ad00..624f530 100644 --- a/WebCore/page/EventHandler.cpp +++ b/WebCore/page/EventHandler.cpp @@ -150,6 +150,8 @@ EventHandler::EventHandler(Frame* frame) , m_mouseDownWasSingleClickInSelection(false) , m_beganSelectingText(false) , m_panScrollInProgress(false) + , m_panScrollButtonPressed(false) + , m_springLoadedPanScrollInProgress(false) , m_hoverTimer(this, &EventHandler::hoverTimerFired) , m_autoscrollTimer(this, &EventHandler::autoscrollTimerFired) , m_autoscrollRenderer(0) @@ -163,6 +165,8 @@ EventHandler::EventHandler(Frame* frame) , m_capturingMouseEventsNode(0) , m_clickCount(0) , m_mouseDownTimestamp(0) + , m_useLatchedWheelEventNode(false) + , m_widgetIsLatched(false) #if PLATFORM(MAC) , m_mouseDownView(nil) , m_sendingEventToSubview(false) @@ -205,6 +209,7 @@ void EventHandler::clear() m_mousePressed = false; m_capturesDragging = false; m_capturingMouseEventsNode = 0; + m_latchedWheelEventNode = 0; } void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result) @@ -355,6 +360,11 @@ bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve // Reset drag state. dragState().m_dragSrc = 0; + if (ScrollView* scrollView = m_frame->view()) { + if (scrollView->isPointInScrollbarCorner(event.event().pos())) + return false; + } + bool singleClick = event.event().clickCount() <= 1; // If we got the event back, that must mean it wasn't prevented, @@ -366,6 +376,8 @@ bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve m_mouseDownWasSingleClickInSelection = false; + m_mouseDown = event.event(); + if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event)) return true; @@ -405,7 +417,7 @@ bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect || (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled(true)); - return swallowEvent; + return swallowEvent; } bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event) @@ -657,7 +669,7 @@ void EventHandler::autoscrollTimerFired(Timer<EventHandler>*) } } #if ENABLE(PAN_SCROLLING) - setPanScrollCursor(); + updatePanScrollState(); toRenderBox(r)->panScroll(m_panScrollStartPos); #endif } @@ -665,7 +677,7 @@ void EventHandler::autoscrollTimerFired(Timer<EventHandler>*) #if ENABLE(PAN_SCROLLING) -void EventHandler::setPanScrollCursor() +void EventHandler::updatePanScrollState() { FrameView* view = m_frame->view(); if (!view) @@ -673,12 +685,14 @@ void EventHandler::setPanScrollCursor() // At the original click location we draw a 4 arrowed icon. Over this icon there won't be any scroll // So we don't want to change the cursor over this area - const int noScrollRadius = 9; - bool east = m_panScrollStartPos.x() < (m_currentMousePosition.x() - noScrollRadius); - bool west = m_panScrollStartPos.x() > (m_currentMousePosition.x() + noScrollRadius); - bool north = m_panScrollStartPos.y() > (m_currentMousePosition.y() + noScrollRadius); - bool south = m_panScrollStartPos.y() < (m_currentMousePosition.y() - noScrollRadius); + bool east = m_panScrollStartPos.x() < (m_currentMousePosition.x() - ScrollView::noPanScrollRadius); + bool west = m_panScrollStartPos.x() > (m_currentMousePosition.x() + ScrollView::noPanScrollRadius); + bool north = m_panScrollStartPos.y() > (m_currentMousePosition.y() + ScrollView::noPanScrollRadius); + bool south = m_panScrollStartPos.y() < (m_currentMousePosition.y() - ScrollView::noPanScrollRadius); + if ((east || west || north || south) && m_panScrollButtonPressed) + m_springLoadedPanScrollInProgress = true; + if (north) { if (east) view->setCursor(northEastPanningCursor()); @@ -748,7 +762,7 @@ void EventHandler::allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const flagUA = ((mask & DragSourceActionImage) || (mask & DragSourceActionLink) || (mask & DragSourceActionSelection)); } -HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool allowShadowContent, bool ignoreClipping) +HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool allowShadowContent, bool ignoreClipping, HitTestScrollbars testScrollbars) { HitTestResult result(point); if (!m_frame->contentRenderer()) @@ -762,7 +776,7 @@ HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool all Node* n = result.innerNode(); if (!result.isOverWidget() || !n || !n->renderer() || !n->renderer()->isWidget()) break; - RenderWidget* renderWidget = static_cast<RenderWidget*>(n->renderer()); + RenderWidget* renderWidget = toRenderWidget(n->renderer()); Widget* widget = renderWidget->widget(); if (!widget || !widget->isFrameView()) break; @@ -775,6 +789,12 @@ HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool all HitTestResult widgetHitTestResult(widgetPoint); frame->contentRenderer()->layer()->hitTest(HitTestRequest(hitType), widgetHitTestResult); result = widgetHitTestResult; + + if (testScrollbars == ShouldHitTestScrollbars) { + Scrollbar* eventScrollbar = view->scrollbarAtPoint(point); + if (eventScrollbar) + result.setScrollbar(eventScrollbar); + } } // If our HitTestResult is not visible, then we started hit testing too far down the frame chain. @@ -833,6 +853,7 @@ void EventHandler::stopAutoscrollTimer(bool rendererIsBeingDestroyed) m_autoscrollTimer.stop(); m_panScrollInProgress = false; + m_springLoadedPanScrollInProgress = false; // If we're not in the top frame we notify it that we are not doing a panScroll any more. if (Page* page = m_frame->page()) { @@ -869,6 +890,21 @@ bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity g return false; } +bool EventHandler::scrollRecursively(ScrollDirection direction, ScrollGranularity granularity) +{ + bool handled = scrollOverflow(direction, granularity); + if (!handled) { + Frame* frame = m_frame; + do { + FrameView* view = frame->view(); + handled = view ? view->scroll(direction, granularity) : false; + frame = frame->tree()->parent(); + } while (!handled && frame); + } + + return handled; +} + IntPoint EventHandler::currentMousePosition() const { return m_currentMousePosition; @@ -890,7 +926,7 @@ Frame* subframeForTargetNode(Node* node) if (!renderer || !renderer->isWidget()) return 0; - Widget* widget = static_cast<RenderWidget*>(renderer)->widget(); + Widget* widget = toRenderWidget(renderer)->widget(); if (!widget || !widget->isFrameView()) return 0; @@ -921,10 +957,10 @@ Cursor EventHandler::selectCursor(const MouseEventWithHitTestResults& event, Scr RenderStyle* style = renderer ? renderer->style() : 0; if (renderer && renderer->isFrameSet()) { - RenderFrameSet* fs = static_cast<RenderFrameSet*>(renderer); - if (fs->canResizeRow(event.localPoint())) + RenderFrameSet* frameSetRenderer = toRenderFrameSet(renderer); + if (frameSetRenderer->canResizeRow(event.localPoint())) return rowResizeCursor(); - if (fs->canResizeColumn(event.localPoint())) + if (frameSetRenderer->canResizeColumn(event.localPoint())) return columnResizeCursor(); } @@ -957,7 +993,7 @@ Cursor EventHandler::selectCursor(const MouseEventWithHitTestResults& event, Scr // If the link is editable, then we need to check the settings to see whether or not the link should be followed if (editable) { ASSERT(m_frame->settings()); - switch(m_frame->settings()->editableLinkBehavior()) { + switch (m_frame->settings()->editableLinkBehavior()) { default: case EditableLinkDefaultBehavior: case EditableLinkAlwaysLive: @@ -1145,11 +1181,12 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) if (renderer) { m_panScrollInProgress = true; + m_panScrollButtonPressed = true; handleAutoscroll(renderer); invalidateClick(); return true; } - } + } #endif m_clickCount = mouseEvent.clickCount(); @@ -1182,8 +1219,12 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) if (swallowEvent) { // scrollbars should get events anyway, even disabled controls might be scrollable - if (mev.scrollbar()) - passMousePressEventToScrollbar(mev, mev.scrollbar()); + Scrollbar* scrollbar = mev.scrollbar(); + + updateLastScrollbarUnderMouse(scrollbar, true); + + if (scrollbar) + passMousePressEventToScrollbar(mev, scrollbar); } else { // Refetch the event target node if it currently is the shadow node inside an <input> element. // If a mouse event handler changes the input element type to one that has a widget associated, @@ -1195,9 +1236,12 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) } FrameView* view = m_frame->view(); - Scrollbar* scrollbar = view ? view->scrollbarUnderMouse(mouseEvent) : 0; + Scrollbar* scrollbar = view ? view->scrollbarAtPoint(mouseEvent.pos()) : 0; if (!scrollbar) scrollbar = mev.scrollbar(); + + updateLastScrollbarUnderMouse(scrollbar, true); + if (scrollbar && passMousePressEventToScrollbar(mev, scrollbar)) swallowEvent = true; else @@ -1287,7 +1331,7 @@ bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, Hi // Send events right to a scrollbar if the mouse is pressed. if (m_lastScrollbarUnderMouse && m_mousePressed) - return m_lastScrollbarUnderMouse->mouseMoved(m_lastScrollbarUnderMouse->transformEvent(mouseEvent)); + return m_lastScrollbarUnderMouse->mouseMoved(mouseEvent); // Treat mouse move events while the mouse is pressed as "read-only" in prepareMouseEvent // if we are allowed to select. @@ -1309,17 +1353,12 @@ bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, Hi m_resizeLayer->resize(mouseEvent, m_offsetFromResizeCorner); else { if (FrameView* view = m_frame->view()) - scrollbar = view->scrollbarUnderMouse(mouseEvent); + scrollbar = view->scrollbarAtPoint(mouseEvent.pos()); if (!scrollbar) scrollbar = mev.scrollbar(); - if (m_lastScrollbarUnderMouse != scrollbar) { - // Send mouse exited to the old scrollbar. - if (m_lastScrollbarUnderMouse) - m_lastScrollbarUnderMouse->mouseExited(); - m_lastScrollbarUnderMouse = m_mousePressed ? 0 : scrollbar; - } + updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed); } bool swallowEvent = false; @@ -1339,7 +1378,7 @@ bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, Hi swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode); } else { if (scrollbar && !m_mousePressed) - scrollbar->mouseMoved(scrollbar->transformEvent(mouseEvent)); // Handle hover effects on platforms that support visual feedback on scrollbar hovering. + scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering. if (Page* page = m_frame->page()) { if ((!m_resizeLayer || !m_resizeLayer->inResizeMode()) && !page->mainFrame()->eventHandler()->panScrollInProgress()) { if (FrameView* view = m_frame->view()) @@ -1370,6 +1409,13 @@ bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent) { RefPtr<FrameView> protector(m_frame->view()); +#if ENABLE(PAN_SCROLLING) + if (mouseEvent.button() == MiddleButton) + m_panScrollButtonPressed = false; + if (m_springLoadedPanScrollInProgress) + stopAutoscrollTimer(); +#endif + m_mousePressed = false; m_currentMousePosition = mouseEvent.pos(); @@ -1705,18 +1751,39 @@ bool EventHandler::handleWheelEvent(PlatformWheelEvent& e) return false; IntPoint vPoint = view->windowToContents(e.pos()); - HitTestRequest request(HitTestRequest::ReadOnly); - HitTestResult result(vPoint); - doc->renderView()->layer()->hitTest(request, result); - Node* node = result.innerNode(); + Node* node; + bool isOverWidget; + bool didSetLatchedNode = false; + + if (m_useLatchedWheelEventNode) { + if (!m_latchedWheelEventNode) { + HitTestRequest request(HitTestRequest::ReadOnly); + HitTestResult result(vPoint); + doc->renderView()->layer()->hitTest(request, result); + m_latchedWheelEventNode = result.innerNode(); + m_widgetIsLatched = result.isOverWidget(); + didSetLatchedNode = true; + } + + node = m_latchedWheelEventNode.get(); + isOverWidget = m_widgetIsLatched; + } else { + if (m_latchedWheelEventNode) + m_latchedWheelEventNode = 0; + + HitTestRequest request(HitTestRequest::ReadOnly); + HitTestResult result(vPoint); + doc->renderView()->layer()->hitTest(request, result); + node = result.innerNode(); + isOverWidget = result.isOverWidget(); + } if (node) { // Figure out which view to send the event to. RenderObject* target = node->renderer(); - if (result.isOverWidget() && target && target->isWidget()) { - Widget* widget = static_cast<RenderWidget*>(target)->widget(); - + if (isOverWidget && target && target->isWidget()) { + Widget* widget = toRenderWidget(target)->widget(); if (widget && passWheelEventToWidget(e, widget)) { e.accept(); return true; @@ -1896,10 +1963,8 @@ bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent) #if ENABLE(PAN_SCROLLING) if (Page* page = m_frame->page()) { if (page->mainFrame()->eventHandler()->panScrollInProgress() || m_autoscrollInProgress) { - static const char* const escapeKeyIdentifier = "U+001B"; - // If a key is pressed while the autoscroll/panScroll is in progress then we want to stop - if (initialKeyEvent.keyIdentifier() == escapeKeyIdentifier && initialKeyEvent.type() == PlatformKeyboardEvent::KeyUp) + if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyDown || initialKeyEvent.type() == PlatformKeyboardEvent::RawKeyDown) stopAutoscrollTimer(); // If we were in autoscroll/panscroll mode, we swallow the key event @@ -2024,7 +2089,7 @@ void EventHandler::handleKeyboardSelectionMovement(KeyboardEvent* event) void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event) { - if (event->type() == eventNames().keydownEvent) { + if (event->type() == eventNames().keydownEvent) { m_frame->editor()->handleKeyboardEvent(event); if (event->defaultHandled()) return; @@ -2034,14 +2099,14 @@ void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event) // provides KB navigation and selection for enhanced accessibility users if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled()) handleKeyboardSelectionMovement(event); - } - if (event->type() == eventNames().keypressEvent) { + } + if (event->type() == eventNames().keypressEvent) { m_frame->editor()->handleKeyboardEvent(event); if (event->defaultHandled()) return; if (event->charCode() == ' ') defaultSpaceEventHandler(event); - } + } } bool EventHandler::dragHysteresisExceeded(const FloatPoint& floatDragViewportLocation) const @@ -2099,6 +2164,9 @@ void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperat } freeClipboard(); dragState().m_dragSrc = 0; + // In case the drag was ended due to an escape key press we need to ensure + // that consecutive mousemove events don't reinitiate the drag and drop. + m_mouseDownMayStartDrag = false; } // returns if we should continue "default processing", i.e., whether eventhandler canceled @@ -2365,7 +2433,7 @@ void EventHandler::capsLockStateMayHaveChanged() if (Node* node = d->focusedNode()) { if (RenderObject* r = node->renderer()) { if (r->isTextField()) - static_cast<RenderTextControlSingleLine*>(r)->capsLockStateMayHaveChanged(); + toRenderTextControlSingleLine(r)->capsLockStateMayHaveChanged(); } } } @@ -2391,6 +2459,7 @@ bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& return scrollbar->mouseDown(mev.event()); } +#ifdef MANUAL_MERGE_REQUIRED #if ENABLE(TOUCH_EVENTS) // Android bool EventHandler::handleTouchEvent(const PlatformTouchEvent& e) { @@ -2499,4 +2568,18 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& e) } #endif +#else // MANUAL_MERGE_REQUIRED +// If scrollbar (under mouse) is different from last, send a mouse exited. Set +// last to scrollbar if setLast is true; else set last to 0. +void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast) +{ + if (m_lastScrollbarUnderMouse != scrollbar) { + // Send mouse exited to the old scrollbar. + if (m_lastScrollbarUnderMouse) + m_lastScrollbarUnderMouse->mouseExited(); + m_lastScrollbarUnderMouse = setLast ? scrollbar : 0; + } +} + +#endif // MANUAL_MERGE_REQUIRED } diff --git a/WebCore/page/EventHandler.h b/WebCore/page/EventHandler.h index 0ad70c2..7fe64ad 100644 --- a/WebCore/page/EventHandler.h +++ b/WebCore/page/EventHandler.h @@ -71,7 +71,9 @@ extern const int ImageDragHysteresis; extern const int TextDragHysteresis; extern const int GeneralDragHysteresis; -class EventHandler : Noncopyable { +enum HitTestScrollbars { ShouldHitTestScrollbars, DontHitTestScrollbars }; + +class EventHandler : public Noncopyable { public: EventHandler(Frame*); ~EventHandler(); @@ -90,7 +92,7 @@ public: RenderObject* autoscrollRenderer() const; void updateAutoscrollRenderer(); - HitTestResult hitTestResultAtPoint(const IntPoint&, bool allowShadowContent, bool ignoreClipping = false); + HitTestResult hitTestResultAtPoint(const IntPoint&, bool allowShadowContent, bool ignoreClipping = false, HitTestScrollbars scrollbars = DontHitTestScrollbars); bool mousePressed() const { return m_mousePressed; } void setMousePressed(bool pressed) { m_mousePressed = pressed; } @@ -113,6 +115,8 @@ public: bool scrollOverflow(ScrollDirection, ScrollGranularity); + bool scrollRecursively(ScrollDirection, ScrollGranularity); + bool shouldDragAutoNode(Node*, const IntPoint&) const; // -webkit-user-drag == auto bool tabsToLinks(KeyboardEvent*) const; @@ -211,7 +215,7 @@ private: Cursor selectCursor(const MouseEventWithHitTestResults&, Scrollbar*); #if ENABLE(PAN_SCROLLING) - void setPanScrollCursor(); + void updatePanScrollState(); #endif void hoverTimerFired(Timer<EventHandler>*); @@ -275,6 +279,8 @@ private: void updateSelectionForMouseDrag(Node* targetNode, const IntPoint& localPoint); + void updateLastScrollbarUnderMouse(Scrollbar*, bool); + bool capturesDragging() const { return m_capturesDragging; } #if PLATFORM(MAC) && defined(__OBJC__) @@ -299,6 +305,9 @@ private: IntPoint m_panScrollStartPos; bool m_panScrollInProgress; + bool m_panScrollButtonPressed; + bool m_springLoadedPanScrollInProgress; + Timer<EventHandler> m_hoverTimer; Timer<EventHandler> m_autoscrollTimer; @@ -339,6 +348,10 @@ private: double m_mouseDownTimestamp; PlatformMouseEvent m_mouseDown; + bool m_useLatchedWheelEventNode; + RefPtr<Node> m_latchedWheelEventNode; + bool m_widgetIsLatched; + #if PLATFORM(MAC) NSView *m_mouseDownView; bool m_sendingEventToSubview; diff --git a/WebCore/page/FocusController.cpp b/WebCore/page/FocusController.cpp index 8dad846..817801c 100644 --- a/WebCore/page/FocusController.cpp +++ b/WebCore/page/FocusController.cpp @@ -58,6 +58,7 @@ using namespace HTMLNames; FocusController::FocusController(Page* page) : m_page(page) , m_isActive(false) + , m_isFocused(false) { } @@ -66,16 +67,20 @@ void FocusController::setFocusedFrame(PassRefPtr<Frame> frame) if (m_focusedFrame == frame) return; - if (m_focusedFrame && m_focusedFrame->view()) { - m_focusedFrame->selection()->setFocused(false); - m_focusedFrame->document()->dispatchWindowEvent(eventNames().blurEvent, false, false); - } + RefPtr<Frame> oldFrame = m_focusedFrame; + RefPtr<Frame> newFrame = frame; - m_focusedFrame = frame; + m_focusedFrame = newFrame; - if (m_focusedFrame && m_focusedFrame->view()) { - m_focusedFrame->selection()->setFocused(true); - m_focusedFrame->document()->dispatchWindowEvent(eventNames().focusEvent, false, false); + // Now that the frame is updated, fire events and update the selection focused states of both frames. + if (oldFrame && oldFrame->view()) { + oldFrame->selection()->setFocused(false); + oldFrame->document()->dispatchWindowEvent(eventNames().blurEvent, false, false); + } + + if (newFrame && newFrame->view() && isFocused()) { + newFrame->selection()->setFocused(true); + newFrame->document()->dispatchWindowEvent(eventNames().focusEvent, false, false); } } @@ -86,6 +91,19 @@ Frame* FocusController::focusedOrMainFrame() return m_page->mainFrame(); } +void FocusController::setFocused(bool focused) +{ + if (isFocused() == focused) + return; + + m_isFocused = focused; + + if (m_focusedFrame && m_focusedFrame->view()) { + m_focusedFrame->selection()->setFocused(focused); + m_focusedFrame->document()->dispatchWindowEvent(focused ? eventNames().focusEvent : eventNames().blurEvent, false, false); + } +} + static Node* deepFocusableNode(FocusDirection direction, Node* node, KeyboardEvent* event) { // The node we found might be a HTMLFrameOwnerElement, so descend down the frame tree until we find either: @@ -322,7 +340,7 @@ void FocusController::setActive(bool active) focusedOrMainFrame()->selection()->pageActivationChanged(); - if (m_focusedFrame) + if (m_focusedFrame && isFocused()) m_focusedFrame->document()->dispatchWindowEvent(active ? eventNames().focusEvent : eventNames().blurEvent, false, false); } diff --git a/WebCore/page/FocusController.h b/WebCore/page/FocusController.h index f4a6632..33debf1 100644 --- a/WebCore/page/FocusController.h +++ b/WebCore/page/FocusController.h @@ -53,10 +53,14 @@ namespace WebCore { void setActive(bool); bool isActive() const { return m_isActive; } + void setFocused(bool); + bool isFocused() const { return m_isFocused; } + private: Page* m_page; RefPtr<Frame> m_focusedFrame; bool m_isActive; + bool m_isFocused; }; } // namespace WebCore diff --git a/WebCore/page/Frame.cpp b/WebCore/page/Frame.cpp index eedf09b..78cc25c 100644 --- a/WebCore/page/Frame.cpp +++ b/WebCore/page/Frame.cpp @@ -41,21 +41,20 @@ #include "EditingText.h" #include "EditorClient.h" #include "EventNames.h" -#include "FocusController.h" #include "FloatQuad.h" +#include "FocusController.h" #include "FrameLoader.h" #include "FrameLoaderClient.h" #include "FrameView.h" #include "GraphicsContext.h" #include "HTMLDocument.h" +#include "HTMLFormControlElement.h" #include "HTMLFormElement.h" #include "HTMLFrameElementBase.h" -#include "HTMLFormControlElement.h" #include "HTMLNames.h" #include "HTMLTableCellElement.h" #include "HitTestResult.h" #include "Logging.h" -#include "markup.h" #include "MediaFeatureNames.h" #include "Navigator.h" #include "NodeList.h" @@ -66,12 +65,13 @@ #include "RenderTextControl.h" #include "RenderTheme.h" #include "RenderView.h" +#include "ScriptController.h" #include "Settings.h" #include "TextIterator.h" #include "TextResourceDecoder.h" #include "XMLNames.h" -#include "ScriptController.h" #include "htmlediting.h" +#include "markup.h" #include "npruntime_impl.h" #include "visible_units.h" #include <wtf/RefCountedLeakCounter.h> @@ -107,7 +107,7 @@ namespace WebCore { using namespace HTMLNames; -#ifndef NDEBUG +#ifndef NDEBUG static WTF::RefCountedLeakCounter frameCounter("Frame"); #endif @@ -118,7 +118,7 @@ static inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement) return ownerElement->document()->frame(); } -Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient) +Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient) : m_page(page) , m_treeNode(this, parentFromOwnerElement(ownerElement)) , m_loader(this, frameLoaderClient) @@ -166,7 +166,7 @@ Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* else { page->incrementFrameCount(); // Make sure we will not end up with two frames referencing the same owner element. - ASSERT((!(ownerElement->m_contentFrame)) || (ownerElement->m_contentFrame->ownerElement() != ownerElement)); + ASSERT((!(ownerElement->m_contentFrame)) || (ownerElement->m_contentFrame->ownerElement() != ownerElement)); ownerElement->m_contentFrame = this; } @@ -179,7 +179,7 @@ Frame::~Frame() { setView(0); loader()->cancelAndClear(); - + // FIXME: We should not be doing all this work inside the destructor ASSERT(!m_lifeSupportTimer.isActive()); @@ -189,14 +189,14 @@ Frame::~Frame() #endif disconnectOwnerElement(); - + if (m_domWindow) m_domWindow->disconnectFrame(); HashSet<DOMWindow*>::iterator end = m_liveFormerWindows.end(); for (HashSet<DOMWindow*>::iterator it = m_liveFormerWindows.begin(); it != end; ++it) (*it)->disconnectFrame(); - + if (m_view) { m_view->hide(); m_view->clearFrame(); @@ -265,7 +265,7 @@ void Frame::setDocument(PassRefPtr<Document> newDoc) m_doc = newDoc; if (m_doc && selection()->isFocusedAndActive()) setUseSecureKeyboardEntry(m_doc->useSecureKeyboardEntryWhenActive()); - + if (m_doc && !m_doc->attached()) m_doc->attach(); @@ -310,14 +310,14 @@ IntRect Frame::firstRectForRange(Range* range) const if (startCaretRect.y() == endCaretRect.y()) { // start and end are on the same line - return IntRect(min(startCaretRect.x(), endCaretRect.x()), - startCaretRect.y(), + return IntRect(min(startCaretRect.x(), endCaretRect.x()), + startCaretRect.y(), abs(endCaretRect.x() - startCaretRect.x()), max(startCaretRect.height(), endCaretRect.height())); } - + // start and end aren't on the same line, so go from start to the end of its line - return IntRect(startCaretRect.x(), + return IntRect(startCaretRect.x(), startCaretRect.y(), startCaretRect.width() + extraWidthToEndOfLine, startCaretRect.height()); @@ -368,23 +368,21 @@ static RegularExpression* createRegExpForLabels(const Vector<String>& labels) bool startsWithWordChar = false; bool endsWithWordChar = false; - if (label.length() != 0) { + if (label.length()) { startsWithWordChar = wordRegExp.match(label.substring(0, 1)) >= 0; endsWithWordChar = wordRegExp.match(label.substring(label.length() - 1, 1)) >= 0; } - - if (i != 0) + + if (i) pattern.append("|"); // Search for word boundaries only if label starts/ends with "word characters". // If we always searched for word boundaries, this wouldn't work for languages // such as Japanese. - if (startsWithWordChar) { + if (startsWithWordChar) pattern.append("\\b"); - } pattern.append(label); - if (endsWithWordChar) { + if (endsWithWordChar) pattern.append("\\b"); - } } pattern.append(")"); return new RegularExpression(pattern, TextCaseInsensitive); @@ -392,10 +390,11 @@ static RegularExpression* createRegExpForLabels(const Vector<String>& labels) String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell) { - RenderTableCell* cellRenderer = static_cast<RenderTableCell*>(cell->renderer()); + RenderObject* cellRenderer = cell->renderer(); if (cellRenderer && cellRenderer->isTableCell()) { - RenderTableCell* cellAboveRenderer = cellRenderer->table()->cellAbove(cellRenderer); + RenderTableCell* tableCellRenderer = toRenderTableCell(cellRenderer); + RenderTableCell* cellAboveRenderer = tableCellRenderer->table()->cellAbove(tableCellRenderer); if (cellAboveRenderer) { HTMLTableCellElement* aboveCell = @@ -465,9 +464,8 @@ String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element // If we started in a cell, but bailed because we found the start of the form or the // previous element, we still might need to search the row above us for a label. - if (startingTableCell && !searchedCellAbove) { + if (startingTableCell && !searchedCellAbove) return searchForLabelsAboveCell(regExp.get(), startingTableCell); - } return String(); } @@ -480,7 +478,7 @@ String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* e // Make numbers and _'s in field names behave like word boundaries, e.g., "address2" replace(name, RegularExpression("\\d", TextCaseSensitive), " "); name.replace('_', ' '); - + OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels)); // Use the largest match we can find in the whole name string int pos; @@ -565,7 +563,7 @@ static bool isFrameElement(const Node *n) RenderObject *renderer = n->renderer(); if (!renderer || !renderer->isWidget()) return false; - Widget* widget = static_cast<RenderWidget*>(renderer)->widget(); + Widget* widget = toRenderWidget(renderer)->widget(); return widget && widget->isFrameView(); } @@ -625,7 +623,7 @@ void Frame::selectionLayoutChanged() // Start blinking with a black caret. Be sure not to restart if we're // already blinking in the right location. if (shouldBlink && !m_caretBlinkTimer.isActive()) { - if (double blinkInterval = theme()->caretBlinkInterval()) + if (double blinkInterval = page()->theme()->caretBlinkInterval()) m_caretBlinkTimer.startRepeating(blinkInterval); if (!m_caretPaint) { @@ -643,7 +641,7 @@ void Frame::selectionLayoutChanged() return; VisibleSelection selection = this->selection()->selection(); - + if (!selection.isRange()) view->clearSelection(); else { @@ -657,7 +655,7 @@ void Frame::selectionLayoutChanged() Position endPos = selection.end(); if (endPos.upstream().isCandidate()) endPos = endPos.upstream(); - + // We can get into a state where the selection endpoints map to the same VisiblePosition when a selection is deleted // because we don't yet notify the SelectionController of text removal. if (startPos.isNotNull() && endPos.isNotNull() && selection.visibleStart() != selection.visibleEnd()) { @@ -732,12 +730,12 @@ bool Frame::shouldApplyPageZoom() const } void Frame::setZoomFactor(float percent, bool isTextOnly) -{ +{ if (m_zoomFactor == percent && isZoomFactorTextOnly() == isTextOnly) return; #if ENABLE(SVG) - // SVG doesn't care if the zoom factor is text only. It will always apply a + // SVG doesn't care if the zoom factor is text only. It will always apply a // zoom to the whole SVG. if (m_doc->isSVGDocument()) { if (!static_cast<SVGDocument*>(m_doc.get())->zoomAndPanEnabled()) @@ -796,7 +794,7 @@ String Frame::jsStatusBarText() const String Frame::jsDefaultStatusBarText() const { - return m_kjsDefaultStatusBarText; + return m_kjsDefaultStatusBarText; } void Frame::setNeedsReapplyStyles() @@ -830,7 +828,7 @@ void Frame::reapplyStyles() // FIXME: This call doesn't really make sense in a function called reapplyStyles. // We should probably eventually move it into its own function. m_doc->docLoader()->setAutoLoadImages(m_page && m_page->settings()->loadsImagesAutomatically()); - + #if FRAME_LOADS_USER_STYLESHEET const KURL userStyleSheetLocation = m_page ? m_page->settings()->userStyleSheetLocation() : KURL(); if (!userStyleSheetLocation.isEmpty()) @@ -862,7 +860,7 @@ bool Frame::shouldDeleteSelection(const VisibleSelection& selection) const return editor()->client()->shouldDeleteRange(selection.toNormalizedRange().get()); } -bool Frame::isContentEditable() const +bool Frame::isContentEditable() const { if (m_editor.clientIsEditable()) return true; @@ -900,7 +898,7 @@ void Frame::clearTypingStyle() void Frame::computeAndSetTypingStyle(CSSStyleDeclaration *style, EditAction editingAction) { - if (!style || style->length() == 0) { + if (!style || !style->length()) { clearTypingStyle(); return; } @@ -936,7 +934,7 @@ void Frame::computeAndSetTypingStyle(CSSStyleDeclaration *style, EditAction edit blockStyle->diff(mutableStyle.get()); if (blockStyle->length() > 0) applyCommand(ApplyStyleCommand::create(document(), blockStyle.get(), editingAction)); - + // Set the remaining style as the typing style. m_typingStyle = mutableStyle.release(); } @@ -953,7 +951,7 @@ String Frame::selectionStartStylePropertyValue(int stylePropertyID) const if (nodeToRemove) { ExceptionCode ec = 0; nodeToRemove->remove(ec); - ASSERT(ec == 0); + ASSERT(!ec); } return value; @@ -972,7 +970,7 @@ PassRefPtr<CSSComputedStyleDeclaration> Frame::selectionComputedStyle(Node*& nod Element *elem = pos.element(); if (!elem) return 0; - + RefPtr<Element> styleElement = elem; ExceptionCode ec = 0; @@ -980,10 +978,10 @@ PassRefPtr<CSSComputedStyleDeclaration> Frame::selectionComputedStyle(Node*& nod styleElement = document()->createElement(spanTag, false); styleElement->setAttribute(styleAttr, m_typingStyle->cssText().impl(), ec); - ASSERT(ec == 0); - + ASSERT(!ec); + styleElement->appendChild(document()->createEditingTextNode(""), ec); - ASSERT(ec == 0); + ASSERT(!ec); if (elem->renderer() && elem->renderer()->canHaveChildren()) { elem->appendChild(styleElement, ec); @@ -991,13 +989,12 @@ PassRefPtr<CSSComputedStyleDeclaration> Frame::selectionComputedStyle(Node*& nod Node *parent = elem->parent(); Node *next = elem->nextSibling(); - if (next) { + if (next) parent->insertBefore(styleElement, next, ec); - } else { + else parent->appendChild(styleElement, ec); - } } - ASSERT(ec == 0); + ASSERT(!ec); nodeToRemove = styleElement.get(); } @@ -1047,18 +1044,16 @@ void Frame::applyEditingStyleToBodyElement() const { RefPtr<NodeList> list = m_doc->getElementsByTagName("body"); unsigned len = list->length(); - for (unsigned i = 0; i < len; i++) { - applyEditingStyleToElement(static_cast<Element*>(list->item(i))); - } + for (unsigned i = 0; i < len; i++) + applyEditingStyleToElement(static_cast<Element*>(list->item(i))); } void Frame::removeEditingStyleFromBodyElement() const { RefPtr<NodeList> list = m_doc->getElementsByTagName("body"); unsigned len = list->length(); - for (unsigned i = 0; i < len; i++) { - removeEditingStyleFromElement(static_cast<Element*>(list->item(i))); - } + for (unsigned i = 0; i < len; i++) + removeEditingStyleFromElement(static_cast<Element*>(list->item(i))); } void Frame::applyEditingStyleToElement(Element* element) const @@ -1071,11 +1066,11 @@ void Frame::applyEditingStyleToElement(Element* element) const ExceptionCode ec = 0; style->setProperty(CSSPropertyWordWrap, "break-word", false, ec); - ASSERT(ec == 0); + ASSERT(!ec); style->setProperty(CSSPropertyWebkitNbspMode, "space", false, ec); - ASSERT(ec == 0); + ASSERT(!ec); style->setProperty(CSSPropertyWebkitLineBreak, "after-white-space", false, ec); - ASSERT(ec == 0); + ASSERT(!ec); } void Frame::removeEditingStyleFromElement(Element*) const @@ -1162,7 +1157,7 @@ RenderPart* Frame::ownerRenderer() const // https://bugs.webkit.org/show_bug.cgi?id=18585 if (!object->isRenderPart()) return 0; - return static_cast<RenderPart*>(object); + return toRenderPart(object); } bool Frame::isDisconnected() const @@ -1192,7 +1187,7 @@ FloatRect Frame::selectionBounds(bool clipToVisibleContent) const FrameView* view = m_view.get(); if (!root || !view) return IntRect(); - + IntRect selectionRect = root->selectionBounds(clipToVisibleContent); return clipToVisibleContent ? intersection(selectionRect, view->visibleContentRect()) : selectionRect; } @@ -1243,7 +1238,7 @@ HTMLFormElement *Frame::currentForm() const Node *start = m_doc ? m_doc->focusedNode() : 0; if (!start) start = selection()->start().node(); - + // try walking up the node tree to find a form element Node *n; for (n = start; n; n = n->parentNode()) { @@ -1252,7 +1247,7 @@ HTMLFormElement *Frame::currentForm() const else if (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement()) return static_cast<HTMLFormControlElement*>(n)->form(); } - + // try walking forward in the node tree to find a form element return start ? scanForForm(start) : 0; } @@ -1262,21 +1257,21 @@ void Frame::revealSelection(const ScrollAlignment& alignment, bool revealExtent) IntRect rect; switch (selection()->selectionType()) { - case VisibleSelection::NoSelection: - return; - case VisibleSelection::CaretSelection: - rect = selection()->absoluteCaretBounds(); - break; - case VisibleSelection::RangeSelection: - rect = revealExtent ? VisiblePosition(selection()->extent()).absoluteCaretBounds() : enclosingIntRect(selectionBounds(false)); - break; + case VisibleSelection::NoSelection: + return; + case VisibleSelection::CaretSelection: + rect = selection()->absoluteCaretBounds(); + break; + case VisibleSelection::RangeSelection: + rect = revealExtent ? VisiblePosition(selection()->extent()).absoluteCaretBounds() : enclosingIntRect(selectionBounds(false)); + break; } Position start = selection()->start(); ASSERT(start.node()); if (start.node() && start.node()->renderer()) { // FIXME: This code only handles scrolling the startContainer's layer, but - // the selection rect could intersect more than just that. + // the selection rect could intersect more than just that. // See <rdar://problem/4799899>. if (RenderLayer* layer = start.node()->renderer()->enclosingLayer()) layer->scrollRectToVisible(rect, false, alignment, alignment); @@ -1316,46 +1311,46 @@ void Frame::clearTimers() RenderStyle *Frame::styleForSelectionStart(Node *&nodeToRemove) const { nodeToRemove = 0; - + if (selection()->isNone()) return 0; - + Position pos = selection()->selection().visibleStart().deepEquivalent(); if (!pos.isCandidate()) return 0; Node *node = pos.node(); if (!node) return 0; - + if (!m_typingStyle) return node->renderer()->style(); - + RefPtr<Element> styleElement = document()->createElement(spanTag, false); - + ExceptionCode ec = 0; String styleText = m_typingStyle->cssText() + " display: inline"; styleElement->setAttribute(styleAttr, styleText.impl(), ec); - ASSERT(ec == 0); - + ASSERT(!ec); + styleElement->appendChild(document()->createEditingTextNode(""), ec); - ASSERT(ec == 0); - + ASSERT(!ec); + node->parentNode()->appendChild(styleElement, ec); - ASSERT(ec == 0); - - nodeToRemove = styleElement.get(); + ASSERT(!ec); + + nodeToRemove = styleElement.get(); return styleElement->renderer() ? styleElement->renderer()->style() : 0; } void Frame::setSelectionFromNone() { - // Put a caret inside the body if the entire frame is editable (either the + // Put a caret inside the body if the entire frame is editable (either the // entire WebView is editable or designMode is on for this document). Document *doc = document(); bool caretBrowsing = settings() && settings()->caretBrowsingEnabled(); if (!selection()->isNone() || !(isContentEditable() || caretBrowsing)) return; - + Node* node = doc->documentElement(); while (node && !node->hasTagName(bodyTag)) node = node->traverseNextNode(); @@ -1378,10 +1373,10 @@ bool Frame::findString(const String& target, bool forward, bool caseFlag, bool w { if (target.isEmpty()) return false; - + if (excludeFromTextSearch()) return false; - + // Start from an edge of the selection, if there's a selection that's not in shadow content. Which edge // is used depends on whether we're searching forward or backward, and whether startInSelection is set. RefPtr<Range> searchRange(rangeOfContents(document())); @@ -1422,7 +1417,7 @@ bool Frame::findString(const String& target, bool forward, bool caseFlag, bool w resultRange = findPlainText(searchRange.get(), target, forward, caseFlag); } - + ExceptionCode exception = 0; // If nothing was found in the shadow tree, search in main content following the shadow tree. @@ -1435,7 +1430,7 @@ bool Frame::findString(const String& target, bool forward, bool caseFlag, bool w resultRange = findPlainText(searchRange.get(), target, forward, caseFlag); } - + if (!editor()->insideVisibleArea(resultRange.get())) { resultRange = editor()->nextVisibleRange(resultRange.get(), target, forward, caseFlag, wrapFlag); if (!resultRange) @@ -1464,9 +1459,9 @@ unsigned Frame::markAllMatchesForText(const String& target, bool caseFlag, unsig { if (target.isEmpty()) return 0; - + RefPtr<Range> searchRange(rangeOfContents(document())); - + ExceptionCode exception = 0; unsigned matchCount = 0; do { @@ -1479,7 +1474,7 @@ unsigned Frame::markAllMatchesForText(const String& target, bool caseFlag, unsig searchRange->setStartAfter(resultRange->startContainer()->shadowAncestorNode(), exception); continue; } - + // A non-collapsed result range can in some funky whitespace cases still not // advance the range's start position (4509328). Break to avoid infinite loop. VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM); @@ -1491,18 +1486,18 @@ unsigned Frame::markAllMatchesForText(const String& target, bool caseFlag, unsig ++matchCount; document()->addMarker(resultRange.get(), DocumentMarker::TextMatch); } - + // Stop looking if we hit the specified limit. A limit of 0 means no limit. if (limit > 0 && matchCount >= limit) break; - + setStart(searchRange.get(), newStart); Node* shadowTreeRoot = searchRange->shadowTreeRootNode(); if (searchRange->collapsed(exception) && shadowTreeRoot) searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), exception); } while (true); - - // Do a "fake" paint in order to execute the code that computes the rendered rect for + + // Do a "fake" paint in order to execute the code that computes the rendered rect for // each text match. Document* doc = document(); if (m_view && contentRenderer()) { @@ -1514,7 +1509,7 @@ unsigned Frame::markAllMatchesForText(const String& target, bool caseFlag, unsig m_view->paintContents(&context, visibleRect); } } - + return matchCount; } @@ -1527,7 +1522,7 @@ void Frame::setMarkedTextMatchesAreHighlighted(bool flag) { if (flag == m_highlightTextMatches) return; - + m_highlightTextMatches = flag; document()->repaintMarkers(DocumentMarker::TextMatch); } @@ -1556,7 +1551,7 @@ DOMWindow* Frame::domWindow() const void Frame::clearFormerDOMWindow(DOMWindow* window) { - m_liveFormerWindows.remove(window); + m_liveFormerWindows.remove(window); } Page* Frame::page() const @@ -1623,7 +1618,7 @@ void Frame::unfocusWindow() { if (!page()) return; - + // If we're a top level window, deactivate the window. if (!tree()->parent()) page()->chrome()->unfocus(); @@ -1685,14 +1680,13 @@ void Frame::respondToChangedSelection(const VisibleSelection& oldSelection, bool // oldSelection may no longer be in the document. if (closeTyping && oldSelection.isContentEditable() && oldSelection.start().node() && oldSelection.start().node()->inDocument()) { VisiblePosition oldStart(oldSelection.visibleStart()); - VisibleSelection oldAdjacentWords = VisibleSelection(startOfWord(oldStart, LeftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary)); + VisibleSelection oldAdjacentWords = VisibleSelection(startOfWord(oldStart, LeftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary)); if (oldAdjacentWords != newAdjacentWords) { if (isContinuousGrammarCheckingEnabled) { VisibleSelection oldSelectedSentence = VisibleSelection(startOfSentence(oldStart), endOfSentence(oldStart)); editor()->markMisspellingsAndBadGrammar(oldAdjacentWords, oldSelectedSentence != newSelectedSentence, oldSelectedSentence); - } else { + } else editor()->markMisspellingsAndBadGrammar(oldAdjacentWords, false, oldAdjacentWords); - } } } @@ -1727,15 +1721,15 @@ VisiblePosition Frame::visiblePositionForPoint(const IntPoint& framePoint) visiblePos = VisiblePosition(Position(node, 0)); return visiblePos; } - + Document* Frame::documentAtPoint(const IntPoint& point) -{ - if (!view()) +{ + if (!view()) return 0; - + IntPoint pt = view()->windowToContents(point); HitTestResult result = HitTestResult(pt); - + if (contentRenderer()) result = eventHandler()->hitTestResultAtPoint(pt, false); return result.innerNode() ? result.innerNode()->document() : 0; @@ -1776,7 +1770,7 @@ void Frame::createView(const IntSize& viewportSize, frameView->setParentVisible(true); if (ownerRenderer()) - ownerRenderer()->setWidget(frameView.get()); + ownerRenderer()->setWidget(frameView); if (HTMLFrameOwnerElement* owner = ownerElement()) view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff); diff --git a/WebCore/page/Frame.h b/WebCore/page/Frame.h index acd91e5..1b55612 100644 --- a/WebCore/page/Frame.h +++ b/WebCore/page/Frame.h @@ -37,8 +37,8 @@ #include "FrameLoader.h" #include "FrameTree.h" #include "Range.h" -#include "ScrollBehavior.h" #include "ScriptController.h" +#include "ScrollBehavior.h" #include "SelectionController.h" #include "TextGranularity.h" @@ -62,29 +62,99 @@ typedef struct HBITMAP__* HBITMAP; namespace WebCore { -class CSSMutableStyleDeclaration; -class Editor; -class EventHandler; -class FrameLoader; -class FrameLoaderClient; -class FrameTree; -class FrameView; -class HTMLFrameOwnerElement; -class HTMLTableCellElement; -class RegularExpression; -class RenderPart; -class ScriptController; -class SelectionController; -class Settings; -class VisibleSelection; -class Widget; + class CSSMutableStyleDeclaration; + class Editor; + class EventHandler; + class FrameLoader; + class FrameLoaderClient; + class FrameTree; + class FrameView; + class HTMLFrameOwnerElement; + class HTMLTableCellElement; + class RegularExpression; + class RenderPart; + class ScriptController; + class SelectionController; + class Settings; + class VisibleSelection; + class Widget; #if FRAME_LOADS_USER_STYLESHEET class UserStyleSheetLoader; #endif -template <typename T> class Timer; + template <typename T> class Timer; + + class Frame : public RefCounted<Frame> { + public: + static PassRefPtr<Frame> create(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* client) + { + return adoptRef(new Frame(page, ownerElement, client)); + } + void setView(PassRefPtr<FrameView>); + ~Frame(); + + void init(); + + Page* page() const; + HTMLFrameOwnerElement* ownerElement() const; + + void pageDestroyed(); + void disconnectOwnerElement(); + + Document* document() const; + FrameView* view() const; + + void setDOMWindow(DOMWindow*); + DOMWindow* domWindow() const; + void clearFormerDOMWindow(DOMWindow*); + + Editor* editor() const; + EventHandler* eventHandler() const; + FrameLoader* loader() const; + SelectionController* selection() const; + FrameTree* tree() const; + AnimationController* animation() const; + ScriptController* script(); + + RenderView* contentRenderer() const; // root renderer for the document contained in this frame + RenderPart* ownerRenderer() const; // renderer for the element that contains this frame + + bool isDisconnected() const; + void setIsDisconnected(bool); + bool excludeFromTextSearch() const; + void setExcludeFromTextSearch(bool); + + void createView(const IntSize&, const Color&, bool, const IntSize &, bool, + ScrollbarMode = ScrollbarAuto, ScrollbarMode = ScrollbarAuto); + + private: + Frame(Page*, HTMLFrameOwnerElement*, FrameLoaderClient*); + + // === undecided, would like to consider moving to another class + + public: + static Frame* frameForWidget(const Widget*); + + Settings* settings() const; // can be NULL + + #if FRAME_LOADS_USER_STYLESHEET + void setUserStyleSheetLocation(const KURL&); + void setUserStyleSheet(const String& styleSheetData); + #endif + + void setPrinting(bool printing, float minPageWidth, float maxPageWidth, bool adjustViewSize); + + bool inViewSourceMode() const; + void setInViewSourceMode(bool = true); + + void keepAlive(); // Used to keep the frame alive when running a script that might destroy it. + #ifndef NDEBUG + static void cancelAllKeepAlive(); + #endif + +#ifdef MANUAL_MERGE_REQUIRED class Frame : public RefCounted<Frame> { public: static PassRefPtr<Frame> create(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* client) @@ -133,244 +203,225 @@ private: Frame(Page*, HTMLFrameOwnerElement*, FrameLoaderClient*); // === undecided, would like to consider moving to another class +#else // MANUAL_MERGE_REQUIRED + void setDocument(PassRefPtr<Document>); +#endif // MANUAL_MERGE_REQUIRED -public: - static Frame* frameForWidget(const Widget*); - - Settings* settings() const; // can be NULL - -#if FRAME_LOADS_USER_STYLESHEET - void setUserStyleSheetLocation(const KURL&); - void setUserStyleSheet(const String& styleSheetData); -#endif - - void setPrinting(bool printing, float minPageWidth, float maxPageWidth, bool adjustViewSize); + void clearTimers(); + static void clearTimers(FrameView*, Document*); - bool inViewSourceMode() const; - void setInViewSourceMode(bool = true); + void setNeedsReapplyStyles(); + bool needsReapplyStyles() const; + void reapplyStyles(); - void keepAlive(); // Used to keep the frame alive when running a script that might destroy it. -#ifndef NDEBUG - static void cancelAllKeepAlive(); -#endif + String documentTypeString() const; - void setDocument(PassRefPtr<Document>); + // This method -- and the corresponding list of former DOM windows -- + // should move onto ScriptController + void clearDOMWindow(); - void clearTimers(); - static void clearTimers(FrameView*, Document*); + String displayStringModifiedByEncoding(const String& str) const + { + return document() ? document()->displayStringModifiedByEncoding(str) : str; + } - void setNeedsReapplyStyles(); - bool needsReapplyStyles() const; - void reapplyStyles(); + private: + void lifeSupportTimerFired(Timer<Frame>*); - String documentTypeString() const; + // === to be moved into FrameView - // This method -- and the corresponding list of former DOM windows -- - // should move onto ScriptController - void clearDOMWindow(); + public: + void setZoomFactor(float scale, bool isTextOnly); + float zoomFactor() const; + bool isZoomFactorTextOnly() const; + bool shouldApplyTextZoom() const; + bool shouldApplyPageZoom() const; + float pageZoomFactor() const { return shouldApplyPageZoom() ? zoomFactor() : 1.0f; } + float textZoomFactor() const { return shouldApplyTextZoom() ? zoomFactor() : 1.0f; } - String displayStringModifiedByEncoding(const String& str) const - { - return document() ? document()->displayStringModifiedByEncoding(str) : str; - } + // === to be moved into Chrome -private: - void lifeSupportTimerFired(Timer<Frame>*); + public: + void focusWindow(); + void unfocusWindow(); + bool shouldClose(RegisteredEventListenerVector* alternateEventListeners = 0); + void scheduleClose(); -// === to be moved into FrameView + void setJSStatusBarText(const String&); + void setJSDefaultStatusBarText(const String&); + String jsStatusBarText() const; + String jsDefaultStatusBarText() const; -public: - void setZoomFactor(float scale, bool isTextOnly); - float zoomFactor() const; - bool isZoomFactorTextOnly() const; - bool shouldApplyTextZoom() const; - bool shouldApplyPageZoom() const; - float pageZoomFactor() const { return shouldApplyPageZoom() ? zoomFactor() : 1.0f; } - float textZoomFactor() const { return shouldApplyTextZoom() ? zoomFactor() : 1.0f; } + // === to be moved into Editor -// === to be moved into Chrome + public: + String selectedText() const; + bool findString(const String&, bool forward, bool caseFlag, bool wrapFlag, bool startInSelection); -public: - void focusWindow(); - void unfocusWindow(); - bool shouldClose(RegisteredEventListenerVector* alternateEventListeners = 0); - void scheduleClose(); + const VisibleSelection& mark() const; // Mark, to be used as emacs uses it. + void setMark(const VisibleSelection&); - void setJSStatusBarText(const String&); - void setJSDefaultStatusBarText(const String&); - String jsStatusBarText() const; - String jsDefaultStatusBarText() const; + void computeAndSetTypingStyle(CSSStyleDeclaration* , EditAction = EditActionUnspecified); + String selectionStartStylePropertyValue(int stylePropertyID) const; + void applyEditingStyleToBodyElement() const; + void removeEditingStyleFromBodyElement() const; + void applyEditingStyleToElement(Element*) const; + void removeEditingStyleFromElement(Element*) const; -// === to be moved into Editor + IntRect firstRectForRange(Range*) const; -public: - String selectedText() const; - bool findString(const String&, bool forward, bool caseFlag, bool wrapFlag, bool startInSelection); + void respondToChangedSelection(const VisibleSelection& oldSelection, bool closeTyping); + bool shouldChangeSelection(const VisibleSelection& oldSelection, const VisibleSelection& newSelection, EAffinity, bool stillSelecting) const; - const VisibleSelection& mark() const; // Mark, to be used as emacs uses it. - void setMark(const VisibleSelection&); + RenderStyle* styleForSelectionStart(Node*& nodeToRemove) const; - void computeAndSetTypingStyle(CSSStyleDeclaration* , EditAction = EditActionUnspecified); - String selectionStartStylePropertyValue(int stylePropertyID) const; - void applyEditingStyleToBodyElement() const; - void removeEditingStyleFromBodyElement() const; - void applyEditingStyleToElement(Element*) const; - void removeEditingStyleFromElement(Element*) const; + unsigned markAllMatchesForText(const String&, bool caseFlag, unsigned limit); + bool markedTextMatchesAreHighlighted() const; + void setMarkedTextMatchesAreHighlighted(bool flag); - IntRect firstRectForRange(Range*) const; - - void respondToChangedSelection(const VisibleSelection& oldSelection, bool closeTyping); - bool shouldChangeSelection(const VisibleSelection& oldSelection, const VisibleSelection& newSelection, EAffinity, bool stillSelecting) const; + PassRefPtr<CSSComputedStyleDeclaration> selectionComputedStyle(Node*& nodeToRemove) const; - RenderStyle* styleForSelectionStart(Node*& nodeToRemove) const; + void textFieldDidBeginEditing(Element*); + void textFieldDidEndEditing(Element*); + void textDidChangeInTextField(Element*); + bool doTextFieldCommandFromEvent(Element*, KeyboardEvent*); + void textWillBeDeletedInTextField(Element* input); + void textDidChangeInTextArea(Element*); - unsigned markAllMatchesForText(const String&, bool caseFlag, unsigned limit); - bool markedTextMatchesAreHighlighted() const; - void setMarkedTextMatchesAreHighlighted(bool flag); + DragImageRef dragImageForSelection(); - PassRefPtr<CSSComputedStyleDeclaration> selectionComputedStyle(Node*& nodeToRemove) const; + // === to be moved into SelectionController - void textFieldDidBeginEditing(Element*); - void textFieldDidEndEditing(Element*); - void textDidChangeInTextField(Element*); - bool doTextFieldCommandFromEvent(Element*, KeyboardEvent*); - void textWillBeDeletedInTextField(Element* input); - void textDidChangeInTextArea(Element*); + public: + TextGranularity selectionGranularity() const; + void setSelectionGranularity(TextGranularity); - DragImageRef dragImageForSelection(); - -// === to be moved into SelectionController + bool shouldChangeSelection(const VisibleSelection&) const; + bool shouldDeleteSelection(const VisibleSelection&) const; + void clearCaretRectIfNeeded(); + void setFocusedNodeIfNeeded(); + void selectionLayoutChanged(); + void notifyRendererOfSelectionChange(bool userTriggered); -public: - TextGranularity selectionGranularity() const; - void setSelectionGranularity(TextGranularity); + void invalidateSelection(); - bool shouldChangeSelection(const VisibleSelection&) const; - bool shouldDeleteSelection(const VisibleSelection&) const; - void clearCaretRectIfNeeded(); - void setFocusedNodeIfNeeded(); - void selectionLayoutChanged(); - void notifyRendererOfSelectionChange(bool userTriggered); + void setCaretVisible(bool = true); + void paintCaret(GraphicsContext*, int tx, int ty, const IntRect& clipRect) const; + void paintDragCaret(GraphicsContext*, int tx, int ty, const IntRect& clipRect) const; - void invalidateSelection(); + bool isContentEditable() const; // if true, everything in frame is editable - void setCaretVisible(bool = true); - void paintCaret(GraphicsContext*, int tx, int ty, const IntRect& clipRect) const; - void paintDragCaret(GraphicsContext*, int tx, int ty, const IntRect& clipRect) const; + void updateSecureKeyboardEntryIfActive(); - bool isContentEditable() const; // if true, everything in frame is editable + CSSMutableStyleDeclaration* typingStyle() const; + void setTypingStyle(CSSMutableStyleDeclaration*); + void clearTypingStyle(); - void updateSecureKeyboardEntryIfActive(); + FloatRect selectionBounds(bool clipToVisibleContent = true) const; + void selectionTextRects(Vector<FloatRect>&, bool clipToVisibleContent = true) const; - CSSMutableStyleDeclaration* typingStyle() const; - void setTypingStyle(CSSMutableStyleDeclaration*); - void clearTypingStyle(); + HTMLFormElement* currentForm() const; - FloatRect selectionBounds(bool clipToVisibleContent = true) const; - void selectionTextRects(Vector<FloatRect>&, bool clipToVisibleContent = true) const; + void revealSelection(const ScrollAlignment& = ScrollAlignment::alignCenterIfNeeded, bool revealExtent = false); + void setSelectionFromNone(); - HTMLFormElement* currentForm() const; + void setUseSecureKeyboardEntry(bool); - void revealSelection(const ScrollAlignment& = ScrollAlignment::alignCenterIfNeeded, bool revealExtent = false); - void setSelectionFromNone(); + private: + void caretBlinkTimerFired(Timer<Frame>*); - void setUseSecureKeyboardEntry(bool); + public: + SelectionController* dragCaretController() const; -private: - void caretBlinkTimerFired(Timer<Frame>*); + String searchForLabelsAboveCell(RegularExpression*, HTMLTableCellElement*); + String searchForLabelsBeforeElement(const Vector<String>& labels, Element*); + String matchLabelsAgainstElement(const Vector<String>& labels, Element*); -public: - SelectionController* dragCaretController() const; + VisiblePosition visiblePositionForPoint(const IntPoint& framePoint); + Document* documentAtPoint(const IntPoint& windowPoint); - String searchForLabelsAboveCell(RegularExpression*, HTMLTableCellElement*); - String searchForLabelsBeforeElement(const Vector<String>& labels, Element*); - String matchLabelsAgainstElement(const Vector<String>& labels, Element*); - - VisiblePosition visiblePositionForPoint(const IntPoint& framePoint); - Document* documentAtPoint(const IntPoint& windowPoint); + #if PLATFORM(MAC) -#if PLATFORM(MAC) + // === undecided, would like to consider moving to another class -// === undecided, would like to consider moving to another class + public: + NSString* searchForNSLabelsAboveCell(RegularExpression*, HTMLTableCellElement*); + NSString* searchForLabelsBeforeElement(NSArray* labels, Element*); + NSString* matchLabelsAgainstElement(NSArray* labels, Element*); -public: - NSString* searchForNSLabelsAboveCell(RegularExpression*, HTMLTableCellElement*); - NSString* searchForLabelsBeforeElement(NSArray* labels, Element*); - NSString* matchLabelsAgainstElement(NSArray* labels, Element*); + #if ENABLE(DASHBOARD_SUPPORT) + NSMutableDictionary* dashboardRegionsDictionary(); + #endif -#if ENABLE(DASHBOARD_SUPPORT) - NSMutableDictionary* dashboardRegionsDictionary(); -#endif + NSImage* selectionImage(bool forceBlackText = false) const; + NSImage* snapshotDragImage(Node*, NSRect* imageRect, NSRect* elementRect) const; + NSImage* nodeImage(Node*) const; - NSImage* selectionImage(bool forceBlackText = false) const; - NSImage* snapshotDragImage(Node*, NSRect* imageRect, NSRect* elementRect) const; - NSImage* nodeImage(Node*) const; + private: + NSImage* imageFromRect(NSRect) const; -private: - NSImage* imageFromRect(NSRect) const; + // === to be moved into Editor -// === to be moved into Editor + public: + NSDictionary* fontAttributesForSelectionStart() const; + NSWritingDirection baseWritingDirectionForSelectionStart() const; -public: - NSDictionary* fontAttributesForSelectionStart() const; - NSWritingDirection baseWritingDirectionForSelectionStart() const; + #endif -#endif + #if PLATFORM(WIN) -#if PLATFORM(WIN) + public: + // FIXME - We should have a single version of nodeImage instead of using platform types. + HBITMAP nodeImage(Node*) const; -public: - // FIXME - We should have a single version of nodeImage instead of using platform types. - HBITMAP nodeImage(Node*) const; + #endif -#endif + private: + Page* m_page; + mutable FrameTree m_treeNode; + mutable FrameLoader m_loader; -private: - Page* m_page; - mutable FrameTree m_treeNode; - mutable FrameLoader m_loader; + mutable RefPtr<DOMWindow> m_domWindow; + HashSet<DOMWindow*> m_liveFormerWindows; - mutable RefPtr<DOMWindow> m_domWindow; - HashSet<DOMWindow*> m_liveFormerWindows; + HTMLFrameOwnerElement* m_ownerElement; + RefPtr<FrameView> m_view; + RefPtr<Document> m_doc; - HTMLFrameOwnerElement* m_ownerElement; - RefPtr<FrameView> m_view; - RefPtr<Document> m_doc; + ScriptController m_script; - ScriptController m_script; + String m_kjsStatusBarText; + String m_kjsDefaultStatusBarText; - String m_kjsStatusBarText; - String m_kjsDefaultStatusBarText; + float m_zoomFactor; - float m_zoomFactor; + TextGranularity m_selectionGranularity; - TextGranularity m_selectionGranularity; + mutable SelectionController m_selectionController; + mutable VisibleSelection m_mark; + Timer<Frame> m_caretBlinkTimer; + mutable Editor m_editor; + mutable EventHandler m_eventHandler; + mutable AnimationController m_animationController; - mutable SelectionController m_selectionController; - mutable VisibleSelection m_mark; - Timer<Frame> m_caretBlinkTimer; - mutable Editor m_editor; - mutable EventHandler m_eventHandler; - mutable AnimationController m_animationController; + RefPtr<CSSMutableStyleDeclaration> m_typingStyle; - RefPtr<CSSMutableStyleDeclaration> m_typingStyle; + Timer<Frame> m_lifeSupportTimer; - Timer<Frame> m_lifeSupportTimer; + bool m_caretVisible; + bool m_caretPaint; - bool m_caretVisible; - bool m_caretPaint; - - bool m_highlightTextMatches; - bool m_inViewSourceMode; - bool m_needsReapplyStyles; - bool m_isDisconnected; - bool m_excludeFromTextSearch; + bool m_highlightTextMatches; + bool m_inViewSourceMode; + bool m_needsReapplyStyles; + bool m_isDisconnected; + bool m_excludeFromTextSearch; -#if FRAME_LOADS_USER_STYLESHEET - UserStyleSheetLoader* m_userStyleSheetLoader; -#endif + #if FRAME_LOADS_USER_STYLESHEET + UserStyleSheetLoader* m_userStyleSheetLoader; + #endif -}; + }; } // namespace WebCore diff --git a/WebCore/page/FrameTree.h b/WebCore/page/FrameTree.h index d4c8c43..9ab999f 100644 --- a/WebCore/page/FrameTree.h +++ b/WebCore/page/FrameTree.h @@ -26,7 +26,7 @@ namespace WebCore { class Frame; - class FrameTree : Noncopyable { + class FrameTree : public Noncopyable { public: FrameTree(Frame* thisFrame, Frame* parentFrame) : m_thisFrame(thisFrame) diff --git a/WebCore/page/FrameView.cpp b/WebCore/page/FrameView.cpp index f753447..ed91587 100644 --- a/WebCore/page/FrameView.cpp +++ b/WebCore/page/FrameView.cpp @@ -6,6 +6,7 @@ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. * (C) 2006 Graham Dennis (graham.dennis@gmail.com) * (C) 2006 Alexey Proskuryakov (ap@nypop.com) + * Copyright (C) 2009 Google Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -114,7 +115,6 @@ FrameView::FrameView(Frame* frame) , m_shouldUpdateWhileOffscreen(true) , m_deferSetNeedsLayouts(0) , m_setNeedsLayoutWasDeferred(false) - , m_lockedToAnchor(false) { init(); } @@ -188,7 +188,7 @@ void FrameView::reset() m_isPainting = false; m_isVisuallyNonEmpty = false; m_firstVisuallyNonEmptyLayoutCallbackPending = true; - m_lockedToAnchor = false; + m_maintainScrollPositionAnchor = 0; } bool FrameView::isFrameView() const @@ -232,6 +232,30 @@ void FrameView::init() } } +void FrameView::detachCustomScrollbars() +{ + if (!m_frame) + return; + + Document* document = m_frame->document(); + if (!document) + return; + + Element* body = document->body(); + if (!body) + return; + + RenderBox* renderBox = body->renderBox(); + + Scrollbar* horizontalBar = horizontalScrollbar(); + if (horizontalBar && horizontalBar->isCustomScrollbar() && toRenderScrollbar(horizontalBar)->owningRenderer() == renderBox) + setHasHorizontalScrollbar(false); + + Scrollbar* verticalBar = verticalScrollbar(); + if (verticalBar && verticalBar->isCustomScrollbar() && toRenderScrollbar(verticalBar)->owningRenderer() == renderBox) + setHasVerticalScrollbar(false); +} + void FrameView::clear() { setCanBlitOnScroll(true); @@ -396,15 +420,18 @@ void FrameView::applyOverflowToViewport(RenderObject* o, ScrollbarMode& hMode, S } #if USE(ACCELERATED_COMPOSITING) -void FrameView::updateCompositingLayers(CompositingUpdate updateType) +void FrameView::updateCompositingLayers() { RenderView* view = m_frame->contentRenderer(); - if (!view || !view->usesCompositing()) + if (!view) return; - if (updateType == ForcedCompositingUpdate) - view->compositor()->setCompositingLayersNeedUpdate(); + // This call will make sure the cached hasAcceleratedCompositing is updated from the pref + view->compositor()->cacheAcceleratedCompositingEnabledFlag(); + if (!view->usesCompositing()) + return; + view->compositor()->updateCompositingLayers(); } @@ -416,6 +443,37 @@ void FrameView::setNeedsOneShotDrawingSynchronization() } #endif // USE(ACCELERATED_COMPOSITING) +bool FrameView::syncCompositingStateRecursive() +{ +#if USE(ACCELERATED_COMPOSITING) + ASSERT(m_frame->view() == this); + RenderView* contentRenderer = m_frame->contentRenderer(); + if (!contentRenderer) + return true; // We don't want to keep trying to update layers if we have no renderer. + + if (m_layoutTimer.isActive()) { + // Don't sync layers if there's a layout pending. + return false; + } + + if (GraphicsLayer* rootLayer = contentRenderer->compositor()->rootPlatformLayer()) + rootLayer->syncCompositingState(); + + bool allSubframesSynced = true; + const HashSet<RefPtr<Widget> >* viewChildren = children(); + HashSet<RefPtr<Widget> >::const_iterator end = viewChildren->end(); + for (HashSet<RefPtr<Widget> >::const_iterator current = viewChildren->begin(); current != end; ++current) { + Widget* widget = (*current).get(); + if (widget->isFrameView()) { + bool synced = static_cast<FrameView*>(widget)->syncCompositingStateRecursive(); + allSubframesSynced &= synced; + } + } + return allSubframesSynced; +#endif // USE(ACCELERATED_COMPOSITING) + return true; +} + void FrameView::didMoveOnscreen() { RenderView* view = m_frame->contentRenderer(); @@ -603,7 +661,9 @@ void FrameView::layout(bool allowSubtree) // Now update the positions of all layers. beginDeferredRepaints(); - layer->updateLayerPositions(m_doFullRepaint); + layer->updateLayerPositions((m_doFullRepaint ? RenderLayer::DoFullRepaint : 0) + | RenderLayer::CheckForRepaint + | RenderLayer::UpdateCompositingLayers); endDeferredRepaints(); #if USE(ACCELERATED_COMPOSITING) @@ -649,9 +709,6 @@ void FrameView::layout(bool allowSubtree) ASSERT(m_enqueueEvents); } - if (lockedToAnchor()) - m_frame->loader()->gotoAnchor(); - m_nestedLayoutCount--; } @@ -734,11 +791,27 @@ void FrameView::restoreScrollbar() setScrollbarsSuppressed(false); } +void FrameView::maintainScrollPositionAtAnchor(Node* anchorNode) +{ + m_maintainScrollPositionAnchor = anchorNode; + if (!m_maintainScrollPositionAnchor) + return; + + // We need to update the layout before scrolling, otherwise we could + // really mess things up if an anchor scroll comes at a bad moment. + m_frame->document()->updateStyleIfNeeded(); + // Only do a layout if changes have occurred that make it necessary. + if (m_frame->contentRenderer() && m_frame->contentRenderer()->needsLayout()) + layout(); + else + scrollToAnchor(); +} + void FrameView::scrollRectIntoViewRecursively(const IntRect& r) { bool wasInProgrammaticScroll = m_inProgrammaticScroll; m_inProgrammaticScroll = true; - setLockedToAnchor(false); + m_maintainScrollPositionAnchor = 0; ScrollView::scrollRectIntoViewRecursively(r); m_inProgrammaticScroll = wasInProgrammaticScroll; } @@ -747,7 +820,7 @@ void FrameView::setScrollPosition(const IntPoint& scrollPoint) { bool wasInProgrammaticScroll = m_inProgrammaticScroll; m_inProgrammaticScroll = true; - setLockedToAnchor(false); + m_maintainScrollPositionAnchor = 0; ScrollView::setScrollPosition(scrollPoint); m_inProgrammaticScroll = wasInProgrammaticScroll; } @@ -800,6 +873,19 @@ void FrameView::repaintContentRectangle(const IntRect& r, bool immediate) ScrollView::repaintContentRectangle(r, immediate); } +void FrameView::visibleContentsResized() +{ + // We check to make sure the view is attached to a frame() as this method can + // be triggered before the view is attached by Frame::createView(...) setting + // various values such as setScrollBarModes(...) for example. An ASSERT is + // triggered when a view is layout before being attached to a frame(). + if (!frame()->view()) + return; + + if (needsLayout()) + layout(); +} + void FrameView::beginDeferredRepaints() { Page* page = m_frame->page(); @@ -1118,6 +1204,27 @@ void FrameView::resumeScheduledEvents() ASSERT(m_scheduledEvents.isEmpty() || m_enqueueEvents); } +void FrameView::scrollToAnchor() +{ + RefPtr<Node> anchorNode = m_maintainScrollPositionAnchor; + if (!anchorNode) + return; + + if (!anchorNode->renderer()) + return; + + IntRect rect; + if (anchorNode != m_frame->document()) + rect = anchorNode->getRect(); + + // Scroll nested layers and frames to reveal the anchor. + // Align to the top and to the closest side (this matches other browsers). + anchorNode->renderer()->enclosingLayer()->scrollRectToVisible(rect, true, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways); + + // scrollRectToVisible can call into scrollRectIntoViewRecursively(), which resets m_maintainScrollPositionAnchor. + m_maintainScrollPositionAnchor = anchorNode; +} + bool FrameView::updateWidgets() { if (m_nestedLayoutCount > 1 || !m_widgetUpdateSet || m_widgetUpdateSet->isEmpty()) @@ -1161,7 +1268,9 @@ void FrameView::performPostLayoutTasks() if (updateWidgets()) break; } - + + scrollToAnchor(); + resumeScheduledEvents(); if (!root->printing()) { @@ -1326,10 +1435,10 @@ void FrameView::updateControlTints() // to define when controls get the tint and to call this function when that changes. // Optimize the common case where we bring a window to the front while it's still empty. - if (!m_frame || m_frame->loader()->url().isEmpty()) + if (!m_frame || m_frame->loader()->url().isEmpty()) return; - - if (theme()->supportsControlTints() && m_frame->contentRenderer()) { + + if (m_frame->contentRenderer() && m_frame->contentRenderer()->theme()->supportsControlTints()) { if (needsLayout()) layout(); PlatformGraphicsContext* const noContext = 0; @@ -1351,7 +1460,7 @@ void FrameView::setWasScrolledByUser(bool wasScrolledByUser) { if (m_inProgrammaticScroll) return; - setLockedToAnchor(false); + m_maintainScrollPositionAnchor = 0; m_wasScrolledByUser = wasScrolledByUser; } @@ -1395,6 +1504,13 @@ void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) if (needsLayout()) return; +#if USE(ACCELERATED_COMPOSITING) + if (!p->paintingDisabled()) { + if (GraphicsLayer* rootLayer = contentRenderer->compositor()->rootPlatformLayer()) + rootLayer->syncCompositingState(); + } +#endif + ASSERT(!m_isPainting); m_isPainting = true; @@ -1447,11 +1563,13 @@ void FrameView::layoutIfNeededRecursive() if (needsLayout()) layout(); - const HashSet<Widget*>* viewChildren = children(); - HashSet<Widget*>::const_iterator end = viewChildren->end(); - for (HashSet<Widget*>::const_iterator current = viewChildren->begin(); current != end; ++current) - if ((*current)->isFrameView()) - static_cast<FrameView*>(*current)->layoutIfNeededRecursive(); + const HashSet<RefPtr<Widget> >* viewChildren = children(); + HashSet<RefPtr<Widget> >::const_iterator end = viewChildren->end(); + for (HashSet<RefPtr<Widget> >::const_iterator current = viewChildren->begin(); current != end; ++current) { + Widget* widget = (*current).get(); + if (widget->isFrameView()) + static_cast<FrameView*>(widget)->layoutIfNeededRecursive(); + } // layoutIfNeededRecursive is called when we need to make sure layout is up-to-date before // painting, so we need to flush out any deferred repaints too. @@ -1517,4 +1635,142 @@ void FrameView::adjustPageHeight(float *newBottom, float oldTop, float oldBottom *newBottom = oldBottom; } +IntRect FrameView::convertFromRenderer(const RenderObject* renderer, const IntRect& rendererRect) const +{ + IntRect rect = renderer->localToAbsoluteQuad(FloatRect(rendererRect)).enclosingBoundingBox(); + + // Convert from page ("absolute") to FrameView coordinates. + rect.move(-scrollX(), -scrollY()); + + return rect; +} + +IntRect FrameView::convertToRenderer(const RenderObject* renderer, const IntRect& viewRect) const +{ + IntRect rect = viewRect; + + // Convert from FrameView coords into page ("absolute") coordinates. + rect.move(scrollX(), scrollY()); + + // FIXME: we don't have a way to map an absolute rect down to a local quad, so just + // move the rect for now. + rect.setLocation(roundedIntPoint(renderer->absoluteToLocal(rect.location(), false, true /* use transforms */))); + return rect; +} + +IntPoint FrameView::convertFromRenderer(const RenderObject* renderer, const IntPoint& rendererPoint) const +{ + IntPoint point = roundedIntPoint(renderer->localToAbsolute(rendererPoint, false, true /* use transforms */)); + + // Convert from page ("absolute") to FrameView coordinates. + point.move(-scrollX(), -scrollY()); + return point; +} + +IntPoint FrameView::convertToRenderer(const RenderObject* renderer, const IntPoint& viewPoint) const +{ + IntPoint point = viewPoint; + + // Convert from FrameView coords into page ("absolute") coordinates. + point += IntSize(scrollX(), scrollY()); + + return roundedIntPoint(renderer->absoluteToLocal(point, false, true /* use transforms */)); +} + +IntRect FrameView::convertToContainingView(const IntRect& localRect) const +{ + if (const ScrollView* parentScrollView = parent()) { + if (parentScrollView->isFrameView()) { + const FrameView* parentView = static_cast<const FrameView*>(parentScrollView); + // Get our renderer in the parent view + RenderPart* renderer = m_frame->ownerRenderer(); + if (!renderer) + return localRect; + + IntRect rect(localRect); + // Add borders and padding?? + rect.move(renderer->borderLeft() + renderer->paddingLeft(), + renderer->borderTop() + renderer->paddingTop()); + return parentView->convertFromRenderer(renderer, rect); + } + + return Widget::convertToContainingView(localRect); + } + + return localRect; +} + +IntRect FrameView::convertFromContainingView(const IntRect& parentRect) const +{ + if (const ScrollView* parentScrollView = parent()) { + if (parentScrollView->isFrameView()) { + const FrameView* parentView = static_cast<const FrameView*>(parentScrollView); + + // Get our renderer in the parent view + RenderPart* renderer = m_frame->ownerRenderer(); + if (!renderer) + return parentRect; + + IntRect rect = parentView->convertToRenderer(renderer, parentRect); + // Subtract borders and padding + rect.move(-renderer->borderLeft() - renderer->paddingLeft(), + -renderer->borderTop() - renderer->paddingTop()); + return rect; + } + + return Widget::convertFromContainingView(parentRect); + } + + return parentRect; +} + +IntPoint FrameView::convertToContainingView(const IntPoint& localPoint) const +{ + if (const ScrollView* parentScrollView = parent()) { + if (parentScrollView->isFrameView()) { + const FrameView* parentView = static_cast<const FrameView*>(parentScrollView); + + // Get our renderer in the parent view + RenderPart* renderer = m_frame->ownerRenderer(); + if (!renderer) + return localPoint; + + IntPoint point(localPoint); + + // Add borders and padding + point.move(renderer->borderLeft() + renderer->paddingLeft(), + renderer->borderTop() + renderer->paddingTop()); + return parentView->convertFromRenderer(renderer, point); + } + + return Widget::convertToContainingView(localPoint); + } + + return localPoint; +} + +IntPoint FrameView::convertFromContainingView(const IntPoint& parentPoint) const +{ + if (const ScrollView* parentScrollView = parent()) { + if (parentScrollView->isFrameView()) { + const FrameView* parentView = static_cast<const FrameView*>(parentScrollView); + + // Get our renderer in the parent view + RenderPart* renderer = m_frame->ownerRenderer(); + if (!renderer) + return parentPoint; + + IntPoint point = parentView->convertToRenderer(renderer, parentPoint); + // Subtract borders and padding + point.move(-renderer->borderLeft() - renderer->paddingLeft(), + -renderer->borderTop() - renderer->paddingTop()); + return point; + } + + return Widget::convertFromContainingView(parentPoint); + } + + return parentPoint; +} + } // namespace WebCore diff --git a/WebCore/page/FrameView.h b/WebCore/page/FrameView.h index 16eadc5..1bdcfb3 100644 --- a/WebCore/page/FrameView.h +++ b/WebCore/page/FrameView.h @@ -48,7 +48,7 @@ class String; template <typename T> class Timer; -class FrameView : public ScrollView, public RefCounted<FrameView> { +class FrameView : public ScrollView { public: friend class RenderView; @@ -93,18 +93,21 @@ public: bool needsFullRepaint() const { return m_doFullRepaint; } #if USE(ACCELERATED_COMPOSITING) - enum CompositingUpdate { NormalCompositingUpdate, ForcedCompositingUpdate }; - void updateCompositingLayers(CompositingUpdate updateType = NormalCompositingUpdate); + void updateCompositingLayers(); // Called when changes to the GraphicsLayer hierarchy have to be synchronized with // content rendered via the normal painting path. void setNeedsOneShotDrawingSynchronization(); #endif + // Only used with accelerated compositing, but outside the #ifdef to make linkage easier. + // Returns true if the sync was completed. + bool syncCompositingStateRecursive(); void didMoveOnscreen(); void willMoveOffscreen(); void resetScrollbars(); + void detachCustomScrollbars(); void clear(); @@ -125,11 +128,6 @@ public: virtual IntRect windowClipRect(bool clipToContents = true) const; IntRect windowClipRectForLayer(const RenderLayer*, bool clipToLayerContents) const; - virtual bool isActive() const; - virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&); - virtual void valueChanged(Scrollbar*); - virtual void getTickmarks(Vector<IntRect>&) const; - virtual IntRect windowResizerRect() const; virtual void scrollRectIntoViewRecursively(const IntRect&); @@ -184,9 +182,13 @@ public: void adjustPageHeight(float* newBottom, float oldTop, float oldBottom, float bottomLimit); - bool lockedToAnchor() { return m_lockedToAnchor; } - void setLockedToAnchor(bool lockedToAnchor) { m_lockedToAnchor = lockedToAnchor; } + void maintainScrollPositionAtAnchor(Node*); + // Methods to convert points and rects between the coordinate space of the renderer, and this view. + virtual IntRect convertFromRenderer(const RenderObject*, const IntRect&) const; + virtual IntRect convertToRenderer(const RenderObject*, const IntRect&) const; + virtual IntPoint convertFromRenderer(const RenderObject*, const IntPoint&) const; + virtual IntPoint convertToRenderer(const RenderObject*, const IntPoint&) const; private: FrameView(Frame*); @@ -208,11 +210,20 @@ private: virtual void repaintContentRectangle(const IntRect&, bool immediate); virtual void contentsResized() { setNeedsLayout(); } - virtual void visibleContentsResized() - { - if (needsLayout()) - layout(); - } + virtual void visibleContentsResized(); + + // Override ScrollView methods to do point conversion via renderers, in order to + // take transforms into account. + virtual IntRect convertToContainingView(const IntRect&) const; + virtual IntRect convertFromContainingView(const IntRect&) const; + virtual IntPoint convertToContainingView(const IntPoint&) const; + virtual IntPoint convertFromContainingView(const IntPoint&) const; + + // ScrollBarClient interface + virtual void valueChanged(Scrollbar*); + virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&); + virtual bool isActive() const; + virtual void getTickmarks(Vector<IntRect>&) const; void deferredRepaintTimerFired(Timer<FrameView>*); void doDeferredRepaints(); @@ -220,6 +231,7 @@ private: double adjustedDeferredRepaintDelay() const; bool updateWidgets(); + void scrollToAnchor(); static double sCurrentPaintTimeStamp; // used for detecting decoded resource thrash in the cache @@ -289,7 +301,7 @@ private: bool m_isVisuallyNonEmpty; bool m_firstVisuallyNonEmptyLayoutCallbackPending; - bool m_lockedToAnchor; + RefPtr<Node> m_maintainScrollPositionAnchor; }; } // namespace WebCore diff --git a/WebCore/page/Geolocation.cpp b/WebCore/page/Geolocation.cpp index 7010339..875da43 100644 --- a/WebCore/page/Geolocation.cpp +++ b/WebCore/page/Geolocation.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved. + * Copyright (C) 2009 Torch Mobile, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -73,6 +74,8 @@ Geolocation::Geolocation(Frame* frame) void Geolocation::disconnectFrame() { m_service->stopUpdating(); + if (m_frame && m_frame->document()) + m_frame->document()->setUsingGeolocation(false); m_frame = 0; } @@ -143,18 +146,23 @@ void Geolocation::setIsAllowed(bool allowed) } } +void Geolocation::sendError(Vector<RefPtr<GeoNotifier> >& notifiers, PositionError* error) +{ + Vector<RefPtr<GeoNotifier> >::const_iterator end = notifiers.end(); + for (Vector<RefPtr<GeoNotifier> >::const_iterator it = notifiers.begin(); it != end; ++it) { + RefPtr<GeoNotifier> notifier = *it; + + if (notifier->m_errorCallback) + notifier->m_errorCallback->handleEvent(error); + } +} + void Geolocation::sendErrorToOneShots(PositionError* error) { Vector<RefPtr<GeoNotifier> > copy; copyToVector(m_oneShots, copy); - Vector<RefPtr<GeoNotifier> >::const_iterator end = copy.end(); - for (Vector<RefPtr<GeoNotifier> >::const_iterator it = copy.begin(); it != end; ++it) { - RefPtr<GeoNotifier> notifier = *it; - - if (notifier->m_errorCallback) - notifier->m_errorCallback->handleEvent(error); - } + sendError(copy, error); } void Geolocation::sendErrorToWatchers(PositionError* error) @@ -162,12 +170,18 @@ void Geolocation::sendErrorToWatchers(PositionError* error) Vector<RefPtr<GeoNotifier> > copy; copyValuesToVector(m_watchers, copy); - Vector<RefPtr<GeoNotifier> >::const_iterator end = copy.end(); - for (Vector<RefPtr<GeoNotifier> >::const_iterator it = copy.begin(); it != end; ++it) { + sendError(copy, error); +} + +void Geolocation::sendPosition(Vector<RefPtr<GeoNotifier> >& notifiers, Geoposition* position) +{ + Vector<RefPtr<GeoNotifier> >::const_iterator end = notifiers.end(); + for (Vector<RefPtr<GeoNotifier> >::const_iterator it = notifiers.begin(); it != end; ++it) { RefPtr<GeoNotifier> notifier = *it; + ASSERT(notifier->m_successCallback); - if (notifier->m_errorCallback) - notifier->m_errorCallback->handleEvent(error); + notifier->m_timer.stop(); + notifier->m_successCallback->handleEvent(position); } } @@ -176,14 +190,7 @@ void Geolocation::sendPositionToOneShots(Geoposition* position) Vector<RefPtr<GeoNotifier> > copy; copyToVector(m_oneShots, copy); - Vector<RefPtr<GeoNotifier> >::const_iterator end = copy.end(); - for (Vector<RefPtr<GeoNotifier> >::const_iterator it = copy.begin(); it != end; ++it) { - RefPtr<GeoNotifier> notifier = *it; - ASSERT(notifier->m_successCallback); - - notifier->m_timer.stop(); - notifier->m_successCallback->handleEvent(position); - } + sendPosition(copy, position); } void Geolocation::sendPositionToWatchers(Geoposition* position) @@ -191,6 +198,7 @@ void Geolocation::sendPositionToWatchers(Geoposition* position) Vector<RefPtr<GeoNotifier> > copy; copyValuesToVector(m_watchers, copy); +#ifdef MANUAL_MERGE_REQUIRED Vector<RefPtr<GeoNotifier> >::const_iterator end = copy.end(); for (Vector<RefPtr<GeoNotifier> >::const_iterator it = copy.begin(); it != end; ++it) { RefPtr<GeoNotifier> notifier = *it; @@ -199,6 +207,9 @@ void Geolocation::sendPositionToWatchers(Geoposition* position) notifier->m_timer.stop(); notifier->m_successCallback->handleEvent(position); } +#else // MANUAL_MERGE_REQUIRED + sendPosition(copy, position); +#endif // MANUAL_MERGE_REQUIRED } void Geolocation::startTimer(Vector<RefPtr<GeoNotifier> >& notifiers) @@ -240,6 +251,9 @@ void Geolocation::handleError(PositionError* error) sendErrorToWatchers(error); m_oneShots.clear(); + + if (!hasListeners()) + m_service->stopUpdating(); } void Geolocation::requestPermission() @@ -254,10 +268,10 @@ void Geolocation::requestPermission() if (!page) return; + m_allowGeolocation = InProgress; + // Ask the chrome: it maintains the geolocation challenge policy itself. page->chrome()->requestGeolocationPermissionForFrame(m_frame, this); - - m_allowGeolocation = InProgress; } void Geolocation::geolocationServicePositionChanged(GeolocationService*) diff --git a/WebCore/page/Geolocation.h b/WebCore/page/Geolocation.h index 44a7fe0..a3fd5e8 100644 --- a/WebCore/page/Geolocation.h +++ b/WebCore/page/Geolocation.h @@ -89,8 +89,11 @@ private: bool hasListeners() const { return !m_oneShots.isEmpty() || !m_watchers.isEmpty(); } + void sendError(Vector<RefPtr<GeoNotifier> >&, PositionError*); void sendErrorToOneShots(PositionError*); void sendErrorToWatchers(PositionError*); + + void sendPosition(Vector<RefPtr<GeoNotifier> >&, Geoposition*); void sendPositionToOneShots(Geoposition*); void sendPositionToWatchers(Geoposition*); diff --git a/WebCore/page/History.idl b/WebCore/page/History.idl index fa308fb..914d441 100644 --- a/WebCore/page/History.idl +++ b/WebCore/page/History.idl @@ -29,8 +29,8 @@ module window { #if defined(V8_BINDING) && V8_BINDING CheckDomainSecurity, #endif - CustomGetOwnPropertySlot, - CustomPutFunction, + DelegatingGetOwnPropertySlot, + DelegatingPutFunction, CustomDeleteProperty, CustomGetPropertyNames ] History { diff --git a/WebCore/page/Location.cpp b/WebCore/page/Location.cpp index c8780eb..5adc48d 100644 --- a/WebCore/page/Location.cpp +++ b/WebCore/page/Location.cpp @@ -125,8 +125,8 @@ String Location::hash() const if (!m_frame) return String(); - const KURL& url = this->url(); - return url.ref().isEmpty() ? "" : "#" + url.ref(); + const String& fragmentIdentifier = this->url().fragmentIdentifier(); + return fragmentIdentifier.isEmpty() ? "" : "#" + fragmentIdentifier; } String Location::toString() const diff --git a/WebCore/page/Location.idl b/WebCore/page/Location.idl index e7fa31a..7d680f2 100644 --- a/WebCore/page/Location.idl +++ b/WebCore/page/Location.idl @@ -32,12 +32,12 @@ module window { #if defined(V8_BINDING) && V8_BINDING CheckDomainSecurity, #endif - CustomGetOwnPropertySlot, - CustomPutFunction, + DelegatingGetOwnPropertySlot, + DelegatingPutFunction, CustomDeleteProperty, CustomGetPropertyNames, CustomDefineGetter, - CustomPrototypePutFunction, + DelegatingPrototypePutFunction, CustomPrototypeDefineGetter ] Location { attribute [DoNotCheckDomainSecurityOnSet, CustomSetter, V8DisallowShadowing] DOMString href; diff --git a/WebCore/page/MouseEventWithHitTestResults.h b/WebCore/page/MouseEventWithHitTestResults.h index c4e419c..7330d93 100644 --- a/WebCore/page/MouseEventWithHitTestResults.h +++ b/WebCore/page/MouseEventWithHitTestResults.h @@ -28,7 +28,6 @@ namespace WebCore { class Scrollbar; -// FIXME: Why doesn't this class just cache a HitTestResult instead of copying all of HitTestResult's fields over? class MouseEventWithHitTestResults { public: MouseEventWithHitTestResults(const PlatformMouseEvent&, const HitTestResult&); @@ -46,6 +45,6 @@ private: HitTestResult m_hitTestResult; }; -} +} // namespace WebCore -#endif +#endif // MouseEventWithHitTestResults_h diff --git a/WebCore/page/NavigatorBase.cpp b/WebCore/page/NavigatorBase.cpp index 5138b0f..5b0c5d4 100644 --- a/WebCore/page/NavigatorBase.cpp +++ b/WebCore/page/NavigatorBase.cpp @@ -29,6 +29,10 @@ #include "NetworkStateNotifier.h" #include "PlatformString.h" +#if PLATFORM(LINUX) +#include "sys/utsname.h" +#include <wtf/StdLibExtras.h> +#endif #ifndef WEBCORE_NAVIGATOR_PLATFORM #if PLATFORM(MAC) && (PLATFORM(PPC) || PLATFORM(PPC64)) @@ -37,6 +41,8 @@ #define WEBCORE_NAVIGATOR_PLATFORM "MacIntel" #elif PLATFORM(WIN_OS) #define WEBCORE_NAVIGATOR_PLATFORM "Win32" +#elif PLATFORM(SYMBIAN) +#define WEBCORE_NAVIGATOR_PLATFORM "Symbian" #else #define WEBCORE_NAVIGATOR_PLATFORM "" #endif @@ -79,7 +85,15 @@ String NavigatorBase::appVersion() const String NavigatorBase::platform() const { +#if PLATFORM(LINUX) + if (String("") != WEBCORE_NAVIGATOR_PLATFORM) + return WEBCORE_NAVIGATOR_PLATFORM; + struct utsname osname; + DEFINE_STATIC_LOCAL(String, platformName, (uname(&osname) >= 0 ? String(osname.sysname) + String(" ") + String(osname.machine) : "")); + return platformName; +#else return WEBCORE_NAVIGATOR_PLATFORM; +#endif } String NavigatorBase::appCodeName() const diff --git a/WebCore/page/Page.cpp b/WebCore/page/Page.cpp index 70b4459..a13496b 100644 --- a/WebCore/page/Page.cpp +++ b/WebCore/page/Page.cpp @@ -34,6 +34,7 @@ #include "FocusController.h" #include "Frame.h" #include "FrameLoader.h" +#include "FrameLoaderClient.h" #include "FrameTree.h" #include "FrameView.h" #include "HTMLElement.h" @@ -46,6 +47,7 @@ #include "PluginData.h" #include "ProgressTracker.h" #include "RenderWidget.h" +#include "RenderTheme.h" #include "ScriptController.h" #include "SelectionController.h" #include "Settings.h" @@ -57,9 +59,8 @@ #include <wtf/StdLibExtras.h> #if ENABLE(DOM_STORAGE) -#include "LocalStorage.h" -#include "SessionStorage.h" #include "StorageArea.h" +#include "StorageNamespace.h" #endif #if ENABLE(JAVASCRIPT_DEBUGGER) @@ -100,10 +101,11 @@ Page::Page(ChromeClient* chromeClient, ContextMenuClient* contextMenuClient, Edi , m_dragController(new DragController(this, dragClient)) , m_focusController(new FocusController(this)) , m_contextMenuController(new ContextMenuController(this, contextMenuClient)) - , m_inspectorController(InspectorController::create(this, inspectorClient)) + , m_inspectorController(new InspectorController(this, inspectorClient)) , m_settings(new Settings(this)) , m_progress(new ProgressTracker) , m_backForwardList(BackForwardList::create(this)) + , m_theme(RenderTheme::themeForPage(this)) , m_editorClient(editorClient) , m_frameCount(0) , m_tabKeyCyclesThroughElements(true) @@ -120,6 +122,7 @@ Page::Page(ChromeClient* chromeClient, ContextMenuClient* contextMenuClient, Edi , m_debugger(0) , m_customHTMLTokenizerTimeDelay(-1) , m_customHTMLTokenizerChunkSize(-1) + , m_canStartPlugins(true) { if (!allPages) { allPages = new HashSet<Page*>; @@ -210,7 +213,7 @@ void Page::goToItem(HistoryItem* item, FrameLoadType type) const KURL& currentURL = m_mainFrame->loader()->url(); const KURL& newURL = item->url(); - if (newURL.hasRef() && equalIgnoringRef(currentURL, newURL)) + if (newURL.hasFragmentIdentifier() && equalIgnoringFragmentIdentifier(currentURL, newURL)) databasePolicy = DatabasePolicyContinue; #endif m_mainFrame->loader()->stopAllLoaders(databasePolicy); @@ -297,6 +300,19 @@ PluginData* Page::pluginData() const return m_pluginData.get(); } +void Page::addUnstartedPlugin(PluginView* view) +{ + ASSERT(!m_canStartPlugins); + m_unstartedPlugins.add(view); +} + +void Page::removeUnstartedPlugin(PluginView* view) +{ + ASSERT(!m_canStartPlugins); + ASSERT(m_unstartedPlugins.contains(view)); + m_unstartedPlugins.remove(view); +} + static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag) { return forward @@ -498,7 +514,9 @@ void Page::removeAllVisitedLinks() void Page::allVisitedStateChanged(PageGroup* group) { ASSERT(group); - ASSERT(allPages); + if (!allPages) + return; + HashSet<Page*>::iterator pagesEnd = allPages->end(); for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) { Page* page = *it; @@ -514,7 +532,9 @@ void Page::allVisitedStateChanged(PageGroup* group) void Page::visitedStateChanged(PageGroup* group, LinkHash visitedLinkHash) { ASSERT(group); - ASSERT(allPages); + if (!allPages) + return; + HashSet<Page*>::iterator pagesEnd = allPages->end(); for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) { Page* page = *it; @@ -548,17 +568,16 @@ void Page::setDebugger(JSC::Debugger* debugger) } #if ENABLE(DOM_STORAGE) -SessionStorage* Page::sessionStorage(bool optionalCreate) +StorageNamespace* Page::sessionStorage(bool optionalCreate) { if (!m_sessionStorage && optionalCreate) - m_sessionStorage = SessionStorage::create(this); + m_sessionStorage = StorageNamespace::sessionStorageNamespace(); return m_sessionStorage.get(); } -void Page::setSessionStorage(PassRefPtr<SessionStorage> newStorage) +void Page::setSessionStorage(PassRefPtr<StorageNamespace> newStorage) { - ASSERT(newStorage->page() == this); m_sessionStorage = newStorage; } #endif diff --git a/WebCore/page/Page.h b/WebCore/page/Page.h index eedd24c..9d9af86 100644 --- a/WebCore/page/Page.h +++ b/WebCore/page/Page.h @@ -59,29 +59,38 @@ namespace WebCore { class Node; class PageGroup; class PluginData; + class PluginView; class ProgressTracker; + class RenderTheme; class VisibleSelection; class SelectionController; + class Settings; #if ENABLE(DOM_STORAGE) - class SessionStorage; + class StorageNamespace; #endif - class Settings; #if ENABLE(WML) class WMLPageState; #endif enum FindDirection { FindDirectionForward, FindDirectionBackward }; - class Page : Noncopyable { + class Page : public Noncopyable { public: static void setNeedsReapplyStyles(); Page(ChromeClient*, ContextMenuClient*, EditorClient*, DragClient*, InspectorClient*); ~Page(); - + + RenderTheme* theme() const { return m_theme.get(); }; + static void refreshPlugins(bool reload); PluginData* pluginData() const; + void setCanStartPlugins(bool); + bool canStartPlugins() const { return m_canStartPlugins; } + void addUnstartedPlugin(PluginView*); + void removeUnstartedPlugin(PluginView*); + EditorClient* editorClient() const { return m_editorClient; } void setMainFrame(PassRefPtr<Frame>); @@ -176,8 +185,8 @@ namespace WebCore { static void visitedStateChanged(PageGroup*, LinkHash visitedHash); #if ENABLE(DOM_STORAGE) - SessionStorage* sessionStorage(bool optionalCreate = true); - void setSessionStorage(PassRefPtr<SessionStorage>); + StorageNamespace* sessionStorage(bool optionalCreate = true); + void setSessionStorage(PassRefPtr<StorageNamespace>); #endif #if ENABLE(WML) @@ -206,7 +215,7 @@ namespace WebCore { OwnPtr<DragController> m_dragController; OwnPtr<FocusController> m_focusController; OwnPtr<ContextMenuController> m_contextMenuController; - RefPtr<InspectorController> m_inspectorController; + OwnPtr<InspectorController> m_inspectorController; OwnPtr<Settings> m_settings; OwnPtr<ProgressTracker> m_progress; @@ -217,6 +226,8 @@ namespace WebCore { mutable RefPtr<PluginData> m_pluginData; + RefPtr<RenderTheme> m_theme; + EditorClient* m_editorClient; int m_frameCount; @@ -247,8 +258,11 @@ namespace WebCore { double m_customHTMLTokenizerTimeDelay; int m_customHTMLTokenizerChunkSize; + bool m_canStartPlugins; + HashSet<PluginView*> m_unstartedPlugins; + #if ENABLE(DOM_STORAGE) - RefPtr<SessionStorage> m_sessionStorage; + RefPtr<StorageNamespace> m_sessionStorage; #endif #if PLATFORM(WIN) || (PLATFORM(WX) && defined(__WXMSW__)) || (PLATFORM(QT) && defined(Q_WS_WIN)) diff --git a/WebCore/page/PageGroup.cpp b/WebCore/page/PageGroup.cpp index f098211..c23cb86 100644 --- a/WebCore/page/PageGroup.cpp +++ b/WebCore/page/PageGroup.cpp @@ -32,8 +32,7 @@ #include "Settings.h" #if ENABLE(DOM_STORAGE) -#include "LocalStorage.h" -#include "StorageArea.h" +#include "StorageNamespace.h" #endif #if PLATFORM(CHROMIUM) @@ -181,8 +180,9 @@ void PageGroup::setShouldTrackVisitedLinks(bool shouldTrack) } #if ENABLE(DOM_STORAGE) -LocalStorage* PageGroup::localStorage() +StorageNamespace* PageGroup::localStorage() { +#ifdef MANUAL_MERGE_REQUIRED if (!m_localStorage) { // Need a page in this page group to query the settings for the local storage database path. Page* page = *m_pages.begin(); @@ -190,6 +190,15 @@ LocalStorage* PageGroup::localStorage() m_localStorage = LocalStorage::localStorage(page->settings()->localStorageDatabasePath()); } +#else // MANUAL_MERGE_REQUIRED + if (!m_localStorage) { + // Need a page in this page group to query the settings for the local storage database path. + Page* page = *m_pages.begin(); + ASSERT(page); + m_localStorage = StorageNamespace::localStorageNamespace(page->settings()->localStorageDatabasePath()); + } + +#endif // MANUAL_MERGE_REQUIRED return m_localStorage.get(); } #endif diff --git a/WebCore/page/PageGroup.h b/WebCore/page/PageGroup.h index d9ffabd..8c842b9 100644 --- a/WebCore/page/PageGroup.h +++ b/WebCore/page/PageGroup.h @@ -34,10 +34,10 @@ namespace WebCore { class KURL; - class LocalStorage; class Page; + class StorageNamespace; - class PageGroup : Noncopyable { + class PageGroup : public Noncopyable { public: PageGroup(const String& name); PageGroup(Page*); @@ -63,7 +63,7 @@ namespace WebCore { unsigned identifier() { return m_identifier; } #if ENABLE(DOM_STORAGE) - LocalStorage* localStorage(); + StorageNamespace* localStorage(); #endif private: @@ -80,7 +80,7 @@ namespace WebCore { unsigned m_identifier; #if ENABLE(DOM_STORAGE) - RefPtr<LocalStorage> m_localStorage; + RefPtr<StorageNamespace> m_localStorage; #endif }; diff --git a/WebCore/page/PageGroupLoadDeferrer.h b/WebCore/page/PageGroupLoadDeferrer.h index 1bdb45c..d443ebd 100644 --- a/WebCore/page/PageGroupLoadDeferrer.h +++ b/WebCore/page/PageGroupLoadDeferrer.h @@ -28,7 +28,7 @@ namespace WebCore { class Frame; class Page; - class PageGroupLoadDeferrer : Noncopyable { + class PageGroupLoadDeferrer : public Noncopyable { public: PageGroupLoadDeferrer(Page*, bool deferSelf); ~PageGroupLoadDeferrer(); diff --git a/WebCore/page/PrintContext.cpp b/WebCore/page/PrintContext.cpp index 2202559..b855ca5 100644 --- a/WebCore/page/PrintContext.cpp +++ b/WebCore/page/PrintContext.cpp @@ -53,7 +53,7 @@ void PrintContext::computePageRects(const FloatRect& printRect, float headerHeig if (!m_frame->document() || !m_frame->view() || !m_frame->document()->renderer()) return; - RenderView* root = static_cast<RenderView*>(m_frame->document()->renderer()); + RenderView* root = toRenderView(m_frame->document()->renderer()); if (!root) { LOG_ERROR("document to be printed has no renderer"); diff --git a/WebCore/page/SecurityOrigin.cpp b/WebCore/page/SecurityOrigin.cpp index 187ec31..baafd4e 100644 --- a/WebCore/page/SecurityOrigin.cpp +++ b/WebCore/page/SecurityOrigin.cpp @@ -33,10 +33,41 @@ #include "FrameLoader.h" #include "KURL.h" #include "PlatformString.h" +#include "StringHash.h" +#include <wtf/HashSet.h> #include <wtf/StdLibExtras.h> namespace WebCore { +typedef HashSet<String, CaseFoldingHash> URLSchemesMap; + +static URLSchemesMap& localSchemes() +{ + DEFINE_STATIC_LOCAL(URLSchemesMap, localSchemes, ()); + + if (localSchemes.isEmpty()) { + localSchemes.add("file"); +#if PLATFORM(MAC) + localSchemes.add("applewebdata"); +#endif +#if PLATFORM(QT) + localSchemes.add("qrc"); +#endif + } + + return localSchemes; +} + +static URLSchemesMap& noAccessSchemes() +{ + DEFINE_STATIC_LOCAL(URLSchemesMap, noAccessSchemes, ()); + + if (noAccessSchemes.isEmpty()) + noAccessSchemes.add("data"); + + return noAccessSchemes; +} + static bool isDefaultPortForProtocol(unsigned short port, const String& protocol) { if (protocol.isEmpty()) @@ -66,7 +97,7 @@ SecurityOrigin::SecurityOrigin(const KURL& url) m_protocol = ""; // Some URLs are not allowed access to anything other than themselves. - if (FrameLoader::shouldTreatURLSchemeAsNoAccess(m_protocol)) + if (shouldTreatURLSchemeAsNoAccess(m_protocol)) m_noAccess = true; // document.domain starts as m_host, but can be set by the DOM. @@ -193,7 +224,7 @@ void SecurityOrigin::grantUniversalAccess() bool SecurityOrigin::isLocal() const { - return FrameLoader::shouldTreatURLSchemeAsLocal(m_protocol); + return shouldTreatURLSchemeAsLocal(m_protocol); } bool SecurityOrigin::isSecureTransitionTo(const KURL& url) const @@ -307,4 +338,62 @@ bool SecurityOrigin::isSameSchemeHostPort(const SecurityOrigin* other) const return true; } +// static +void SecurityOrigin::registerURLSchemeAsLocal(const String& scheme) +{ + localSchemes().add(scheme); +} + +// static +bool SecurityOrigin::shouldTreatURLAsLocal(const String& url) +{ + // This avoids an allocation of another String and the HashSet contains() + // call for the file: and http: schemes. + if (url.length() >= 5) { + const UChar* s = url.characters(); + if (s[0] == 'h' && s[1] == 't' && s[2] == 't' && s[3] == 'p' && s[4] == ':') + return false; + if (s[0] == 'f' && s[1] == 'i' && s[2] == 'l' && s[3] == 'e' && s[4] == ':') + return true; + } + + int loc = url.find(':'); + if (loc == -1) + return false; + + String scheme = url.left(loc); + return localSchemes().contains(scheme); +} + +// static +bool SecurityOrigin::shouldTreatURLSchemeAsLocal(const String& scheme) +{ + // This avoids an allocation of another String and the HashSet contains() + // call for the file: and http: schemes. + if (scheme.length() == 4) { + const UChar* s = scheme.characters(); + if (s[0] == 'h' && s[1] == 't' && s[2] == 't' && s[3] == 'p') + return false; + if (s[0] == 'f' && s[1] == 'i' && s[2] == 'l' && s[3] == 'e') + return true; + } + + if (scheme.isEmpty()) + return false; + + return localSchemes().contains(scheme); +} + +// static +void SecurityOrigin::registerURLSchemeAsNoAccess(const String& scheme) +{ + noAccessSchemes().add(scheme); +} + +// static +bool SecurityOrigin::shouldTreatURLSchemeAsNoAccess(const String& scheme) +{ + return noAccessSchemes().contains(scheme); +} + } // namespace WebCore diff --git a/WebCore/page/SecurityOrigin.h b/WebCore/page/SecurityOrigin.h index 96f85df..ab92683 100644 --- a/WebCore/page/SecurityOrigin.h +++ b/WebCore/page/SecurityOrigin.h @@ -128,6 +128,13 @@ namespace WebCore { // (and whether it was set) but considering the host. It is used for postMessage. bool isSameSchemeHostPort(const SecurityOrigin*) const; + static void registerURLSchemeAsLocal(const String&); + static bool shouldTreatURLAsLocal(const String&); + static bool shouldTreatURLSchemeAsLocal(const String&); + + static void registerURLSchemeAsNoAccess(const String&); + static bool shouldTreatURLSchemeAsNoAccess(const String&); + private: explicit SecurityOrigin(const KURL&); explicit SecurityOrigin(const SecurityOrigin*); diff --git a/WebCore/page/Settings.cpp b/WebCore/page/Settings.cpp index b67cf44..b36d458 100644 --- a/WebCore/page/Settings.cpp +++ b/WebCore/page/Settings.cpp @@ -28,6 +28,7 @@ #include "Frame.h" #include "FrameTree.h" +#include "FrameView.h" #include "HistoryItem.h" #include "Page.h" #include "PageCache.h" @@ -44,7 +45,7 @@ static void setNeedsReapplyStylesInAllFrames(Page* page) } #if USE(SAFARI_THEME) -bool Settings::gShouldPaintNativeControls = false; +bool Settings::gShouldPaintNativeControls = true; #endif Settings::Settings(Page* page) @@ -75,6 +76,7 @@ Settings::Settings(Page* page) , m_arePluginsEnabled(false) , m_databasesEnabled(false) , m_localStorageEnabled(false) + , m_sessionStorageEnabled(true) , m_isJavaScriptEnabled(false) , m_isWebSecurityEnabled(true) , m_allowUniversalAccessFromFileURLs(true) @@ -86,6 +88,7 @@ Settings::Settings(Page* page) #endif , m_needsAdobeFrameReloadingQuirk(false) , m_needsKeyboardEventDisambiguationQuirks(false) + , m_treatsAnyTextCSSLinkAsStylesheet(false) , m_needsLeopardMailQuirks(false) , m_needsTigerMailQuirks(false) , m_isDOMPasteAllowed(false) @@ -98,6 +101,7 @@ Settings::Settings(Page* page) , m_needsSiteSpecificQuirks(false) , m_fontRenderingMode(0) , m_webArchiveDebugModeEnabled(false) + , m_localFileContentSniffingEnabled(false) , m_inApplicationChromeMode(false) , m_offlineWebApplicationCacheEnabled(false) , m_shouldPaintCustomScrollbars(false) @@ -115,6 +119,8 @@ Settings::Settings(Page* page) // FIXME: This should really be disabled by default as it makes platforms that don't support the feature download files // they can't use by. Leaving enabled for now to not change existing behavior. , m_downloadableBinaryFontsEnabled(true) + , m_xssAuditorEnabled(false) + , m_acceleratedCompositingEnabled(true) { // A Frame may not have been created yet, so we initialize the AtomicString // hash before trying to use it. @@ -261,6 +267,11 @@ void Settings::setLocalStorageEnabled(bool localStorageEnabled) m_localStorageEnabled = localStorageEnabled; } +void Settings::setSessionStorageEnabled(bool sessionStorageEnabled) +{ + m_sessionStorageEnabled = sessionStorageEnabled; +} + void Settings::setPrivateBrowsingEnabled(bool privateBrowsingEnabled) { m_privateBrowsingEnabled = privateBrowsingEnabled; @@ -333,6 +344,11 @@ void Settings::setNeedsKeyboardEventDisambiguationQuirks(bool needsQuirks) m_needsKeyboardEventDisambiguationQuirks = needsQuirks; } +void Settings::setTreatsAnyTextCSSLinkAsStylesheet(bool treatsAnyTextCSSLinkAsStylesheet) +{ + m_treatsAnyTextCSSLinkAsStylesheet = treatsAnyTextCSSLinkAsStylesheet; +} + void Settings::setNeedsLeopardMailQuirks(bool needsQuirks) { m_needsLeopardMailQuirks = needsQuirks; @@ -508,6 +524,11 @@ void Settings::setWebArchiveDebugModeEnabled(bool enabled) m_webArchiveDebugModeEnabled = enabled; } +void Settings::setLocalFileContentSniffingEnabled(bool enabled) +{ + m_localFileContentSniffingEnabled = enabled; +} + void Settings::setLocalStorageDatabasePath(const String& path) { m_localStorageDatabasePath = path; @@ -569,4 +590,18 @@ void Settings::setDownloadableBinaryFontsEnabled(bool downloadableBinaryFontsEna m_downloadableBinaryFontsEnabled = downloadableBinaryFontsEnabled; } +void Settings::setXSSAuditorEnabled(bool xssAuditorEnabled) +{ + m_xssAuditorEnabled = xssAuditorEnabled; +} + +void Settings::setAcceleratedCompositingEnabled(bool enabled) +{ + if (m_acceleratedCompositingEnabled == enabled) + return; + + m_acceleratedCompositingEnabled = enabled; + setNeedsReapplyStylesInAllFrames(m_page); +} + } // namespace WebCore diff --git a/WebCore/page/Settings.h b/WebCore/page/Settings.h index f2f4279..574fed7 100644 --- a/WebCore/page/Settings.h +++ b/WebCore/page/Settings.h @@ -148,6 +148,9 @@ namespace WebCore { void setLocalStorageEnabled(bool); bool localStorageEnabled() const { return m_localStorageEnabled; } + void setSessionStorageEnabled(bool); + bool sessionStorageEnabled() const { return m_sessionStorageEnabled; } + void setPrivateBrowsingEnabled(bool); bool privateBrowsingEnabled() const { return m_privateBrowsingEnabled; } @@ -186,6 +189,9 @@ namespace WebCore { void setNeedsKeyboardEventDisambiguationQuirks(bool); bool needsKeyboardEventDisambiguationQuirks() const { return m_needsKeyboardEventDisambiguationQuirks; } + void setTreatsAnyTextCSSLinkAsStylesheet(bool); + bool treatsAnyTextCSSLinkAsStylesheet() const { return m_treatsAnyTextCSSLinkAsStylesheet; } + void setNeedsLeopardMailQuirks(bool); bool needsLeopardMailQuirks() const { return m_needsLeopardMailQuirks; } @@ -243,6 +249,9 @@ namespace WebCore { void setWebArchiveDebugModeEnabled(bool); bool webArchiveDebugModeEnabled() const { return m_webArchiveDebugModeEnabled; } + void setLocalFileContentSniffingEnabled(bool); + bool localFileContentSniffingEnabled() const { return m_localFileContentSniffingEnabled; } + void setLocalStorageDatabasePath(const String&); const String& localStorageDatabasePath() const { return m_localStorageDatabasePath; } @@ -279,6 +288,12 @@ namespace WebCore { void setDownloadableBinaryFontsEnabled(bool); bool downloadableBinaryFontsEnabled() const { return m_downloadableBinaryFontsEnabled; } + void setXSSAuditorEnabled(bool); + bool xssAuditorEnabled() const { return m_xssAuditorEnabled; } + + void setAcceleratedCompositingEnabled(bool); + bool acceleratedCompositingEnabled() const { return m_acceleratedCompositingEnabled; } + private: Page* m_page; @@ -340,6 +355,7 @@ namespace WebCore { bool m_arePluginsEnabled : 1; bool m_databasesEnabled : 1; bool m_localStorageEnabled : 1; + bool m_sessionStorageEnabled : 1; bool m_isJavaScriptEnabled : 1; bool m_isWebSecurityEnabled : 1; bool m_allowUniversalAccessFromFileURLs: 1; @@ -351,6 +367,7 @@ namespace WebCore { #endif bool m_needsAdobeFrameReloadingQuirk : 1; bool m_needsKeyboardEventDisambiguationQuirks : 1; + bool m_treatsAnyTextCSSLinkAsStylesheet : 1; bool m_needsLeopardMailQuirks : 1; bool m_needsTigerMailQuirks : 1; bool m_isDOMPasteAllowed : 1; @@ -363,6 +380,7 @@ namespace WebCore { bool m_needsSiteSpecificQuirks : 1; unsigned m_fontRenderingMode : 1; bool m_webArchiveDebugModeEnabled : 1; + bool m_localFileContentSniffingEnabled : 1; bool m_inApplicationChromeMode : 1; bool m_offlineWebApplicationCacheEnabled : 1; bool m_shouldPaintCustomScrollbars : 1; @@ -372,6 +390,8 @@ namespace WebCore { bool m_allowScriptsToCloseWindows : 1; unsigned m_editingBehavior : 1; bool m_downloadableBinaryFontsEnabled : 1; + bool m_xssAuditorEnabled : 1; + bool m_acceleratedCompositingEnabled : 1; #if USE(SAFARI_THEME) static bool gShouldPaintNativeControls; diff --git a/WebCore/page/XSSAuditor.cpp b/WebCore/page/XSSAuditor.cpp new file mode 100644 index 0000000..70b691b --- /dev/null +++ b/WebCore/page/XSSAuditor.cpp @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2008, 2009 Daniel Bates (dbates@intudata.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE 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 "XSSAuditor.h" + +#include <wtf/StdLibExtras.h> +#include <wtf/Vector.h> + +#include "Console.h" +#include "CString.h" +#include "DocumentLoader.h" +#include "DOMWindow.h" +#include "Frame.h" +#include "KURL.h" +#include "PreloadScanner.h" +#include "ResourceResponseBase.h" +#include "ScriptSourceCode.h" +#include "Settings.h" +#include "TextResourceDecoder.h" + +using namespace WTF; + +namespace WebCore { + +static bool isNonCanonicalCharacter(UChar c) +{ + // Note, we don't remove backslashes like PHP stripslashes(), which among other things converts "\\0" to the \0 character. + // Instead, we remove backslashes and zeros (since the string "\\0" =(remove backslashes)=> "0"). However, this has the + // adverse effect that we remove any legitimate zeros from a string. + // + // For instance: new String("http://localhost:8000") => new String("http://localhost:8"). + return (c == '\\' || c == '0' || c < ' ' || c == 127); +} + +XSSAuditor::XSSAuditor(Frame* frame) + : m_frame(frame) +{ +} + +XSSAuditor::~XSSAuditor() +{ +} + +bool XSSAuditor::isEnabled() const +{ + Settings* settings = m_frame->settings(); + return (settings && settings->xssAuditorEnabled()); +} + +bool XSSAuditor::canEvaluate(const String& code) const +{ + if (!isEnabled()) + return true; + + if (findInRequest(code, false)) { + DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request.\n")); + m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); + return false; + } + return true; +} + +bool XSSAuditor::canEvaluateJavaScriptURL(const String& code) const +{ + if (!isEnabled()) + return true; + + if (findInRequest(code)) { + DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request.\n")); + m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); + return false; + } + return true; +} + +bool XSSAuditor::canCreateInlineEventListener(const String&, const String& code) const +{ + if (!isEnabled()) + return true; + + if (findInRequest(code)) { + DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request.\n")); + m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); + return false; + } + return true; +} + +bool XSSAuditor::canLoadExternalScriptFromSrc(const String& context, const String& url) const +{ + if (!isEnabled()) + return true; + + if (findInRequest(context + url)) { + DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request.\n")); + m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); + return false; + } + return true; +} + +bool XSSAuditor::canLoadObject(const String& url) const +{ + if (!isEnabled()) + return true; + + if (findInRequest(url)) { + DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request")); + m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); + return false; + } + return true; +} + +bool XSSAuditor::canSetBaseElementURL(const String& url) const +{ + if (!isEnabled()) + return true; + + KURL baseElementURL(m_frame->document()->url(), url); + if (m_frame->document()->url().host() != baseElementURL.host() && findInRequest(url)) { + DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request")); + m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); + return false; + } + return true; +} + +String XSSAuditor::canonicalize(const String& string) +{ + String result = decodeHTMLEntities(string); + return result.removeCharacters(&isNonCanonicalCharacter); +} + +String XSSAuditor::decodeURL(const String& string, const TextEncoding& encoding, bool decodeHTMLentities) +{ + String result; + String url = string; + + url.replace('+', ' '); + result = decodeURLEscapeSequences(url); + String decodedResult = encoding.decode(result.utf8().data(), result.length()); + if (!decodedResult.isEmpty()) + result = decodedResult; + if (decodeHTMLentities) + result = decodeHTMLEntities(result); + return result; +} + +String XSSAuditor::decodeHTMLEntities(const String& string, bool leaveUndecodableHTMLEntitiesUntouched) +{ + SegmentedString source(string); + SegmentedString sourceShadow; + Vector<UChar> result; + + while (!source.isEmpty()) { + UChar cc = *source; + source.advance(); + + if (cc != '&') { + result.append(cc); + continue; + } + + if (leaveUndecodableHTMLEntitiesUntouched) + sourceShadow = source; + bool notEnoughCharacters = false; + unsigned entity = PreloadScanner::consumeEntity(source, notEnoughCharacters); + // We ignore notEnoughCharacters because we might as well use this loop + // to copy the remaining characters into |result|. + + if (entity > 0xFFFF) { + result.append(U16_LEAD(entity)); + result.append(U16_TRAIL(entity)); + } else if (entity && (!leaveUndecodableHTMLEntitiesUntouched || entity != 0xFFFD)){ + result.append(entity); + } else { + result.append('&'); + if (leaveUndecodableHTMLEntitiesUntouched) + source = sourceShadow; + } + } + + return String::adopt(result); +} + +bool XSSAuditor::findInRequest(const String& string, bool decodeHTMLentities) const +{ + bool result = false; + Frame* parentFrame = m_frame->tree()->parent(); + if (parentFrame && m_frame->document()->url() == blankURL()) + result = findInRequest(parentFrame, string, decodeHTMLentities); + if (!result) + result = findInRequest(m_frame, string, decodeHTMLentities); + return result; +} + +bool XSSAuditor::findInRequest(Frame* frame, const String& string, bool decodeHTMLentities) const +{ + ASSERT(frame->document()); + String pageURL = frame->document()->url().string(); + + if (!frame->document()->decoder()) { + // Note, JavaScript URLs do not have a charset. + return false; + } + + if (protocolIs(pageURL, "data")) + return false; + + if (string.isEmpty()) + return false; + + String canonicalizedString = canonicalize(string); + if (canonicalizedString.isEmpty()) + return false; + + if (string.length() < pageURL.length()) { + // The string can actually fit inside the pageURL. + String decodedPageURL = canonicalize(decodeURL(pageURL, frame->document()->decoder()->encoding(), decodeHTMLentities)); + if (decodedPageURL.find(canonicalizedString, 0, false) != -1) + return true; // We've found the smoking gun. + } + + FormData* formDataObj = frame->loader()->documentLoader()->originalRequest().httpBody(); + if (formDataObj && !formDataObj->isEmpty()) { + String formData = formDataObj->flattenToString(); + if (string.length() < formData.length()) { + // Notice it is sufficient to compare the length of the string to + // the url-encoded POST data because the length of the url-decoded + // code is less than or equal to the length of the url-encoded + // string. + String decodedFormData = canonicalize(decodeURL(formData, frame->document()->decoder()->encoding(), decodeHTMLentities)); + if (decodedFormData.find(canonicalizedString, 0, false) != -1) + return true; // We found the string in the POST data. + } + } + + return false; +} + +} // namespace WebCore + diff --git a/WebCore/page/XSSAuditor.h b/WebCore/page/XSSAuditor.h new file mode 100644 index 0000000..26f10ab --- /dev/null +++ b/WebCore/page/XSSAuditor.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2008, 2009 Daniel Bates (dbates@intudata.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE 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 XSSAuditor_h +#define XSSAuditor_h + +#include "PlatformString.h" +#include "TextEncoding.h" + +namespace WebCore { + + class Frame; + class ScriptSourceCode; + + // The XSSAuditor class is used to prevent type 1 cross-site scripting + // vulnerabilites (also known as reflected vulnerabilities). + // + // More specifically, the XSSAuditor class decides whether the execution of + // a script is to be allowed or denied based on the content of any + // user-submitted data, including: + // + // * the query string of the URL. + // * the HTTP-POST data. + // + // If the source code of a script resembles any user-submitted data then it + // is denied execution. + // + // When you instantiate the XSSAuditor you must specify the {@link Frame} + // of the page that you wish to audit. + // + // Bindings + // + // An XSSAuditor is instantiated within the contructor of a + // ScriptController object and passed the Frame the script originated. The + // ScriptController calls back to the XSSAuditor to determine whether a + // JavaScript script is safe to execute before executing it. The following + // methods call into XSSAuditor: + // + // * ScriptController::evaluate - used to evaluate JavaScript scripts. + // * ScriptController::createInlineEventListener - used to create JavaScript event handlers. + // * HTMLTokenizer::scriptHandler - used to load external JavaScript scripts. + // + class XSSAuditor { + public: + XSSAuditor(Frame*); + ~XSSAuditor(); + + bool isEnabled() const; + + // Determines whether the script should be allowed or denied execution + // based on the content of any user-submitted data. + bool canEvaluate(const String& code) const; + + // Determines whether the JavaScript URL should be allowed or denied execution + // based on the content of any user-submitted data. + bool canEvaluateJavaScriptURL(const String& code) const; + + // Determines whether the event listener should be created based on the + // content of any user-submitted data. + bool canCreateInlineEventListener(const String& functionName, const String& code) const; + + // Determines whether the external script should be loaded based on the + // content of any user-submitted data. + bool canLoadExternalScriptFromSrc(const String& context, const String& url) const; + + // Determines whether object should be loaded based on the content of + // any user-submitted data. + // + // This method is called by FrameLoader::requestObject. + bool canLoadObject(const String& url) const; + + // Determines whether the base URL should be changed based on the content + // of any user-submitted data. + // + // This method is called by HTMLBaseElement::process. + bool canSetBaseElementURL(const String& url) const; + + private: + static String canonicalize(const String&); + + static String decodeURL(const String& url, const TextEncoding& encoding = UTF8Encoding(), bool decodeHTMLentities = true); + + static String decodeHTMLEntities(const String&, bool leaveUndecodableHTMLEntitiesUntouched = true); + + bool findInRequest(const String&, bool decodeHTMLentities = true) const; + + bool findInRequest(Frame*, const String&, bool decodeHTMLentities = true) const; + + // The frame to audit. + Frame* m_frame; + }; + +} // namespace WebCore + +#endif // XSSAuditor_h diff --git a/WebCore/page/android/DragControllerAndroid.cpp b/WebCore/page/android/DragControllerAndroid.cpp index 7a52b56..99e18a6 100644 --- a/WebCore/page/android/DragControllerAndroid.cpp +++ b/WebCore/page/android/DragControllerAndroid.cpp @@ -43,7 +43,7 @@ DragOperation DragController::dragOperation(DragData* dragData) if (dragData->containsURL()) return DragOperationCopy; - return DragOperationNone; + return DragOperationNone; } void DragController::cleanupAfterSystemDrag() diff --git a/WebCore/page/android/EventHandlerAndroid.cpp b/WebCore/page/android/EventHandlerAndroid.cpp index df73fe0..b52ca22 100644 --- a/WebCore/page/android/EventHandlerAndroid.cpp +++ b/WebCore/page/android/EventHandlerAndroid.cpp @@ -39,7 +39,13 @@ namespace WebCore { +#ifdef MANUAL_MERGE_REQUIRED bool EventHandler::tabsToAllControls(KeyboardEvent* ) const +#else // MANUAL_MERGE_REQUIRED +unsigned EventHandler::s_accessKeyModifiers = PlatformKeyboardEvent::AltKey; + +bool EventHandler::tabsToAllControls(KeyboardEvent*) const +#endif // MANUAL_MERGE_REQUIRED { return true; } @@ -56,8 +62,7 @@ bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestR RenderObject* target = event.targetNode() ? event.targetNode()->renderer() : 0; if (!target || !target->isWidget()) return false; - - return passMouseDownEventToWidget(static_cast<RenderWidget*>(target)->widget()); + return passMouseDownEventToWidget(toRenderWidget(target)->widget()); } bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget) diff --git a/WebCore/page/animation/AnimationBase.cpp b/WebCore/page/animation/AnimationBase.cpp index 7b8a189..7503f0a 100644 --- a/WebCore/page/animation/AnimationBase.cpp +++ b/WebCore/page/animation/AnimationBase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -45,6 +45,8 @@ #include "MatrixTransformOperation.h" #include "Matrix3DTransformOperation.h" #include "RenderBox.h" +#include "RenderLayer.h" +#include "RenderLayerBacking.h" #include "RenderStyle.h" #include "UnitBezier.h" @@ -113,11 +115,23 @@ static inline IntSize blendFunc(const AnimationBase* anim, const IntSize& from, blendFunc(anim, from.height(), to.height(), progress)); } +static inline ShadowStyle blendFunc(const AnimationBase* anim, ShadowStyle from, ShadowStyle to, double progress) +{ + if (from == to) + return to; + + double fromVal = from == Normal ? 1 : 0; + double toVal = to == Normal ? 1 : 0; + double result = blendFunc(anim, fromVal, toVal, progress); + return result > 0 ? Normal : Inset; +} + static inline ShadowData* blendFunc(const AnimationBase* anim, const ShadowData* from, const ShadowData* to, double progress) { ASSERT(from && to); return new ShadowData(blendFunc(anim, from->x, to->x, progress), blendFunc(anim, from->y, to->y, progress), - blendFunc(anim, from->blur, to->blur, progress), blendFunc(anim, from->color, to->color, progress)); + blendFunc(anim, from->blur, to->blur, progress), blendFunc(anim, from->spread, to->spread, progress), + blendFunc(anim, from->style, to->style, progress), blendFunc(anim, from->color, to->color, progress)); } static inline TransformOperations blendFunc(const AnimationBase* anim, const TransformOperations& from, const TransformOperations& to, double progress) @@ -300,7 +314,7 @@ public: { ShadowData* shadowA = (a->*m_getter)(); ShadowData* shadowB = (b->*m_getter)(); - ShadowData defaultShadowData(0, 0, 0, Color::transparent); + ShadowData defaultShadowData(0, 0, 0, 0, Normal, Color::transparent); if (!shadowA) shadowA = &defaultShadowData; @@ -404,8 +418,15 @@ static void ensurePropertyMap() gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyRight, &RenderStyle::right, &RenderStyle::setRight)); gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyTop, &RenderStyle::top, &RenderStyle::setTop)); gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyBottom, &RenderStyle::bottom, &RenderStyle::setBottom)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWidth, &RenderStyle::width, &RenderStyle::setWidth)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMinWidth, &RenderStyle::minWidth, &RenderStyle::setMinWidth)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMaxWidth, &RenderStyle::maxWidth, &RenderStyle::setMaxWidth)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyHeight, &RenderStyle::height, &RenderStyle::setHeight)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMinHeight, &RenderStyle::minHeight, &RenderStyle::setMinHeight)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMaxHeight, &RenderStyle::maxHeight, &RenderStyle::setMaxHeight)); + gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderLeftWidth, &RenderStyle::borderLeftWidth, &RenderStyle::setBorderLeftWidth)); gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderRightWidth, &RenderStyle::borderRightWidth, &RenderStyle::setBorderRightWidth)); gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderTopWidth, &RenderStyle::borderTopWidth, &RenderStyle::setBorderTopWidth)); @@ -442,16 +463,18 @@ static void ensurePropertyMap() gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyOutlineWidth, &RenderStyle::outlineWidth, &RenderStyle::setOutlineWidth)); gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyLetterSpacing, &RenderStyle::letterSpacing, &RenderStyle::setLetterSpacing)); gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyWordSpacing, &RenderStyle::wordSpacing, &RenderStyle::setWordSpacing)); + gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyTextIndent, &RenderStyle::textIndent, &RenderStyle::setTextIndent)); + gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitPerspective, &RenderStyle::perspective, &RenderStyle::setPerspective)); gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginX, &RenderStyle::perspectiveOriginX, &RenderStyle::setPerspectiveOriginX)); gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginY, &RenderStyle::perspectiveOriginY, &RenderStyle::setPerspectiveOriginY)); gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginX, &RenderStyle::transformOriginX, &RenderStyle::setTransformOriginX)); gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginY, &RenderStyle::transformOriginY, &RenderStyle::setTransformOriginY)); gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitTransformOriginZ, &RenderStyle::transformOriginZ, &RenderStyle::setTransformOriginZ)); - gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyWebkitBorderTopLeftRadius, &RenderStyle::borderTopLeftRadius, &RenderStyle::setBorderTopLeftRadius)); - gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyWebkitBorderTopRightRadius, &RenderStyle::borderTopRightRadius, &RenderStyle::setBorderTopRightRadius)); - gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyWebkitBorderBottomLeftRadius, &RenderStyle::borderBottomLeftRadius, &RenderStyle::setBorderBottomLeftRadius)); - gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyWebkitBorderBottomRightRadius, &RenderStyle::borderBottomRightRadius, &RenderStyle::setBorderBottomRightRadius)); + gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyBorderTopLeftRadius, &RenderStyle::borderTopLeftRadius, &RenderStyle::setBorderTopLeftRadius)); + gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyBorderTopRightRadius, &RenderStyle::borderTopRightRadius, &RenderStyle::setBorderTopRightRadius)); + gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyBorderBottomLeftRadius, &RenderStyle::borderBottomLeftRadius, &RenderStyle::setBorderBottomLeftRadius)); + gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyBorderBottomRightRadius, &RenderStyle::borderBottomRightRadius, &RenderStyle::setBorderBottomRightRadius)); gPropertyWrappers->append(new PropertyWrapper<EVisibility>(CSSPropertyVisibility, &RenderStyle::visibility, &RenderStyle::setVisibility)); gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyZoom, &RenderStyle::zoom, &RenderStyle::setZoom)); @@ -473,7 +496,7 @@ static void ensurePropertyMap() gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyOutlineColor, &RenderStyle::outlineColor, &RenderStyle::setOutlineColor)); // These are for shadows - gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyWebkitBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow)); + gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow)); gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyTextShadow, &RenderStyle::textShadow, &RenderStyle::setTextShadow)); #if ENABLE(SVG) @@ -484,8 +507,6 @@ static void ensurePropertyMap() // TODO: // - // CSSPropertyMinWidth, CSSPropertyMaxWidth, CSSPropertyMinHeight, CSSPropertyMaxHeight - // CSSPropertyTextIndent // CSSPropertyVerticalAlign // // Compound properties that have components that should be animatable: @@ -1041,7 +1062,7 @@ void AnimationBase::getTimeToNextEvent(double& time, bool& isLooping) const double nextIterationTime = m_totalDuration; if (m_totalDuration < 0 || elapsedDuration < m_totalDuration) { - durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration()); + durationLeft = m_animation->duration() > 0 ? (m_animation->duration() - fmod(elapsedDuration, m_animation->duration())) : 0; nextIterationTime = elapsedDuration + durationLeft; } @@ -1065,10 +1086,18 @@ void AnimationBase::goIntoEndingOrLoopingState() m_animState = isLooping ? AnimationStateLooping : AnimationStateEnding; } -void AnimationBase::pauseAtTime(double t) +void AnimationBase::freezeAtTime(double t) { - updatePlayState(false); + ASSERT(m_startTime); // if m_startTime is zero, we haven't started yet, so we'll get a bad pause time. m_pauseTime = m_startTime + t - m_animation->delay(); + +#if USE(ACCELERATED_COMPOSITING) + if (m_object && m_object->hasLayer()) { + RenderLayer* layer = toRenderBoxModelObject(m_object)->layer(); + if (layer->isComposited()) + layer->backing()->suspendAnimations(m_pauseTime); + } +#endif } double AnimationBase::beginAnimationUpdateTime() const diff --git a/WebCore/page/animation/AnimationBase.h b/WebCore/page/animation/AnimationBase.h index 8f55a8e..3482f65 100644 --- a/WebCore/page/animation/AnimationBase.h +++ b/WebCore/page/animation/AnimationBase.h @@ -156,7 +156,8 @@ public: bool isTransformFunctionListValid() const { return m_transformFunctionListValid; } - void pauseAtTime(double t); + // Freeze the animation; used by DumpRenderTree. + void freezeAtTime(double t); double beginAnimationUpdateTime() const; diff --git a/WebCore/page/animation/AnimationController.cpp b/WebCore/page/animation/AnimationController.cpp index 58a1f5b..ed241e1 100644 --- a/WebCore/page/animation/AnimationController.cpp +++ b/WebCore/page/animation/AnimationController.cpp @@ -136,9 +136,9 @@ void AnimationControllerPrivate::updateStyleIfNeededDispatcherFired(Timer<Animat Vector<EventToDispatch>::const_iterator eventsToDispatchEnd = m_eventsToDispatch.end(); for (Vector<EventToDispatch>::const_iterator it = m_eventsToDispatch.begin(); it != eventsToDispatchEnd; ++it) { if (it->eventType == eventNames().webkitTransitionEndEvent) - it->element->dispatchWebKitTransitionEvent(it->eventType,it->name, it->elapsedTime); + it->element->dispatchWebKitTransitionEvent(it->eventType, it->name, it->elapsedTime); else - it->element->dispatchWebKitAnimationEvent(it->eventType,it->name, it->elapsedTime); + it->element->dispatchWebKitAnimationEvent(it->eventType, it->name, it->elapsedTime); } m_eventsToDispatch.clear(); @@ -152,20 +152,6 @@ void AnimationControllerPrivate::updateStyleIfNeededDispatcherFired(Timer<Animat if (m_frame) m_frame->document()->updateStyleIfNeeded(); - - // We can now safely remove any animations or transitions that are finished. - // We can't remove them any earlier because we might get a false restart of - // a transition. This can happen because we have not yet set the final property - // value until we call the rendering dispatcher. So this can make the current - // style slightly different from the desired final style (because our last - // animation step was, say 0.9999 or something). And we need to remove them - // here because if there are no more animations running we'll never get back - // into the animation code to clean them up. - RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end(); - for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) { - CompositeAnimation* compAnim = it->second.get(); - compAnim->cleanupFinishedAnimations(); // will not modify m_compositeAnimations, so OK to call while iterating - } } void AnimationControllerPrivate::startUpdateStyleIfNeededDispatcher() diff --git a/WebCore/page/animation/CompositeAnimation.cpp b/WebCore/page/animation/CompositeAnimation.cpp index d60455a..8946d80 100644 --- a/WebCore/page/animation/CompositeAnimation.cpp +++ b/WebCore/page/animation/CompositeAnimation.cpp @@ -67,91 +67,117 @@ void CompositeAnimation::clearRenderer() void CompositeAnimation::updateTransitions(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle) { - RefPtr<RenderStyle> modifiedCurrentStyle; - - // If currentStyle is null, we don't do transitions - if (!currentStyle || !targetStyle->transitions()) + // If currentStyle is null or there are no old or new transitions, just skip it + if (!currentStyle || (!targetStyle->transitions() && m_transitions.isEmpty())) return; + // Mark all existing transitions as no longer active. We will mark the still active ones + // in the next loop and then toss the ones that didn't get marked. + CSSPropertyTransitionsMap::const_iterator end = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) + it->second->setActive(false); + + RefPtr<RenderStyle> modifiedCurrentStyle; + // Check to see if we need to update the active transitions - for (size_t i = 0; i < targetStyle->transitions()->size(); ++i) { - const Animation* anim = targetStyle->transitions()->animation(i); - bool isActiveTransition = anim->duration() || anim->delay() > 0; + if (targetStyle->transitions()) { + for (size_t i = 0; i < targetStyle->transitions()->size(); ++i) { + const Animation* anim = targetStyle->transitions()->animation(i); + bool isActiveTransition = anim->duration() || anim->delay() > 0; - int prop = anim->property(); + int prop = anim->property(); - if (prop == cAnimateNone) - continue; - - bool all = prop == cAnimateAll; + if (prop == cAnimateNone) + continue; - // Handle both the 'all' and single property cases. For the single prop case, we make only one pass - // through the loop. - for (int propertyIndex = 0; propertyIndex < AnimationBase::getNumProperties(); ++propertyIndex) { - if (all) { - // Get the next property which is not a shorthand. - bool isShorthand; - prop = AnimationBase::getPropertyAtIndex(propertyIndex, isShorthand); - if (isShorthand) - continue; - } + bool all = prop == cAnimateAll; + + // Handle both the 'all' and single property cases. For the single prop case, we make only one pass + // through the loop. + for (int propertyIndex = 0; propertyIndex < AnimationBase::getNumProperties(); ++propertyIndex) { + if (all) { + // Get the next property which is not a shorthand. + bool isShorthand; + prop = AnimationBase::getPropertyAtIndex(propertyIndex, isShorthand); + if (isShorthand) + continue; + } - // ImplicitAnimations are always hashed by actual properties, never cAnimateAll - ASSERT(prop >= firstCSSProperty && prop < (firstCSSProperty + numCSSProperties)); - - // If there is a running animation for this property, the transition is overridden - // and we have to use the unanimatedStyle from the animation. We do the test - // against the unanimated style here, but we "override" the transition later. - RefPtr<KeyframeAnimation> keyframeAnim = getAnimationForProperty(prop); - RenderStyle* fromStyle = keyframeAnim ? keyframeAnim->unanimatedStyle() : currentStyle; - - // See if there is a current transition for this prop - ImplicitAnimation* implAnim = m_transitions.get(prop).get(); - bool equal = true; - - if (implAnim) { - // This might be a transition that is just finishing. That would be the case - // if it were postActive. But we still need to check for equality because - // it could be just finishing AND changing to a new goal state. - // - // This implAnim might also not be an already running transition. It might be - // newly added to the list in a previous iteration. This would happen if - // you have both an explicit transition-property and 'all' in the same - // list. In this case, the latter one overrides the earlier one, so we - // behave as though this is a running animation being replaced. - if (!implAnim->isTargetPropertyEqual(prop, targetStyle)) { -#if USE(ACCELERATED_COMPOSITING) - // For accelerated animations we need to return a new RenderStyle with the _current_ value - // of the property, so that restarted transitions use the correct starting point. - if (AnimationBase::animationOfPropertyIsAccelerated(prop) && !implAnim->isFallbackAnimating()) { - if (!modifiedCurrentStyle) - modifiedCurrentStyle = RenderStyle::clone(currentStyle); - - implAnim->blendPropertyValueInStyle(prop, modifiedCurrentStyle.get()); + // ImplicitAnimations are always hashed by actual properties, never cAnimateAll + ASSERT(prop >= firstCSSProperty && prop < (firstCSSProperty + numCSSProperties)); + + // If there is a running animation for this property, the transition is overridden + // and we have to use the unanimatedStyle from the animation. We do the test + // against the unanimated style here, but we "override" the transition later. + RefPtr<KeyframeAnimation> keyframeAnim = getAnimationForProperty(prop); + RenderStyle* fromStyle = keyframeAnim ? keyframeAnim->unanimatedStyle() : currentStyle; + + // See if there is a current transition for this prop + ImplicitAnimation* implAnim = m_transitions.get(prop).get(); + bool equal = true; + + if (implAnim) { + // If we are post active don't bother setting the active flag. This will cause + // this animation to get removed at the end of this function. + if (!implAnim->postActive()) + implAnim->setActive(true); + + // This might be a transition that is just finishing. That would be the case + // if it were postActive. But we still need to check for equality because + // it could be just finishing AND changing to a new goal state. + // + // This implAnim might also not be an already running transition. It might be + // newly added to the list in a previous iteration. This would happen if + // you have both an explicit transition-property and 'all' in the same + // list. In this case, the latter one overrides the earlier one, so we + // behave as though this is a running animation being replaced. + if (!implAnim->isTargetPropertyEqual(prop, targetStyle)) { + #if USE(ACCELERATED_COMPOSITING) + // For accelerated animations we need to return a new RenderStyle with the _current_ value + // of the property, so that restarted transitions use the correct starting point. + if (AnimationBase::animationOfPropertyIsAccelerated(prop) && !implAnim->isFallbackAnimating()) { + if (!modifiedCurrentStyle) + modifiedCurrentStyle = RenderStyle::clone(currentStyle); + + implAnim->blendPropertyValueInStyle(prop, modifiedCurrentStyle.get()); + } + #endif + m_transitions.remove(prop); + equal = false; } -#endif - m_transitions.remove(prop); - equal = false; + } else { + // We need to start a transition if it is active and the properties don't match + equal = !isActiveTransition || AnimationBase::propertiesEqual(prop, fromStyle, targetStyle); } - } else { - // We need to start a transition if it is active and the properties don't match - equal = !isActiveTransition || AnimationBase::propertiesEqual(prop, fromStyle, targetStyle); - } - // We can be in this loop with an inactive transition (!isActiveTransition). We need - // to do that to check to see if we are canceling a transition. But we don't want to - // start one of the inactive transitions. So short circuit that here. (See - // <https://bugs.webkit.org/show_bug.cgi?id=24787> - if (!equal && isActiveTransition) { - // Add the new transition - m_transitions.set(prop, ImplicitAnimation::create(const_cast<Animation*>(anim), prop, renderer, this, modifiedCurrentStyle ? modifiedCurrentStyle.get() : fromStyle)); + // We can be in this loop with an inactive transition (!isActiveTransition). We need + // to do that to check to see if we are canceling a transition. But we don't want to + // start one of the inactive transitions. So short circuit that here. (See + // <https://bugs.webkit.org/show_bug.cgi?id=24787> + if (!equal && isActiveTransition) { + // Add the new transition + m_transitions.set(prop, ImplicitAnimation::create(const_cast<Animation*>(anim), prop, renderer, this, modifiedCurrentStyle ? modifiedCurrentStyle.get() : fromStyle)); + } + + // We only need one pass for the single prop case + if (!all) + break; } - - // We only need one pass for the single prop case - if (!all) - break; } } + + // Make a list of transitions to be removed + Vector<int> toBeRemoved; + end = m_transitions.end(); + for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) { + ImplicitAnimation* anim = it->second.get(); + if (!anim->active()) + toBeRemoved.append(anim->animatingProperty()); + } + + // Now remove the transitions from the list + for (size_t j = 0; j < toBeRemoved.size(); ++j) + m_transitions.remove(toBeRemoved[j]); } void CompositeAnimation::updateKeyframeAnimations(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle) @@ -160,52 +186,62 @@ void CompositeAnimation::updateKeyframeAnimations(RenderObject* renderer, Render if (m_keyframeAnimations.isEmpty() && !targetStyle->hasAnimations()) return; - // Nothing to do if the current and target animations are the same - if (currentStyle && currentStyle->hasAnimations() && targetStyle->hasAnimations() && *(currentStyle->animations()) == *(targetStyle->animations())) - return; - - // Mark all existing animations as no longer active AnimationNameMap::const_iterator kfend = m_keyframeAnimations.end(); - for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != kfend; ++it) - it->second->setIndex(-1); - - // Toss the animation order map - m_keyframeAnimationOrderMap.clear(); - // Now mark any still active animations as active and add any new animations - if (targetStyle->animations()) { - int numAnims = targetStyle->animations()->size(); - for (int i = 0; i < numAnims; ++i) { - const Animation* anim = targetStyle->animations()->animation(i); - AtomicString animationName(anim->name()); - - if (!anim->isValidAnimation()) - continue; + if (currentStyle && currentStyle->hasAnimations() && targetStyle->hasAnimations() && *(currentStyle->animations()) == *(targetStyle->animations())) { + // The current and target animations are the same so we just need to toss any + // animation which is finished (postActive). + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != kfend; ++it) { + if (it->second->postActive()) + it->second->setIndex(-1); + } + } else { + // Mark all existing animations as no longer active. + for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != kfend; ++it) + it->second->setIndex(-1); - // See if there is a current animation for this name - RefPtr<KeyframeAnimation> keyframeAnim = m_keyframeAnimations.get(animationName.impl()); + // Toss the animation order map. + m_keyframeAnimationOrderMap.clear(); + + // Now mark any still active animations as active and add any new animations. + if (targetStyle->animations()) { + int numAnims = targetStyle->animations()->size(); + for (int i = 0; i < numAnims; ++i) { + const Animation* anim = targetStyle->animations()->animation(i); + AtomicString animationName(anim->name()); + + if (!anim->isValidAnimation()) + continue; + + // See if there is a current animation for this name. + RefPtr<KeyframeAnimation> keyframeAnim = m_keyframeAnimations.get(animationName.impl()); - if (keyframeAnim) { - // There is one so it is still active - - // Animations match, but play states may differ. update if needed - keyframeAnim->updatePlayState(anim->playState() == AnimPlayStatePlaying); - - // Set the saved animation to this new one, just in case the play state has changed - keyframeAnim->setAnimation(anim); - keyframeAnim->setIndex(i); - } else if ((anim->duration() || anim->delay()) && anim->iterationCount()) { - keyframeAnim = KeyframeAnimation::create(const_cast<Animation*>(anim), renderer, i, this, currentStyle ? currentStyle : targetStyle); - m_keyframeAnimations.set(keyframeAnim->name().impl(), keyframeAnim); + if (keyframeAnim) { + // If this animation is postActive, skip it so it gets removed at the end of this function. + if (keyframeAnim->postActive()) + continue; + + // This one is still active. + + // Animations match, but play states may differ. Update if needed. + keyframeAnim->updatePlayState(anim->playState() == AnimPlayStatePlaying); + + // Set the saved animation to this new one, just in case the play state has changed. + keyframeAnim->setAnimation(anim); + keyframeAnim->setIndex(i); + } else if ((anim->duration() || anim->delay()) && anim->iterationCount()) { + keyframeAnim = KeyframeAnimation::create(const_cast<Animation*>(anim), renderer, i, this, currentStyle ? currentStyle : targetStyle); + m_keyframeAnimations.set(keyframeAnim->name().impl(), keyframeAnim); + } + + // Add this to the animation order map. + if (keyframeAnim) + m_keyframeAnimationOrderMap.append(keyframeAnim->name().impl()); } - - // Add this to the animation order map - if (keyframeAnim) - m_keyframeAnimationOrderMap.append(keyframeAnim->name().impl()); } } - - // Make a list of animations to be removed + + // Make a list of animations to be removed. Vector<AtomicStringImpl*> animsToBeRemoved; kfend = m_keyframeAnimations.end(); for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != kfend; ++it) { @@ -214,7 +250,7 @@ void CompositeAnimation::updateKeyframeAnimations(RenderObject* renderer, Render animsToBeRemoved.append(keyframeAnim->name().impl()); } - // Now remove the animations from the list + // Now remove the animations from the list. for (size_t j = 0; j < animsToBeRemoved.size(); ++j) m_keyframeAnimations.remove(animsToBeRemoved[j]); } @@ -223,11 +259,9 @@ PassRefPtr<RenderStyle> CompositeAnimation::animate(RenderObject* renderer, Rend { RefPtr<RenderStyle> resultStyle; - // Update animations first so we can see if any transitions are overridden - updateKeyframeAnimations(renderer, currentStyle, targetStyle); - - // We don't do any transitions if we don't have a currentStyle (on startup) + // We don't do any transitions if we don't have a currentStyle (on startup). updateTransitions(renderer, currentStyle, targetStyle); + updateKeyframeAnimations(renderer, currentStyle, targetStyle); if (currentStyle) { // Now that we have transition objects ready, let them know about the new goal state. We want them @@ -249,8 +283,6 @@ PassRefPtr<RenderStyle> CompositeAnimation::animate(RenderObject* renderer, Rend keyframeAnim->animate(this, renderer, currentStyle, targetStyle, resultStyle); } - cleanupFinishedAnimations(); - return resultStyle ? resultStyle.release() : targetStyle; } @@ -341,50 +373,6 @@ PassRefPtr<KeyframeAnimation> CompositeAnimation::getAnimationForProperty(int pr return retval; } -void CompositeAnimation::cleanupFinishedAnimations() -{ - if (isSuspended()) - return; - - // Make a list of transitions to be deleted - Vector<int> finishedTransitions; - if (!m_transitions.isEmpty()) { - CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end(); - - for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) { - ImplicitAnimation* anim = it->second.get(); - if (!anim) - continue; - if (anim->postActive()) - finishedTransitions.append(anim->animatingProperty()); - } - - // Delete them - size_t finishedTransitionCount = finishedTransitions.size(); - for (size_t i = 0; i < finishedTransitionCount; ++i) - m_transitions.remove(finishedTransitions[i]); - } - - // Make a list of animations to be deleted - Vector<AtomicStringImpl*> finishedAnimations; - if (!m_keyframeAnimations.isEmpty()) { - AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); - - for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) { - KeyframeAnimation* anim = it->second.get(); - if (!anim) - continue; - if (anim->postActive()) - finishedAnimations.append(anim->name().impl()); - } - - // Delete them - size_t finishedAnimationCount = finishedAnimations.size(); - for (size_t i = 0; i < finishedAnimationCount; ++i) - m_keyframeAnimations.remove(finishedAnimations[i]); - } -} - void CompositeAnimation::suspendAnimations() { if (m_isSuspended) @@ -492,7 +480,7 @@ bool CompositeAnimation::pauseAnimationAtTime(const AtomicString& name, double t int count = keyframeAnim->m_animation->iterationCount(); if ((t >= 0.0) && (!count || (t <= count * keyframeAnim->duration()))) { - keyframeAnim->pauseAtTime(t); + keyframeAnim->freezeAtTime(t); return true; } @@ -509,7 +497,7 @@ bool CompositeAnimation::pauseTransitionAtTime(int property, double t) return false; if ((t >= 0.0) && (t <= implAnim->duration())) { - implAnim->pauseAtTime(t); + implAnim->freezeAtTime(t); return true; } diff --git a/WebCore/page/animation/CompositeAnimation.h b/WebCore/page/animation/CompositeAnimation.h index 739cfdc..b7db442 100644 --- a/WebCore/page/animation/CompositeAnimation.h +++ b/WebCore/page/animation/CompositeAnimation.h @@ -74,8 +74,6 @@ public: PassRefPtr<KeyframeAnimation> getAnimationForProperty(int property) const; - void cleanupFinishedAnimations(); - void overrideImplicitAnimations(int property); void resumeOverriddenImplicitAnimations(int property); diff --git a/WebCore/page/animation/ImplicitAnimation.cpp b/WebCore/page/animation/ImplicitAnimation.cpp index e93fee4..8e6349d 100644 --- a/WebCore/page/animation/ImplicitAnimation.cpp +++ b/WebCore/page/animation/ImplicitAnimation.cpp @@ -45,6 +45,7 @@ ImplicitAnimation::ImplicitAnimation(const Animation* transition, int animatingP , m_transitionProperty(transition->property()) , m_animatingProperty(animatingProperty) , m_overridden(false) + , m_active(true) , m_fromStyle(fromStyle) { ASSERT(animatingProperty != cAnimateAll); @@ -211,6 +212,10 @@ bool ImplicitAnimation::affectsProperty(int property) const bool ImplicitAnimation::isTargetPropertyEqual(int prop, const RenderStyle* targetStyle) { + // We can get here for a transition that has not started yet. This would make m_toStyle unset and null. + // So we check that here (see <https://bugs.webkit.org/show_bug.cgi?id=26706>) + if (!m_toStyle) + return false; return propertiesEqual(prop, m_toStyle.get(), targetStyle); } diff --git a/WebCore/page/animation/ImplicitAnimation.h b/WebCore/page/animation/ImplicitAnimation.h index 33fe4e4..7e286d2 100644 --- a/WebCore/page/animation/ImplicitAnimation.h +++ b/WebCore/page/animation/ImplicitAnimation.h @@ -66,6 +66,9 @@ public: void blendPropertyValueInStyle(int, RenderStyle* currentStyle); virtual double timeToNextService(); + + bool active() const { return m_active; } + void setActive(bool b) { m_active = b; } protected: bool shouldSendEventForListener(Document::ListenerType) const; @@ -80,6 +83,7 @@ private: int m_transitionProperty; // Transition property as specified in the RenderStyle. May be cAnimateAll int m_animatingProperty; // Specific property for this ImplicitAnimation bool m_overridden; // true when there is a keyframe animation that overrides the transitioning property + bool m_active; // used for culling the list of transitions // The two styles that we are blending. RefPtr<RenderStyle> m_fromStyle; diff --git a/WebCore/page/animation/KeyframeAnimation.cpp b/WebCore/page/animation/KeyframeAnimation.cpp index 3f84de1..39ae1e7 100644 --- a/WebCore/page/animation/KeyframeAnimation.cpp +++ b/WebCore/page/animation/KeyframeAnimation.cpp @@ -93,8 +93,10 @@ void KeyframeAnimation::getKeyframeAnimationInterval(const RenderStyle*& fromSty return; const TimingFunction* timingFunction = 0; - if (fromStyle->animations() && fromStyle->animations()->size() > 0) + if (fromStyle->animations() && fromStyle->animations()->size() > 0) { + // We get the timing function from the first animation, because we've synthesized a RenderStyle for each keyframe. timingFunction = &(fromStyle->animations()->animation(0)->timingFunction()); + } prog = progress(scale, offset, timingFunction); } @@ -209,8 +211,12 @@ void KeyframeAnimation::endAnimation(bool reset) #if USE(ACCELERATED_COMPOSITING) if (m_object->hasLayer()) { RenderLayer* layer = toRenderBoxModelObject(m_object)->layer(); - if (layer->isComposited()) - layer->backing()->animationFinished(m_keyframes.animationName(), 0, reset); + if (layer->isComposited()) { + if (reset) + layer->backing()->animationFinished(m_keyframes.animationName()); + else + layer->backing()->animationPaused(m_keyframes.animationName()); + } } #else UNUSED_PARAM(reset); diff --git a/WebCore/page/chromium/EventHandlerChromium.cpp b/WebCore/page/chromium/EventHandlerChromium.cpp index 0cfc12d..467f94e 100644 --- a/WebCore/page/chromium/EventHandlerChromium.cpp +++ b/WebCore/page/chromium/EventHandlerChromium.cpp @@ -105,8 +105,7 @@ bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestR // Figure out which view to send the event to. if (!event.targetNode() || !event.targetNode()->renderer() || !event.targetNode()->renderer()->isWidget()) return false; - - return passMouseDownEventToWidget(static_cast<RenderWidget*>(event.targetNode()->renderer())->widget()); + return passMouseDownEventToWidget(toRenderWidget(event.targetNode()->renderer())->widget()); } bool EventHandler::passMouseDownEventToWidget(Widget* widget) diff --git a/WebCore/page/chromium/FrameChromium.cpp b/WebCore/page/chromium/FrameChromium.cpp index 5253bbc..1372cd9 100644 --- a/WebCore/page/chromium/FrameChromium.cpp +++ b/WebCore/page/chromium/FrameChromium.cpp @@ -46,7 +46,7 @@ void computePageRectsForFrame(Frame* frame, const IntRect& printRect, float head if (!frame->document() || !frame->view() || !frame->document()->renderer()) return; - RenderView* root = static_cast<RenderView*>(frame->document()->renderer()); + RenderView* root = toRenderView(frame->document()->renderer()); if (!root) { LOG_ERROR("document to be printed has no renderer"); diff --git a/WebCore/page/gtk/DragControllerGtk.cpp b/WebCore/page/gtk/DragControllerGtk.cpp index 9e17255..c064a87 100644 --- a/WebCore/page/gtk/DragControllerGtk.cpp +++ b/WebCore/page/gtk/DragControllerGtk.cpp @@ -53,7 +53,7 @@ DragOperation DragController::dragOperation(DragData* dragData) if (dragData->containsURL()) return DragOperationCopy; - return DragOperationNone; + return DragOperationNone; } const IntSize& DragController::maxDragImageSize() diff --git a/WebCore/page/gtk/EventHandlerGtk.cpp b/WebCore/page/gtk/EventHandlerGtk.cpp index 7692dae..d12cdcc 100644 --- a/WebCore/page/gtk/EventHandlerGtk.cpp +++ b/WebCore/page/gtk/EventHandlerGtk.cpp @@ -62,8 +62,7 @@ bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestR RenderObject* target = event.targetNode() ? event.targetNode()->renderer() : 0; if (!target || !target->isWidget()) return false; - - return passMouseDownEventToWidget(static_cast<RenderWidget*>(target)->widget()); + return passMouseDownEventToWidget(toRenderWidget(target)->widget()); } bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget) diff --git a/WebCore/page/haiku/DragControllerHaiku.cpp b/WebCore/page/haiku/DragControllerHaiku.cpp new file mode 100644 index 0000000..0b95558 --- /dev/null +++ b/WebCore/page/haiku/DragControllerHaiku.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * 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 "DragController.h" + +#include "DragData.h" + +#include <InterfaceDefs.h> + + +namespace WebCore +{ + +// FIXME: These values are straight out of DragControllerMac, so probably have +// little correlation with Haiku standards... +const int DragController::LinkDragBorderInset = 2; +const int DragController::MaxOriginalImageArea = 1500 * 1500; +const int DragController::DragIconRightInset = 7; +const int DragController::DragIconBottomInset = 3; + +const float DragController::DragImageAlpha = 0.75f; + + +bool DragController::isCopyKeyDown() +{ + if (modifiers() & B_COMMAND_KEY) + return true; + + return false; +} + +DragOperation DragController::dragOperation(DragData* dragData) +{ + // FIXME: This logic is incomplete + if (dragData->containsURL()) + return DragOperationCopy; + + return DragOperationNone; +} + +const IntSize& DragController::maxDragImageSize() +{ + static const IntSize maxDragImageSize(400, 400); + + return maxDragImageSize; +} + +void DragController::cleanupAfterSystemDrag() +{ +} + +} // namespace WebCore + diff --git a/WebCore/page/haiku/EventHandlerHaiku.cpp b/WebCore/page/haiku/EventHandlerHaiku.cpp new file mode 100644 index 0000000..64b8519 --- /dev/null +++ b/WebCore/page/haiku/EventHandlerHaiku.cpp @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * Copyright (C) 2009 Maxime Simon <simon.maxime@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 "EventHandler.h" + +#include "ClipboardHaiku.h" +#include "EventNames.h" +#include "FocusController.h" +#include "Frame.h" +#include "FrameView.h" +#include "HitTestResult.h" +#include "KeyboardEvent.h" +#include "MouseEventWithHitTestResults.h" +#include "Page.h" +#include "PlatformKeyboardEvent.h" +#include "PlatformScrollBar.h" +#include "PlatformWheelEvent.h" +#include "RenderWidget.h" + +#include "NotImplemented.h" + +#include <interface/View.h> + + +namespace WebCore { + +const double EventHandler::TextDragDelay = 0.0; + +static bool isKeyboardOptionTab(KeyboardEvent* event) +{ + return event + && (event->type() == eventNames().keydownEvent + || event->type() == eventNames().keypressEvent) + && event->altKey() + && event->keyIdentifier() == "U+000009"; +} + +bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent* event) const +{ + return isKeyboardOptionTab(event); +} + +bool EventHandler::tabsToAllControls(KeyboardEvent* event) const +{ + bool handlingOptionTab = isKeyboardOptionTab(event); + + return handlingOptionTab; +} + +void EventHandler::focusDocumentView() +{ + BView* view = m_frame->view()->platformWidget(); + if (view) + view->MakeFocus(); + + Page* page = m_frame->page(); + if (page) + page->focusController()->setFocusedFrame(m_frame); +} + +bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event) +{ + // Figure out which view to send the event to. + RenderObject* target = event.targetNode() ? event.targetNode()->renderer() : 0; + if (!target || !target->isWidget()) + return false; + return passMouseDownEventToWidget(toRenderWidget(target)->widget()); +} + +bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget) +{ + return passMouseDownEventToWidget(renderWidget->widget()); +} + +bool EventHandler::passMouseDownEventToWidget(Widget* widget) +{ + notImplemented(); + return false; +} + +bool EventHandler::eventActivatedView(const PlatformMouseEvent&) const +{ + notImplemented(); + return false; +} + +bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults& event, Frame* subframe, HitTestResult*) +{ + notImplemented(); + return true; +} + +bool EventHandler::passWheelEventToWidget(PlatformWheelEvent& event, Widget* widget) +{ + notImplemented(); + return false; +} + +PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const +{ + return new ClipboardHaiku(ClipboardWritable, true); +} + +bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) +{ + return passSubframeEventToSubframe(mev, subframe); +} + +bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode) +{ + return passSubframeEventToSubframe(mev, subframe, hoveredNode); +} + +bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) +{ + return passSubframeEventToSubframe(mev, subframe); +} + +unsigned EventHandler::accessKeyModifiers() +{ + return PlatformKeyboardEvent::AltKey; +} + +} // namespace WebCore + diff --git a/WebCore/page/haiku/FrameHaiku.cpp b/WebCore/page/haiku/FrameHaiku.cpp new file mode 100644 index 0000000..50168dd --- /dev/null +++ b/WebCore/page/haiku/FrameHaiku.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Frame.h" + +#include "NotImplemented.h" + + +namespace WebCore { + +DragImageRef Frame::dragImageForSelection() +{ + notImplemented(); + return 0; +} + +} // namespace WebCore + diff --git a/WebCore/page/mac/EventHandlerMac.mm b/WebCore/page/mac/EventHandlerMac.mm index d69aff4..54bdff9 100644 --- a/WebCore/page/mac/EventHandlerMac.mm +++ b/WebCore/page/mac/EventHandlerMac.mm @@ -45,6 +45,7 @@ #include "RuntimeApplicationChecks.h" #include "Scrollbar.h" #include "Settings.h" +#include "WebCoreSystemInterface.h" #include <objc/objc-runtime.h> #include <wtf/StdLibExtras.h> @@ -72,7 +73,7 @@ NSEvent *EventHandler::currentNSEvent() return currentNSEventSlot().get(); } -class CurrentEventScope : Noncopyable { +class CurrentEventScope : public Noncopyable { public: CurrentEventScope(NSEvent *); ~CurrentEventScope(); @@ -107,6 +108,8 @@ bool EventHandler::wheelEvent(NSEvent *event) CurrentEventScope scope(event); + m_useLatchedWheelEventNode = wkIsLatchingWheelEvent(event); + PlatformWheelEvent wheelEvent(event, page->chrome()->platformWindow()); handleWheelEvent(wheelEvent); @@ -229,7 +232,7 @@ bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestR // just pass currentEvent down to the widget, we don't want to call it for events that // don't correspond to Cocoa events. The mousedown/ups will have already been passed on as // part of the pressed/released handling. - return passMouseDownEventToWidget(static_cast<RenderWidget*>(target)->widget()); + return passMouseDownEventToWidget(toRenderWidget(target)->widget()); } bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget) @@ -255,10 +258,12 @@ static bool lastEventIsMouseUp() return false; } -bool EventHandler::passMouseDownEventToWidget(Widget* widget) +bool EventHandler::passMouseDownEventToWidget(Widget* pWidget) { // FIXME: This function always returns true. It should be changed either to return // false in some cases or the return value should be removed. + + RefPtr<Widget> widget = pWidget; if (!widget) { LOG_ERROR("hit a RenderWidget without a corresponding Widget, means a frame is half-constructed"); @@ -300,7 +305,10 @@ bool EventHandler::passMouseDownEventToWidget(Widget* widget) ASSERT(!m_sendingEventToSubview); m_sendingEventToSubview = true; + NSView *outerView = widget->getOuterView(); + widget->beforeMouseDown(outerView, widget.get()); [view mouseDown:currentNSEvent()]; + widget->afterMouseDown(outerView, widget.get()); m_sendingEventToSubview = false; if (!wasDeferringLoading) @@ -441,10 +449,10 @@ bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults& eve RenderObject* renderer = node->renderer(); if (!renderer || !renderer->isWidget()) return false; - Widget* widget = static_cast<RenderWidget*>(renderer)->widget(); + Widget* widget = toRenderWidget(renderer)->widget(); if (!widget || !widget->isFrameView()) return false; - if (!passWidgetMouseDownEventToWidget(static_cast<RenderWidget*>(renderer))) + if (!passWidgetMouseDownEventToWidget(toRenderWidget(renderer))) return false; m_mouseDownWasInSubframe = true; return true; @@ -543,8 +551,8 @@ void EventHandler::mouseDown(NSEvent *event) m_mouseDownView = nil; CurrentEventScope scope(event); - m_mouseDown = currentPlatformMouseEvent(); - handleMousePressEvent(m_mouseDown); + + handleMousePressEvent(currentPlatformMouseEvent()); END_BLOCK_OBJC_EXCEPTIONS; } diff --git a/WebCore/page/mac/FrameMac.mm b/WebCore/page/mac/FrameMac.mm index decbcad..c656624 100644 --- a/WebCore/page/mac/FrameMac.mm +++ b/WebCore/page/mac/FrameMac.mm @@ -147,10 +147,11 @@ static RegularExpression* regExpForLabels(NSArray* labels) NSString* Frame::searchForNSLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell) { - RenderTableCell* cellRenderer = static_cast<RenderTableCell*>(cell->renderer()); + RenderObject* cellRenderer = cell->renderer(); if (cellRenderer && cellRenderer->isTableCell()) { - RenderTableCell* cellAboveRenderer = cellRenderer->table()->cellAbove(cellRenderer); + RenderTableCell* tableCellRenderer = toRenderTableCell(cellRenderer); + RenderTableCell* cellAboveRenderer = tableCellRenderer->table()->cellAbove(tableCellRenderer); if (cellAboveRenderer) { HTMLTableCellElement* aboveCell = @@ -470,8 +471,11 @@ void Frame::setUseSecureKeyboardEntry(bool enable) #ifdef BUILDING_ON_TIGER KeyScript(enableRomanKeyboardsOnly); #else + // WebKit substitutes nil for input context when in password field, which corresponds to null TSMDocument. So, there is + // no need to call TSMGetActiveDocument(), which may return an incorrect result when selection hasn't been yet updated + // after focusing a node. CFArrayRef inputSources = TISCreateASCIICapableInputSourceList(); - TSMSetDocumentProperty(TSMGetActiveDocument(), kTSMDocumentEnabledInputSourcesPropertyTag, sizeof(CFArrayRef), &inputSources); + TSMSetDocumentProperty(0, kTSMDocumentEnabledInputSourcesPropertyTag, sizeof(CFArrayRef), &inputSources); CFRelease(inputSources); #endif } else { @@ -479,7 +483,7 @@ void Frame::setUseSecureKeyboardEntry(bool enable) #ifdef BUILDING_ON_TIGER KeyScript(smKeyEnableKybds); #else - TSMRemoveDocumentProperty(TSMGetActiveDocument(), kTSMDocumentEnabledInputSourcesPropertyTag); + TSMRemoveDocumentProperty(0, kTSMDocumentEnabledInputSourcesPropertyTag); #endif } } diff --git a/WebCore/page/mac/WebCoreViewFactory.h b/WebCore/page/mac/WebCoreViewFactory.h index c18f4d4..d4dc821 100644 --- a/WebCore/page/mac/WebCoreViewFactory.h +++ b/WebCore/page/mac/WebCoreViewFactory.h @@ -141,6 +141,9 @@ // FTP Directory Related - (NSString *)unknownFileSizeText; +- (NSString *)mediaElementLoadingStateText; +- (NSString *)mediaElementLiveBroadcastStateText; + @end @interface WebCoreViewFactory : NSObject diff --git a/WebCore/page/qt/DragControllerQt.cpp b/WebCore/page/qt/DragControllerQt.cpp index 1fe56b4..e6c7682 100644 --- a/WebCore/page/qt/DragControllerQt.cpp +++ b/WebCore/page/qt/DragControllerQt.cpp @@ -31,8 +31,7 @@ #include "FrameView.h" #include "Page.h" -namespace WebCore -{ +namespace WebCore { // FIXME: These values are straight out of DragControllerMac, so probably have // little correlation with Qt standards... diff --git a/WebCore/page/win/DragControllerWin.cpp b/WebCore/page/win/DragControllerWin.cpp index dca8ea2..f0404ff 100644 --- a/WebCore/page/win/DragControllerWin.cpp +++ b/WebCore/page/win/DragControllerWin.cpp @@ -50,7 +50,8 @@ DragOperation DragController::dragOperation(DragData* dragData) return dragData->containsURL() && !m_didInitiateDrag ? DragOperationCopy : DragOperationNone; } -bool DragController::isCopyKeyDown() { +bool DragController::isCopyKeyDown() +{ return ::GetAsyncKeyState(VK_CONTROL); } diff --git a/WebCore/page/win/EventHandlerWin.cpp b/WebCore/page/win/EventHandlerWin.cpp index 88bc373..50e50fb 100644 --- a/WebCore/page/win/EventHandlerWin.cpp +++ b/WebCore/page/win/EventHandlerWin.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007-2009 Torch Mobile, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -87,9 +88,13 @@ bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const { +#if PLATFORM(WINCE) + return 0; +#else COMPtr<WCDataObject> dataObject; WCDataObject::createInstance(&dataObject); return ClipboardWin::create(true, dataObject.get(), ClipboardWritable); +#endif } void EventHandler::focusDocumentView() diff --git a/WebCore/page/win/FrameCGWin.cpp b/WebCore/page/win/FrameCGWin.cpp index 8b0408d..7483627 100644 --- a/WebCore/page/win/FrameCGWin.cpp +++ b/WebCore/page/win/FrameCGWin.cpp @@ -28,6 +28,7 @@ #include <windows.h> +#include "BitmapInfo.h" #include "FrameView.h" #include "GraphicsContext.h" #include "Settings.h" @@ -55,7 +56,7 @@ static HBITMAP imageFromRect(const Frame* frame, IntRect& ir) HDC hdc = CreateCompatibleDC(0); int w = ir.width(); int h = ir.height(); - BITMAPINFO bmp = { { sizeof(BITMAPINFOHEADER), w, h, 1, 32 } }; + BitmapInfo bmp = BitmapInfo::create(IntSize(w, h)); HBITMAP hbmp = CreateDIBSection(0, &bmp, DIB_RGB_COLORS, static_cast<void**>(&bits), 0, 0); HBITMAP hbmpOld = static_cast<HBITMAP>(SelectObject(hdc, hbmp)); diff --git a/WebCore/page/win/FrameWin.cpp b/WebCore/page/win/FrameWin.cpp index 0c1c5b1..1e480fb 100644 --- a/WebCore/page/win/FrameWin.cpp +++ b/WebCore/page/win/FrameWin.cpp @@ -47,7 +47,7 @@ void computePageRectsForFrame(Frame* frame, const IntRect& printRect, float head if (!frame->document() || !frame->view() || !frame->document()->renderer()) return; - RenderView* root = static_cast<RenderView*>(frame->document()->renderer()); + RenderView* root = toRenderView(frame->document()->renderer()); if (!root) { LOG_ERROR("document to be printed has no renderer"); diff --git a/WebCore/page/win/FrameWin.h b/WebCore/page/win/FrameWin.h index 405c7b2..2924291 100644 --- a/WebCore/page/win/FrameWin.h +++ b/WebCore/page/win/FrameWin.h @@ -34,7 +34,7 @@ typedef struct HBITMAP__* HBITMAP; namespace WebCore { HBITMAP imageFromSelection(Frame* frame, bool forceWhiteText); - void computePageRectsForFrame(Frame*, const IntRect& printRect, float headerHeight, float footerHeight, float userScaleFactor,Vector<IntRect>& pages, int& pageHeight); + void computePageRectsForFrame(Frame*, const IntRect& printRect, float headerHeight, float footerHeight, float userScaleFactor, Vector<IntRect>& pages, int& pageHeight); } diff --git a/WebCore/page/win/PageWin.cpp b/WebCore/page/win/PageWin.cpp index f4c744a..5d7450c 100644 --- a/WebCore/page/win/PageWin.cpp +++ b/WebCore/page/win/PageWin.cpp @@ -27,12 +27,36 @@ #include "Page.h" #include "Frame.h" +#include "FrameLoaderClient.h" #include "FrameView.h" #include "FloatRect.h" +#include "PluginView.h" #include <windows.h> namespace WebCore { HINSTANCE Page::s_instanceHandle = 0; +void Page::setCanStartPlugins(bool canStartPlugins) +{ + if (m_canStartPlugins == canStartPlugins) + return; + + m_canStartPlugins = canStartPlugins; + + if (!m_canStartPlugins || m_unstartedPlugins.isEmpty()) + return; + + Vector<PluginView*> unstartedPlugins; + copyToVector(m_unstartedPlugins, unstartedPlugins); + m_unstartedPlugins.clear(); + + for (size_t i = 0; i < unstartedPlugins.size(); ++i) { + if (unstartedPlugins[i]->start()) + continue; + unstartedPlugins[i]->parentFrame()->loader()->client()->dispatchDidFailToStartPlugin(unstartedPlugins[i]); + } +} + } // namespace WebCore + diff --git a/WebCore/page/wince/FrameWince.cpp b/WebCore/page/wince/FrameWince.cpp new file mode 100644 index 0000000..480a103 --- /dev/null +++ b/WebCore/page/wince/FrameWince.cpp @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007-2009 Torch Mobile, Inc. + * + * 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 "Frame.h" + +#include "Document.h" +#include "EditorClient.h" +#include "FloatRect.h" +#include "FrameLoader.h" +#include "FrameLoadRequest.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "HTMLIFrameElement.h" +#include "HTMLNames.h" +#include "HTMLTableCellElement.h" +#include "KeyboardEvent.h" +#include "NP_jsobject.h" +#include "npruntime_impl.h" +#include "Page.h" +#include "Plugin.h" +#include "RegularExpression.h" +#include "RenderFrame.h" +#include "RenderTableCell.h" +#include "RenderView.h" +#include "ResourceHandle.h" +#include "runtime_root.h" +#include "Settings.h" +#include "TextResourceDecoder.h" +#include "UserStyleSheetLoader.h" + +#include <windows.h> + +using std::min; + +namespace WebCore { + +using namespace HTMLNames; + +extern HDC g_screenDC; + +void computePageRectsForFrame(Frame* frame, const IntRect& printRect, float headerHeight, float footerHeight, float userScaleFactor, Vector<IntRect>& pages, int& outPageHeight) +{ + ASSERT(frame); + + pages.clear(); + outPageHeight = 0; + + if (!frame->document() || !frame->view() || !frame->document()->renderer()) + return; + + RenderView* root = toRenderView(frame->document()->renderer()); + + if (!root) { + LOG_ERROR("document to be printed has no renderer"); + return; + } + + if (userScaleFactor <= 0) { + LOG_ERROR("userScaleFactor has bad value %.2f", userScaleFactor); + return; + } + + float ratio = (float)printRect.height() / (float)printRect.width(); + + float pageWidth = (float) root->overflowWidth(); + float pageHeight = pageWidth * ratio; + outPageHeight = (int) pageHeight; // this is the height of the page adjusted by margins + pageHeight -= (headerHeight + footerHeight); + + if (pageHeight <= 0) { + LOG_ERROR("pageHeight has bad value %.2f", pageHeight); + return; + } + + float currPageHeight = pageHeight / userScaleFactor; + float docHeight = root->layer()->height(); + float docWidth = root->layer()->width(); + float currPageWidth = pageWidth / userScaleFactor; + + + // always return at least one page, since empty files should print a blank page + float printedPagesHeight = 0.0; + do { + float proposedBottom = min(docHeight, printedPagesHeight + pageHeight); + frame->view()->adjustPageHeight(&proposedBottom, printedPagesHeight, proposedBottom, printedPagesHeight); + currPageHeight = max(1.0f, proposedBottom - printedPagesHeight); + + pages.append(IntRect(0, printedPagesHeight, currPageWidth, currPageHeight)); + printedPagesHeight += currPageHeight; + } while (printedPagesHeight < docHeight); +} + +HBITMAP imageFromSelection(Frame* frame, bool forceBlackText) +{ + if (!frame->view()) + return 0; + + frame->view()->setPaintRestriction(forceBlackText ? PaintRestrictionSelectionOnlyBlackText : PaintRestrictionSelectionOnly); + FloatRect fr = frame->selectionBounds(); + IntRect ir((int)fr.x(), (int)fr.y(), (int)fr.width(), (int)fr.height()); + if (ir.isEmpty()) + return 0; + + int w; + int h; + FrameView* view = frame->view(); + if (view->parent()) { + ir.setLocation(view->parent()->convertChildToSelf(view, ir.location())); + w = ir.width() * view->scale() + 0.5; + h = ir.height() * view->scale() + 0.5; + } else { + ir = view->contentsToWindow(ir); + w = ir.width(); + h = ir.height(); + } + + OwnPtr<HDC> bmpDC(CreateCompatibleDC(g_screenDC)); + HBITMAP hBmp = MemoryManager::createCompatibleBitmap(g_screenDC, w, h); + if (!hBmp) + return 0; + + HBITMAP hbmpOld = (HBITMAP)SelectObject(bmpDC.get(), hBmp); + + { + GraphicsContext gc(bmpDC.get()); + frame->document()->updateLayout(); + view->paint(&gc, ir); + } + + SelectObject(bmpDC.get(), hbmpOld); + + frame->view()->setPaintRestriction(PaintRestrictionNone); + + return hBmp; +} + +DragImageRef Frame::dragImageForSelection() +{ + if (selection()->isRange()) + return imageFromSelection(this, false); + + return 0; +} + +void Frame::setUserStyleSheetLocation(const KURL& url) +{ + delete m_userStyleSheetLoader; + m_userStyleSheetLoader = 0; + if (m_doc && m_doc->docLoader()) + m_userStyleSheetLoader = new UserStyleSheetLoader(m_doc, url.string()); +} + +void Frame::setUserStyleSheet(const String& styleSheet) +{ + delete m_userStyleSheetLoader; + m_userStyleSheetLoader = 0; + if (m_doc) + m_doc->setUserStyleSheet(styleSheet); +} + +} // namespace WebCore diff --git a/WebCore/page/wx/EventHandlerWx.cpp b/WebCore/page/wx/EventHandlerWx.cpp index a0d8b23..65a743c 100644 --- a/WebCore/page/wx/EventHandlerWx.cpp +++ b/WebCore/page/wx/EventHandlerWx.cpp @@ -62,7 +62,7 @@ bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestR if (!event.targetNode() || !event.targetNode()->renderer() || !event.targetNode()->renderer()->isWidget()) return false; - return passMouseDownEventToWidget(static_cast<RenderWidget*>(event.targetNode()->renderer())->widget()); + return passMouseDownEventToWidget(toRenderWidget(event.targetNode()->renderer())->widget()); } bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget) |