diff options
author | darin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-30 04:19:34 +0000 |
---|---|---|
committer | darin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-30 04:19:34 +0000 |
commit | 42b7289e9b7667a34c82a1395d380a00643f0c28 (patch) | |
tree | 50dae4af6a888936c5b6d893d97d9f7d03696c55 | |
parent | 29672abd046612aa325fcfc0e69e1cc4d91c299c (diff) | |
download | chromium_src-42b7289e9b7667a34c82a1395d380a00643f0c28.zip chromium_src-42b7289e9b7667a34c82a1395d380a00643f0c28.tar.gz chromium_src-42b7289e9b7667a34c82a1395d380a00643f0c28.tar.bz2 |
Moves webview_impl.cc, webframe_impl.cc and webframeloaderclient_impl.cc into
webkit/api/src.
R=yaar
BUG=25896,25897,25902
TEST=none
Review URL: http://codereview.chromium.org/341030
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@30558 0039d316-1c4b-4281-b951-d872f2087c98
49 files changed, 6537 insertions, 6387 deletions
diff --git a/webkit/api/src/AutocompletePopupMenuClient.cpp b/webkit/api/src/AutocompletePopupMenuClient.cpp new file mode 100644 index 0000000..96cccf5 --- /dev/null +++ b/webkit/api/src/AutocompletePopupMenuClient.cpp @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "AutocompletePopupMenuClient.h" + +#include "CSSValueKeywords.h" +#include "CSSStyleSelector.h" +#include "FrameView.h" +#include "HTMLInputElement.h" +#include "RenderTheme.h" +#include "WebVector.h" +#include "WebViewImpl.h" + +using namespace WebCore; + +namespace WebKit { + +AutocompletePopupMenuClient::AutocompletePopupMenuClient(WebViewImpl* webView) + : m_textField(0) + , m_selectedIndex(0) + , m_webView(webView) +{ +} + +AutocompletePopupMenuClient::~AutocompletePopupMenuClient() +{ +} + +void AutocompletePopupMenuClient::initialize( + HTMLInputElement* textField, + const WebVector<WebString>& suggestions, + int defaultSuggestionIndex) +{ + ASSERT(defaultSuggestionIndex < static_cast<int>(suggestions.size())); + m_textField = textField; + m_selectedIndex = defaultSuggestionIndex; + setSuggestions(suggestions); + + FontDescription fontDescription; + m_webView->theme()->systemFont(CSSValueWebkitControl, fontDescription); + // Use a smaller font size to match IE/Firefox. + // FIXME: http://crbug.com/7376 use the system size instead of a + // fixed font size value. + fontDescription.setComputedSize(12.0); + Font font(fontDescription, 0, 0); + font.update(textField->document()->styleSelector()->fontSelector()); + // The direction of text in popup menu is set the same as the direction of + // the input element: textField. + m_style.set(new PopupMenuStyle(Color::black, Color::white, font, true, + Length(WebCore::Fixed), + textField->renderer()->style()->direction())); +} + +void AutocompletePopupMenuClient::valueChanged(unsigned listIndex, bool fireEvents) +{ + m_textField->setValue(m_suggestions[listIndex]); + EditorClientImpl* editor = + static_cast<EditorClientImpl*>(m_webView->page()->editorClient()); + ASSERT(editor); + editor->onAutofillSuggestionAccepted( + static_cast<HTMLInputElement*>(m_textField.get())); +} + +String AutocompletePopupMenuClient::itemText(unsigned listIndex) const +{ + return m_suggestions[listIndex]; +} + +PopupMenuStyle AutocompletePopupMenuClient::itemStyle(unsigned listIndex) const +{ + return *m_style; +} + +PopupMenuStyle AutocompletePopupMenuClient::menuStyle() const +{ + return *m_style; +} + +int AutocompletePopupMenuClient::clientPaddingLeft() const +{ + // Bug http://crbug.com/7708 seems to indicate the style can be NULL. + RenderStyle* style = textFieldStyle(); + return style ? m_webView->theme()->popupInternalPaddingLeft(style) : 0; +} + +int AutocompletePopupMenuClient::clientPaddingRight() const +{ + // Bug http://crbug.com/7708 seems to indicate the style can be NULL. + RenderStyle* style = textFieldStyle(); + return style ? m_webView->theme()->popupInternalPaddingRight(style) : 0; +} + +void AutocompletePopupMenuClient::popupDidHide() +{ + m_webView->autoCompletePopupDidHide(); +} + +void AutocompletePopupMenuClient::setTextFromItem(unsigned listIndex) +{ + m_textField->setValue(m_suggestions[listIndex]); +} + +FontSelector* AutocompletePopupMenuClient::fontSelector() const +{ + return m_textField->document()->styleSelector()->fontSelector(); +} + +HostWindow* AutocompletePopupMenuClient::hostWindow() const +{ + return m_textField->document()->view()->hostWindow(); +} + +PassRefPtr<Scrollbar> AutocompletePopupMenuClient::createScrollbar( + ScrollbarClient* client, + ScrollbarOrientation orientation, + ScrollbarControlSize size) +{ + return Scrollbar::createNativeScrollbar(client, orientation, size); +} + +void AutocompletePopupMenuClient::setSuggestions(const WebVector<WebString>& suggestions) +{ + m_suggestions.clear(); + for (size_t i = 0; i < suggestions.size(); ++i) + m_suggestions.append(suggestions[i]); + // Try to preserve selection if possible. + if (m_selectedIndex >= static_cast<int>(suggestions.size())) + m_selectedIndex = -1; +} + +void AutocompletePopupMenuClient::removeItemAtIndex(int index) +{ + ASSERT(index >= 0 && index < static_cast<int>(m_suggestions.size())); + m_suggestions.remove(index); +} + +RenderStyle* AutocompletePopupMenuClient::textFieldStyle() const +{ + RenderStyle* style = m_textField->computedStyle(); + if (!style) { + // It seems we can only have an NULL style in a TextField if the + // node is dettached, in which case we the popup shoud not be + // showing. Please report this in http://crbug.com/7708 and + // include the page you were visiting. + ASSERT_NOT_REACHED(); + } + return style; +} + +} // namespace WebKit diff --git a/webkit/api/src/AutocompletePopupMenuClient.h b/webkit/api/src/AutocompletePopupMenuClient.h new file mode 100644 index 0000000..ad24e54 --- /dev/null +++ b/webkit/api/src/AutocompletePopupMenuClient.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "PopupMenuClient.h" + +namespace WebCore { +class HTMLInputElement; +class PopupMenuStyle; +class RenderStyle; +} + +namespace WebKit { +class WebString; +class WebViewImpl; +template <typename T> class WebVector; + +// AutocompletePopupMenuClient +class AutocompletePopupMenuClient : public WebCore::PopupMenuClient { +public: + AutocompletePopupMenuClient(WebViewImpl* webview); + ~AutocompletePopupMenuClient(); + + void initialize(WebCore::HTMLInputElement*, + const WebVector<WebString>& suggestions, + int defaultSuggestionIndex); + + WebCore::HTMLInputElement* textField() const { return m_textField.get(); } + + void setSuggestions(const WebVector<WebString>&); + void removeItemAtIndex(int index); + + // WebCore::PopupMenuClient methods: + virtual void valueChanged(unsigned listIndex, bool fireEvents = true); + virtual WebCore::String itemText(unsigned listIndex) const; + virtual WebCore::String itemToolTip(unsigned lastIndex) const { return WebCore::String(); } + virtual bool itemIsEnabled(unsigned listIndex) const { return true; } + virtual WebCore::PopupMenuStyle itemStyle(unsigned listIndex) const; + virtual WebCore::PopupMenuStyle menuStyle() const; + virtual int clientInsetLeft() const { return 0; } + virtual int clientInsetRight() const { return 0; } + virtual int clientPaddingLeft() const; + virtual int clientPaddingRight() const; + virtual int listSize() const { return m_suggestions.size(); } + virtual int selectedIndex() const { return m_selectedIndex; } + virtual void popupDidHide(); + virtual bool itemIsSeparator(unsigned listIndex) const { return false; } + virtual bool itemIsLabel(unsigned listIndex) const { return false; } + virtual bool itemIsSelected(unsigned listIndex) const { return false; } + virtual bool shouldPopOver() const { return false; } + virtual bool valueShouldChangeOnHotTrack() const { return false; } + virtual void setTextFromItem(unsigned listIndex); + virtual WebCore::FontSelector* fontSelector() const; + virtual WebCore::HostWindow* hostWindow() const; + virtual PassRefPtr<WebCore::Scrollbar> createScrollbar( + WebCore::ScrollbarClient* client, + WebCore::ScrollbarOrientation orientation, + WebCore::ScrollbarControlSize size); + +private: + WebCore::RenderStyle* textFieldStyle() const; + + RefPtr<WebCore::HTMLInputElement> m_textField; + Vector<WebCore::String> m_suggestions; + int m_selectedIndex; + WebViewImpl* m_webView; + OwnPtr<WebCore::PopupMenuStyle> m_style; +}; + +} // namespace WebKit diff --git a/webkit/api/src/BackForwardListClientImpl.cpp b/webkit/api/src/BackForwardListClientImpl.cpp index fc6defd..8feae32 100644 --- a/webkit/api/src/BackForwardListClientImpl.cpp +++ b/webkit/api/src/BackForwardListClientImpl.cpp @@ -33,9 +33,7 @@ #include "HistoryItem.h" #include "WebViewClient.h" - -// FIXME: Remove this once WebViewImpl moves out of glue/. -#include "webkit/glue/webview_impl.h" +#include "WebViewImpl.h" using namespace WebCore; @@ -52,13 +50,13 @@ BackForwardListClientImpl::~BackForwardListClientImpl() { } -void BackForwardListClientImpl::SetCurrentHistoryItem(HistoryItem* item) +void BackForwardListClientImpl::setCurrentHistoryItem(HistoryItem* item) { m_previousItem = m_currentItem; m_currentItem = item; } -HistoryItem* BackForwardListClientImpl::GetPreviousHistoryItem() const +HistoryItem* BackForwardListClientImpl::previousHistoryItem() const { return m_previousItem.get(); } @@ -70,7 +68,7 @@ void BackForwardListClientImpl::addItem(PassRefPtr<HistoryItem> item) // If WebCore adds a new HistoryItem, it means this is a new navigation (ie, // not a reload or back/forward). - m_webView->ObserveNewNavigation(); + m_webView->observeNewNavigation(); if (m_webView->client()) m_webView->client()->didAddHistoryItem(); diff --git a/webkit/api/src/BackForwardListClientImpl.h b/webkit/api/src/BackForwardListClientImpl.h index e498ea0..1d8beb0 100644 --- a/webkit/api/src/BackForwardListClientImpl.h +++ b/webkit/api/src/BackForwardListClientImpl.h @@ -33,9 +33,8 @@ #include "BackForwardList.h" -class WebViewImpl; - namespace WebKit { +class WebViewImpl; extern const char backForwardNavigationScheme[]; @@ -44,8 +43,8 @@ public: BackForwardListClientImpl(WebViewImpl* webview); ~BackForwardListClientImpl(); - void SetCurrentHistoryItem(WebCore::HistoryItem* item); - WebCore::HistoryItem* GetPreviousHistoryItem() const; + void setCurrentHistoryItem(WebCore::HistoryItem* item); + WebCore::HistoryItem* previousHistoryItem() const; private: // WebCore::BackForwardListClient methods: diff --git a/webkit/api/src/ChromeClientImpl.cpp b/webkit/api/src/ChromeClientImpl.cpp index a81c3aa..a28589c 100644 --- a/webkit/api/src/ChromeClientImpl.cpp +++ b/webkit/api/src/ChromeClientImpl.cpp @@ -56,24 +56,21 @@ #include "WebAccessibilityObject.h" #include "WebConsoleMessage.h" #include "WebCursorInfo.h" -#include "WebFileChooserCompletion.h" +#include "WebFileChooserCompletionImpl.h" #include "WebFrameClient.h" +#include "WebFrameImpl.h" #include "WebInputEvent.h" #include "WebKit.h" +#include "WebPopupMenuImpl.h" #include "WebPopupMenuInfo.h" #include "WebRect.h" #include "WebTextDirection.h" #include "WebURLRequest.h" #include "WebViewClient.h" -#include "WebFileChooserCompletionImpl.h" -#include "WebPopupMenuImpl.h" +#include "WebViewImpl.h" #include "WindowFeatures.h" #include "WrappedResourceRequest.h" -// FIXME: Remove these once they move out of glue/. -#include "webkit/glue/webframe_impl.h" -#include "webkit/glue/webview_impl.h" - using namespace WebCore; namespace WebKit { @@ -148,14 +145,14 @@ void ChromeClientImpl::focus() // If accessibility is enabled, we should notify assistive technology that // the active AccessibilityObject changed. - const Frame* frame = m_webView->GetFocusedWebCoreFrame(); + const Frame* frame = m_webView->focusedWebCoreFrame(); if (!frame) return; Document* doc = frame->document(); if (doc && doc->axObjectCache()->accessibilityEnabled()) { - Node* focusedNode = m_webView->GetFocusedNode(); + Node* focusedNode = m_webView->focusedWebCoreNode(); if (!focusedNode) { // Could not retrieve focused Node. @@ -202,7 +199,7 @@ Page* ChromeClientImpl::createWindow( return 0; WebViewImpl* newView = static_cast<WebViewImpl*>( - m_webView->client()->createView(WebFrameImpl::FromFrame(frame))); + m_webView->client()->createView(WebFrameImpl::fromFrame(frame))); if (!newView) return 0; @@ -210,13 +207,13 @@ Page* ChromeClientImpl::createWindow( // This corresponds to window.open(""), for example. if (!r.resourceRequest().isEmpty()) { WrappedResourceRequest request(r.resourceRequest()); - newView->main_frame()->loadRequest(request); + newView->mainFrame()->loadRequest(request); } return newView->page(); } -static inline bool CurrentEventShouldCauseBackgroundTab(const WebInputEvent* inputEvent) +static inline bool currentEventShouldCauseBackgroundTab(const WebInputEvent* inputEvent) { if (!inputEvent) return false; @@ -246,7 +243,7 @@ static inline bool CurrentEventShouldCauseBackgroundTab(const WebInputEvent* inp bool alt = mouseEvent->modifiers & WebMouseEvent::AltKey; bool meta = mouseEvent->modifiers & WebMouseEvent::MetaKey; - if (!WebViewImpl::NavigationPolicyFromMouseEvent(buttonNumber, ctrl, shift, alt, meta, &policy)) + if (!WebViewImpl::navigationPolicyFromMouseEvent(buttonNumber, ctrl, shift, alt, meta, &policy)) return false; return policy == WebNavigationPolicyNewBackgroundTab; @@ -270,7 +267,7 @@ void ChromeClientImpl::show() WebNavigationPolicy policy = WebNavigationPolicyNewForegroundTab; if (asPopup) policy = WebNavigationPolicyNewPopup; - if (CurrentEventShouldCauseBackgroundTab(WebViewImpl::current_input_event())) + if (currentEventShouldCauseBackgroundTab(WebViewImpl::currentInputEvent())) policy = WebNavigationPolicyNewBackgroundTab; m_webView->client()->show(policy); @@ -312,7 +309,7 @@ void ChromeClientImpl::setScrollbarsVisible(bool value) m_scrollbarsVisible = value; WebFrameImpl* web_frame = static_cast<WebFrameImpl*>(m_webView->mainFrame()); if (web_frame) - web_frame->SetAllowsScrolling(value); + web_frame->setAllowsScrolling(value); } bool ChromeClientImpl::scrollbarsVisible() @@ -359,7 +356,7 @@ bool ChromeClientImpl::runBeforeUnloadConfirmPanel(const String& message, Frame* { if (m_webView->client()) { return m_webView->client()->runModalBeforeUnloadDialog( - WebFrameImpl::FromFrame(frame), message); + WebFrameImpl::fromFrame(frame), message); } return false; } @@ -387,7 +384,7 @@ void ChromeClientImpl::runJavaScriptAlert(Frame* frame, const String& message) V8Proxy::processConsoleMessages(); #endif m_webView->client()->runModalAlertDialog( - WebFrameImpl::FromFrame(frame), message); + WebFrameImpl::fromFrame(frame), message); } } @@ -396,7 +393,7 @@ bool ChromeClientImpl::runJavaScriptConfirm(Frame* frame, const String& message) { if (m_webView->client()) { return m_webView->client()->runModalConfirmDialog( - WebFrameImpl::FromFrame(frame), message); + WebFrameImpl::fromFrame(frame), message); } return false; } @@ -410,7 +407,7 @@ bool ChromeClientImpl::runJavaScriptPrompt(Frame* frame, if (m_webView->client()) { WebString actualValue; bool ok = m_webView->client()->runModalPromptDialog( - WebFrameImpl::FromFrame(frame), + WebFrameImpl::fromFrame(frame), message, defaultValue, &actualValue); @@ -492,7 +489,7 @@ IntRect ChromeClientImpl::windowToScreen(const IntRect& rect) const { void ChromeClientImpl::contentsSizeChanged(Frame* frame, const IntSize& size) const { - WebFrameImpl* webframe = WebFrameImpl::FromFrame(frame); + WebFrameImpl* webframe = WebFrameImpl::fromFrame(frame); if (webframe->client()) webframe->client()->didChangeContentsSize(webframe, size); } @@ -527,7 +524,7 @@ void ChromeClientImpl::setToolTip(const String& tooltipText, TextDirection dir) void ChromeClientImpl::print(Frame* frame) { if (m_webView->client()) - m_webView->client()->printPage(WebFrameImpl::FromFrame(frame)); + m_webView->client()->printPage(WebFrameImpl::fromFrame(frame)); } void ChromeClientImpl::exceededDatabaseQuota(Frame* frame, const String& databaseName) @@ -613,7 +610,7 @@ void ChromeClientImpl::formStateDidChange(const Node* node) { // The current history item is not updated yet. That happens lazily when // WebFrame::currentHistoryItem is requested. - WebFrameImpl* webframe = WebFrameImpl::FromFrame(node->document()->frame()); + WebFrameImpl* webframe = WebFrameImpl::fromFrame(node->document()->frame()); if (webframe->client()) webframe->client()->didUpdateCurrentHistoryItem(webframe); } @@ -655,7 +652,7 @@ void ChromeClientImpl::getPopupMenuInfo(PopupContainer* popupContainer, #if ENABLE(NOTIFICATIONS) NotificationPresenter* ChromeClientImpl::notificationPresenter() const { - return m_webView->GetNotificationPresenter(); + return m_webView->notificationPresenterImpl(); } #endif diff --git a/webkit/api/src/ChromeClientImpl.h b/webkit/api/src/ChromeClientImpl.h index 427390a..9a1e443 100644 --- a/webkit/api/src/ChromeClientImpl.h +++ b/webkit/api/src/ChromeClientImpl.h @@ -33,8 +33,6 @@ #include "ChromeClientChromium.h" -class WebViewImpl; - namespace WebCore { class HTMLParserQuirks; class PopupContainer; @@ -43,6 +41,7 @@ struct WindowFeatures; } namespace WebKit { +class WebViewImpl; struct WebCursorInfo; struct WebPopupMenuInfo; diff --git a/webkit/api/src/ContextMenuClientImpl.cpp b/webkit/api/src/ContextMenuClientImpl.cpp index fd2a7a8..f32c72f 100644 --- a/webkit/api/src/ContextMenuClientImpl.cpp +++ b/webkit/api/src/ContextMenuClientImpl.cpp @@ -48,17 +48,14 @@ #include "Widget.h" #include "WebContextMenuData.h" -#include "WebFrame.h" +#include "WebDataSourceImpl.h" +#include "WebFrameImpl.h" #include "WebPoint.h" #include "WebString.h" #include "WebURL.h" #include "WebURLResponse.h" #include "WebViewClient.h" -#include "WebDataSourceImpl.h" -#undef LOG - -// FIXME: Temporary hack until WebViewImpl is in api/src. -#include "webkit/glue/webview_impl.h" +#include "WebViewImpl.h" using namespace WebCore; @@ -143,7 +140,7 @@ PlatformMenuDescription ContextMenuClientImpl::getCustomMenuFromDefaultItems( // response to user input (Mouse event WM_RBUTTONDOWN, // Keyboard events KeyVK_APPS, Shift+F10). Check if this is being invoked // in response to the above input events before popping up the context menu. - if (!m_webView->context_menu_allowed()) + if (!m_webView->contextMenuAllowed()) return 0; HitTestResult r = defaultMenu->hitTestResult(); @@ -192,8 +189,8 @@ PlatformMenuDescription ContextMenuClientImpl::getCustomMenuFromDefaultItems( data.frameEncoding = selectedFrame->loader()->encoding(); // Send the frame and page URLs in any case. - data.pageURL = urlFromFrame(m_webView->main_frame()->frame()); - if (selectedFrame != m_webView->main_frame()->frame()) + data.pageURL = urlFromFrame(m_webView->mainFrameImpl()->frame()); + if (selectedFrame != m_webView->mainFrameImpl()->frame()) data.frameURL = urlFromFrame(selectedFrame); if (r.isSelected()) @@ -202,7 +199,7 @@ PlatformMenuDescription ContextMenuClientImpl::getCustomMenuFromDefaultItems( data.isEditable = false; if (r.isContentEditable()) { data.isEditable = true; - if (m_webView->GetFocusedWebCoreFrame()->editor()->isContinuousSpellCheckingEnabled()) { + if (m_webView->focusedWebCoreFrame()->editor()->isContinuousSpellCheckingEnabled()) { data.isSpellCheckingEnabled = true; data.misspelledWord = selectMisspelledWord(defaultMenu, selectedFrame); } @@ -216,22 +213,22 @@ PlatformMenuDescription ContextMenuClientImpl::getCustomMenuFromDefaultItems( // Compute edit flags. data.editFlags = WebContextMenuData::CanDoNone; - if (m_webView->GetFocusedWebCoreFrame()->editor()->canUndo()) + if (m_webView->focusedWebCoreFrame()->editor()->canUndo()) data.editFlags |= WebContextMenuData::CanUndo; - if (m_webView->GetFocusedWebCoreFrame()->editor()->canRedo()) + if (m_webView->focusedWebCoreFrame()->editor()->canRedo()) data.editFlags |= WebContextMenuData::CanRedo; - if (m_webView->GetFocusedWebCoreFrame()->editor()->canCut()) + if (m_webView->focusedWebCoreFrame()->editor()->canCut()) data.editFlags |= WebContextMenuData::CanCut; - if (m_webView->GetFocusedWebCoreFrame()->editor()->canCopy()) + if (m_webView->focusedWebCoreFrame()->editor()->canCopy()) data.editFlags |= WebContextMenuData::CanCopy; - if (m_webView->GetFocusedWebCoreFrame()->editor()->canPaste()) + if (m_webView->focusedWebCoreFrame()->editor()->canPaste()) data.editFlags |= WebContextMenuData::CanPaste; - if (m_webView->GetFocusedWebCoreFrame()->editor()->canDelete()) + if (m_webView->focusedWebCoreFrame()->editor()->canDelete()) data.editFlags |= WebContextMenuData::CanDelete; // We can always select all... data.editFlags |= WebContextMenuData::CanSelectAll; - WebFrame* selected_web_frame = WebFrameImpl::FromFrame(selectedFrame); + WebFrame* selected_web_frame = WebFrameImpl::fromFrame(selectedFrame); if (m_webView->client()) m_webView->client()->showContextMenu(selected_web_frame, data); diff --git a/webkit/api/src/ContextMenuClientImpl.h b/webkit/api/src/ContextMenuClientImpl.h index 712891c..a19b247 100644 --- a/webkit/api/src/ContextMenuClientImpl.h +++ b/webkit/api/src/ContextMenuClientImpl.h @@ -33,9 +33,8 @@ #include "ContextMenuClient.h" -class WebViewImpl; - namespace WebKit { + class WebViewImpl; class ContextMenuClientImpl : public WebCore::ContextMenuClient { public: diff --git a/webkit/api/src/DragClientImpl.cpp b/webkit/api/src/DragClientImpl.cpp index 77c5ad8..5d8a9c3 100644 --- a/webkit/api/src/DragClientImpl.cpp +++ b/webkit/api/src/DragClientImpl.cpp @@ -36,9 +36,7 @@ #include "Frame.h" #include "WebDragData.h" #include "WebViewClient.h" - -// FIXME: Remove this once WebViewImpl moves out of glue/. -#include "webkit/glue/webview_impl.h" +#include "WebViewImpl.h" using namespace WebCore; @@ -85,7 +83,7 @@ void DragClientImpl::startDrag(DragImageRef dragImage, if (!clipboard->sourceOperation(dragOperationMask)) dragOperationMask = DragOperationEvery; - m_webView->StartDragging( + m_webView->startDragging( eventPos, dragData, static_cast<WebDragOperationsMask>(dragOperationMask)); } diff --git a/webkit/api/src/DragClientImpl.h b/webkit/api/src/DragClientImpl.h index 6eea773..7012370 100644 --- a/webkit/api/src/DragClientImpl.h +++ b/webkit/api/src/DragClientImpl.h @@ -41,9 +41,8 @@ class IntPoint; class KURL; } -class WebViewImpl; - namespace WebKit { +class WebViewImpl; class DragClientImpl : public WebCore::DragClient { public: diff --git a/webkit/api/src/EditorClientImpl.cpp b/webkit/api/src/EditorClientImpl.cpp index 058b892..d604d68 100644 --- a/webkit/api/src/EditorClientImpl.cpp +++ b/webkit/api/src/EditorClientImpl.cpp @@ -41,15 +41,16 @@ #include "PlatformString.h" #include "RenderObject.h" +#include "DOMUtilitiesPrivate.h" +#include "PasswordAutocompleteListener.h" #include "WebEditingAction.h" +#include "WebFrameImpl.h" #include "WebKit.h" #include "WebNode.h" #include "WebRange.h" #include "WebTextAffinity.h" #include "WebViewClient.h" -#include "DOMUtilitiesPrivate.h" -#include "PasswordAutocompleteListener.h" -#include "webkit/glue/webview_impl.h" +#include "WebViewImpl.h" using namespace WebCore; @@ -114,7 +115,7 @@ bool EditorClientImpl::shouldSpellcheckByDefault() { // Spellcheck should be enabled for all editable areas (such as textareas, // contentEditable regions, and designMode docs), except text inputs. - const Frame* frame = m_webView->GetFocusedWebCoreFrame(); + const Frame* frame = m_webView->focusedWebCoreFrame(); if (!frame) return false; const Editor* editor = frame->editor(); @@ -265,7 +266,7 @@ void EditorClientImpl::didBeginEditing() void EditorClientImpl::respondToChangedSelection() { if (m_webView->client()) { - Frame* frame = m_webView->GetFocusedWebCoreFrame(); + Frame* frame = m_webView->focusedWebCoreFrame(); if (frame) m_webView->client()->didChangeSelection(!frame->selection()->isRange()); } @@ -653,7 +654,7 @@ void EditorClientImpl::textFieldDidEndEditing(Element* element) m_autofillTimer.stop(); // Hide any showing popup. - m_webView->HideAutoCompletePopup(); + m_webView->hideAutoCompletePopup(); if (!m_webView->client()) return; // The page is getting closed, don't fill the password. @@ -663,8 +664,8 @@ void EditorClientImpl::textFieldDidEndEditing(Element* element) if (!inputElement) return; - WebFrameImpl* webframe = WebFrameImpl::FromFrame(inputElement->document()->frame()); - PasswordAutocompleteListener* listener = webframe->GetPasswordListener(inputElement); + WebFrameImpl* webframe = WebFrameImpl::fromFrame(inputElement->document()->frame()); + PasswordAutocompleteListener* listener = webframe->getPasswordListener(inputElement); if (!listener) return; @@ -744,15 +745,15 @@ void EditorClientImpl::doAutofill(Timer<EditorClientImpl>* timer) && inputElement->selectionEnd() == static_cast<int>(value.length()); if ((!args->autofillOnEmptyValue && value.isEmpty()) || !isCaretAtEnd) { - m_webView->HideAutoCompletePopup(); + m_webView->hideAutoCompletePopup(); return; } // First let's see if there is a password listener for that element. // We won't trigger form autofill in that case, as having both behavior on // a node would be confusing. - WebFrameImpl* webframe = WebFrameImpl::FromFrame(inputElement->document()->frame()); - PasswordAutocompleteListener* listener = webframe->GetPasswordListener(inputElement); + WebFrameImpl* webframe = WebFrameImpl::fromFrame(inputElement->document()->frame()); + PasswordAutocompleteListener* listener = webframe->getPasswordListener(inputElement); if (listener) { if (args->autofillFormOnly) return; @@ -780,8 +781,8 @@ void EditorClientImpl::cancelPendingAutofill() void EditorClientImpl::onAutofillSuggestionAccepted(HTMLInputElement* textField) { - WebFrameImpl* webframe = WebFrameImpl::FromFrame(textField->document()->frame()); - PasswordAutocompleteListener* listener = webframe->GetPasswordListener(textField); + WebFrameImpl* webframe = WebFrameImpl::fromFrame(textField->document()->frame()); + PasswordAutocompleteListener* listener = webframe->getPasswordListener(textField); // Password listeners need to autocomplete other fields that depend on the // input element with autofill suggestions. if (listener) diff --git a/webkit/api/src/EditorClientImpl.h b/webkit/api/src/EditorClientImpl.h index 55cd0b7..fd08b4d 100644 --- a/webkit/api/src/EditorClientImpl.h +++ b/webkit/api/src/EditorClientImpl.h @@ -39,9 +39,8 @@ namespace WebCore { class HTMLInputElement; } -class WebViewImpl; - namespace WebKit { +class WebViewImpl; class EditorClientImpl : public WebCore::EditorClient { public: diff --git a/webkit/api/src/FrameLoaderClientImpl.cpp b/webkit/api/src/FrameLoaderClientImpl.cpp new file mode 100644 index 0000000..3b7a906 --- /dev/null +++ b/webkit/api/src/FrameLoaderClientImpl.cpp @@ -0,0 +1,1405 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FrameLoaderClientImpl.h" + +#include "Chrome.h" +#include "CString.h" +#include "Document.h" +#include "DocumentLoader.h" +#include "HTMLAppletElement.h" +#include "HTMLFormElement.h" // needed by FormState.h +#include "HTMLNames.h" +#include "FormState.h" +#include "FrameLoader.h" +#include "FrameLoadRequest.h" +#include "HitTestResult.h" +#include "MIMETypeRegistry.h" +#include "MouseEvent.h" +#include "Page.h" +#include "PlatformString.h" +#include "PluginData.h" +#include "StringExtras.h" +#include "WebForm.h" +#include "WebFrameClient.h" +#include "WebFrameImpl.h" +#include "WebNode.h" +#include "WebPlugin.h" +#include "WebPluginParams.h" +#include "WebSecurityOrigin.h" +#include "WebURL.h" +#include "WebURLError.h" +#include "WebVector.h" +#include "WebViewClient.h" +#include "WebViewImpl.h" +#include "WebDataSourceImpl.h" +#include "WebPluginContainerImpl.h" +#include "WebPluginLoadObserver.h" +#include "WindowFeatures.h" +#include "WrappedResourceRequest.h" +#include "WrappedResourceResponse.h" + +// FIXME: remove these +#include "googleurl/src/gurl.h" +#include "net/base/mime_util.h" +#include "webkit/glue/glue_util.h" +#include "webkit/glue/webdevtoolsagent_impl.h" +#include "webkit/glue/webkit_glue.h" + +using namespace WebCore; + +namespace WebKit { + +// Domain for internal error codes. +static const char internalErrorDomain[] = "WebKit"; + +// An internal error code. Used to note a policy change error resulting from +// dispatchDecidePolicyForMIMEType not passing the PolicyUse option. +enum { + PolicyChangeError = -10000, +}; + +FrameLoaderClientImpl::FrameLoaderClientImpl(WebFrameImpl* frame) + : m_webFrame(frame) + , m_hasRepresentation(false) + , m_sentInitialResponseToPlugin(false) + , m_nextNavigationPolicy(WebNavigationPolicyIgnore) { +} + +FrameLoaderClientImpl::~FrameLoaderClientImpl() { +} + +void FrameLoaderClientImpl::frameLoaderDestroyed() +{ + // When the WebFrame was created, it had an extra reference given to it on + // behalf of the Frame. Since the WebFrame owns us, this extra ref also + // serves to keep us alive until the FrameLoader is done with us. The + // FrameLoader calls this method when it's going away. Therefore, we balance + // out that extra reference, which may cause 'this' to be deleted. + m_webFrame->closing(); + m_webFrame->deref(); +} + +void FrameLoaderClientImpl::windowObjectCleared() +{ + if (m_webFrame->client()) + m_webFrame->client()->didClearWindowObject(m_webFrame); + + WebViewImpl* webview = m_webFrame->viewImpl(); + if (webview) { + WebDevToolsAgentImpl* toolsAgent = webview->devToolsAgentImpl(); + if (toolsAgent) + toolsAgent->WindowObjectCleared(m_webFrame); + } +} + +void FrameLoaderClientImpl::documentElementAvailable() +{ + if (m_webFrame->client()) + m_webFrame->client()->didCreateDocumentElement(m_webFrame); +} + +void FrameLoaderClientImpl::didCreateScriptContextForFrame() +{ + if (m_webFrame->client()) + m_webFrame->client()->didCreateScriptContext(m_webFrame); +} + +void FrameLoaderClientImpl::didDestroyScriptContextForFrame() +{ + if (m_webFrame->client()) + m_webFrame->client()->didDestroyScriptContext(m_webFrame); +} + +void FrameLoaderClientImpl::didCreateIsolatedScriptContext() +{ + if (m_webFrame->client()) + m_webFrame->client()->didCreateIsolatedScriptContext(m_webFrame); +} + +void FrameLoaderClientImpl::didPerformFirstNavigation() const +{ +} + +void FrameLoaderClientImpl::registerForIconNotification(bool) +{ +} + +bool FrameLoaderClientImpl::hasWebView() const +{ + return m_webFrame->viewImpl() != 0; +} + +bool FrameLoaderClientImpl::hasFrameView() const +{ + // The Mac port has this notion of a WebFrameView, which seems to be + // some wrapper around an NSView. Since our equivalent is HWND, I guess + // we have a "frameview" whenever we have the toplevel HWND. + return m_webFrame->viewImpl() != 0; +} + +void FrameLoaderClientImpl::makeDocumentView() +{ + m_webFrame->createFrameView(); +} + +void FrameLoaderClientImpl::makeRepresentation(DocumentLoader*) +{ + m_hasRepresentation = true; +} + +void FrameLoaderClientImpl::forceLayout() +{ + // FIXME +} + +void FrameLoaderClientImpl::forceLayoutForNonHTML() +{ + // FIXME +} + +void FrameLoaderClientImpl::setCopiesOnScroll() +{ + // FIXME +} + +void FrameLoaderClientImpl::detachedFromParent2() +{ + // Nothing to do here. +} + +void FrameLoaderClientImpl::detachedFromParent3() +{ + // Close down the proxy. The purpose of this change is to make the + // call to ScriptController::clearWindowShell a no-op when called from + // Frame::pageDestroyed. Without this change, this call to clearWindowShell + // will cause a crash. If you remove/modify this, just ensure that you can + // go to a page and then navigate to a new page without getting any asserts + // or crashes. + m_webFrame->frame()->script()->proxy()->clearForClose(); +} + +// This function is responsible for associating the |identifier| with a given +// subresource load. The following functions that accept an |identifier| are +// called for each subresource, so they should not be dispatched to the +// WebFrame. +void FrameLoaderClientImpl::assignIdentifierToInitialRequest( + unsigned long identifier, DocumentLoader* loader, + const ResourceRequest& request) +{ + if (m_webFrame->client()) { + WrappedResourceRequest webreq(request); + m_webFrame->client()->assignIdentifierToRequest( + m_webFrame, identifier, webreq); + } +} + +// Determines whether the request being loaded by |loader| is a frame or a +// subresource. A subresource in this context is anything other than a frame -- +// this includes images and xmlhttp requests. It is important to note that a +// subresource is NOT limited to stuff loaded through the frame's subresource +// loader. Synchronous xmlhttp requests for example, do not go through the +// subresource loader, but we still label them as TargetIsSubResource. +// +// The important edge cases to consider when modifying this function are +// how synchronous resource loads are treated during load/unload threshold. +static ResourceRequest::TargetType determineTargetTypeFromLoader( + DocumentLoader* loader) +{ + if (loader == loader->frameLoader()->provisionalDocumentLoader()) { + if (loader->frameLoader()->isLoadingMainFrame()) + return ResourceRequest::TargetIsMainFrame; + else + return ResourceRequest::TargetIsSubFrame; + } + return ResourceRequest::TargetIsSubResource; +} + +void FrameLoaderClientImpl::dispatchWillSendRequest( + DocumentLoader* loader, unsigned long identifier, ResourceRequest& request, + const ResourceResponse& redirectResponse) +{ + if (loader) { + // We want to distinguish between a request for a document to be loaded into + // the main frame, a sub-frame, or the sub-objects in that document. + request.setTargetType(determineTargetTypeFromLoader(loader)); + } + + // FrameLoader::loadEmptyDocumentSynchronously() creates an empty document + // with no URL. We don't like that, so we'll rename it to about:blank. + if (request.url().isEmpty()) + request.setURL(KURL(ParsedURLString, "about:blank")); + if (request.firstPartyForCookies().isEmpty()) + request.setFirstPartyForCookies(KURL(ParsedURLString, "about:blank")); + + // Give the WebFrameClient a crack at the request. + if (m_webFrame->client()) { + WrappedResourceRequest webreq(request); + WrappedResourceResponse webresp(redirectResponse); + m_webFrame->client()->willSendRequest( + m_webFrame, identifier, webreq, webresp); + } +} + +bool FrameLoaderClientImpl::shouldUseCredentialStorage( + DocumentLoader*, unsigned long identifier) +{ + // FIXME + // Intended to pass through to a method on the resource load delegate. + // If implemented, that method controls whether the browser should ask the + // networking layer for a stored default credential for the page (say from + // the Mac OS keychain). If the method returns false, the user should be + // presented with an authentication challenge whether or not the networking + // layer has a credential stored. + // This returns true for backward compatibility: the ability to override the + // system credential store is new. (Actually, not yet fully implemented in + // WebKit, as of this writing.) + return true; +} + +void FrameLoaderClientImpl::dispatchDidReceiveAuthenticationChallenge( + DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) +{ + // FIXME +} + +void FrameLoaderClientImpl::dispatchDidCancelAuthenticationChallenge( + DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) +{ + // FIXME +} + +void FrameLoaderClientImpl::dispatchDidReceiveResponse(DocumentLoader* loader, + unsigned long identifier, + const ResourceResponse& response) +{ + if (m_webFrame->client()) { + WrappedResourceResponse webresp(response); + m_webFrame->client()->didReceiveResponse(m_webFrame, identifier, webresp); + } +} + +void FrameLoaderClientImpl::dispatchDidReceiveContentLength( + DocumentLoader* loader, + unsigned long identifier, + int lengthReceived) +{ +} + +// Called when a particular resource load completes +void FrameLoaderClientImpl::dispatchDidFinishLoading(DocumentLoader* loader, + unsigned long identifier) +{ + if (m_webFrame->client()) + m_webFrame->client()->didFinishResourceLoad(m_webFrame, identifier); +} + +void FrameLoaderClientImpl::dispatchDidFailLoading(DocumentLoader* loader, + unsigned long identifier, + const ResourceError& error) +{ + if (m_webFrame->client()) + m_webFrame->client()->didFailResourceLoad(m_webFrame, identifier, error); +} + +void FrameLoaderClientImpl::dispatchDidFinishDocumentLoad() +{ + // A frame may be reused. This call ensures we don't hold on to our password + // listeners and their associated HTMLInputElements. + m_webFrame->clearPasswordListeners(); + + if (m_webFrame->client()) + m_webFrame->client()->didFinishDocumentLoad(m_webFrame); +} + +bool FrameLoaderClientImpl::dispatchDidLoadResourceFromMemoryCache( + DocumentLoader* loader, + const ResourceRequest& request, + const ResourceResponse& response, + int length) +{ + if (m_webFrame->client()) { + WrappedResourceRequest webreq(request); + WrappedResourceResponse webresp(response); + m_webFrame->client()->didLoadResourceFromMemoryCache( + m_webFrame, webreq, webresp); + } + return false; // Do not suppress remaining notifications +} + +void FrameLoaderClientImpl::dispatchDidLoadResourceByXMLHttpRequest( + unsigned long identifier, + const ScriptString& source) +{ +} + +void FrameLoaderClientImpl::dispatchDidHandleOnloadEvents() +{ + if (m_webFrame->client()) + m_webFrame->client()->didHandleOnloadEvents(m_webFrame); +} + +// Redirect Tracking +// ================= +// We want to keep track of the chain of redirects that occur during page +// loading. There are two types of redirects, server redirects which are HTTP +// response codes, and client redirects which are document.location= and meta +// refreshes. +// +// This outlines the callbacks that we get in different redirect situations, +// and how each call modifies the redirect chain. +// +// Normal page load +// ---------------- +// dispatchDidStartProvisionalLoad() -> adds URL to the redirect list +// dispatchDidCommitLoad() -> DISPATCHES & clears list +// +// Server redirect (success) +// ------------------------- +// dispatchDidStartProvisionalLoad() -> adds source URL +// dispatchDidReceiveServerRedirectForProvisionalLoad() -> adds dest URL +// dispatchDidCommitLoad() -> DISPATCHES +// +// Client redirect (success) +// ------------------------- +// (on page) +// dispatchWillPerformClientRedirect() -> saves expected redirect +// dispatchDidStartProvisionalLoad() -> appends redirect source (since +// it matches the expected redirect) +// and the current page as the dest) +// dispatchDidCancelClientRedirect() -> clears expected redirect +// dispatchDidCommitLoad() -> DISPATCHES +// +// Client redirect (cancelled) +// (e.g meta-refresh trumped by manual doc.location change, or just cancelled +// because a link was clicked that requires the meta refresh to be rescheduled +// (the SOURCE URL may have changed). +// --------------------------- +// dispatchDidCancelClientRedirect() -> clears expected redirect +// dispatchDidStartProvisionalLoad() -> adds only URL to redirect list +// dispatchDidCommitLoad() -> DISPATCHES & clears list +// rescheduled ? dispatchWillPerformClientRedirect() -> saves expected redirect +// : nothing + +// Client redirect (failure) +// ------------------------- +// (on page) +// dispatchWillPerformClientRedirect() -> saves expected redirect +// dispatchDidStartProvisionalLoad() -> appends redirect source (since +// it matches the expected redirect) +// and the current page as the dest) +// dispatchDidCancelClientRedirect() +// dispatchDidFailProvisionalLoad() +// +// Load 1 -> Server redirect to 2 -> client redirect to 3 -> server redirect to 4 +// ------------------------------------------------------------------------------ +// dispatchDidStartProvisionalLoad() -> adds source URL 1 +// dispatchDidReceiveServerRedirectForProvisionalLoad() -> adds dest URL 2 +// dispatchDidCommitLoad() -> DISPATCHES 1+2 +// -- begin client redirect and NEW DATA SOURCE +// dispatchWillPerformClientRedirect() -> saves expected redirect +// dispatchDidStartProvisionalLoad() -> appends URL 2 and URL 3 +// dispatchDidReceiveServerRedirectForProvisionalLoad() -> appends destination URL 4 +// dispatchDidCancelClientRedirect() -> clears expected redirect +// dispatchDidCommitLoad() -> DISPATCHES +// +// Interesting case with multiple location changes involving anchors. +// Load page 1 containing future client-redirect (back to 1, e.g meta refresh) > Click +// on a link back to the same page (i.e an anchor href) > +// client-redirect finally fires (with new source, set to 1#anchor) +// ----------------------------------------------------------------------------- +// dispatchWillPerformClientRedirect(non-zero 'interval' param) -> saves expected redirect +// -- click on anchor href +// dispatchDidCancelClientRedirect() -> clears expected redirect +// dispatchDidStartProvisionalLoad() -> adds 1#anchor source +// dispatchDidCommitLoad() -> DISPATCHES 1#anchor +// dispatchWillPerformClientRedirect() -> saves exp. source (1#anchor) +// -- redirect timer fires +// dispatchDidStartProvisionalLoad() -> appends 1#anchor (src) and 1 (dest) +// dispatchDidCancelClientRedirect() -> clears expected redirect +// dispatchDidCommitLoad() -> DISPATCHES 1#anchor + 1 +// +void FrameLoaderClientImpl::dispatchDidReceiveServerRedirectForProvisionalLoad() +{ + WebDataSourceImpl* ds = m_webFrame->provisionalDataSourceImpl(); + if (!ds) { + // Got a server redirect when there is no provisional DS! + ASSERT_NOT_REACHED(); + return; + } + + // The server redirect may have been blocked. + if (ds->request().isNull()) + return; + + // A provisional load should have started already, which should have put an + // entry in our redirect chain. + ASSERT(ds->hasRedirectChain()); + + // The URL of the destination is on the provisional data source. We also need + // to update the redirect chain to account for this addition (we do this + // before the callback so the callback can look at the redirect chain to see + // what happened). + ds->appendRedirect(ds->request().url()); + + if (m_webFrame->client()) + m_webFrame->client()->didReceiveServerRedirectForProvisionalLoad(m_webFrame); +} + +// Called on both success and failure of a client redirect. +void FrameLoaderClientImpl::dispatchDidCancelClientRedirect() +{ + // No longer expecting a client redirect. + if (m_webFrame->client()) { + m_expectedClientRedirectSrc = KURL(); + m_expectedClientRedirectDest = KURL(); + m_webFrame->client()->didCancelClientRedirect(m_webFrame); + } + + // No need to clear the redirect chain, since that data source has already + // been deleted by the time this function is called. +} + +void FrameLoaderClientImpl::dispatchWillPerformClientRedirect( + const KURL& url, + double interval, + double fireDate) +{ + // Tells dispatchDidStartProvisionalLoad that if it sees this item it is a + // redirect and the source item should be added as the start of the chain. + m_expectedClientRedirectSrc = m_webFrame->url(); + m_expectedClientRedirectDest = url; + + // FIXME: bug 1135512. Webkit does not properly notify us of cancelling + // http > file client redirects. Since the FrameLoader's policy is to never + // carry out such a navigation anyway, the best thing we can do for now to + // not get confused is ignore this notification. + if (m_expectedClientRedirectDest.isLocalFile() + && m_expectedClientRedirectSrc.protocolInHTTPFamily()) { + m_expectedClientRedirectSrc = KURL(); + m_expectedClientRedirectDest = KURL(); + return; + } + + if (m_webFrame->client()) { + m_webFrame->client()->willPerformClientRedirect( + m_webFrame, + m_expectedClientRedirectSrc, + m_expectedClientRedirectDest, + static_cast<unsigned int>(interval), + static_cast<unsigned int>(fireDate)); + } +} + +void FrameLoaderClientImpl::dispatchDidChangeLocationWithinPage() +{ + // Anchor fragment navigations are not normal loads, so we need to synthesize + // some events for our delegate. + WebViewImpl* webView = m_webFrame->viewImpl(); + if (webView->client()) + webView->client()->didStartLoading(); + + WebDataSourceImpl* ds = m_webFrame->dataSourceImpl(); + ASSERT(ds); // Should not be null when navigating to a reference fragment! + if (ds) { + KURL url = ds->request().url(); + KURL chainEnd; + if (ds->hasRedirectChain()) { + chainEnd = ds->endOfRedirectChain(); + ds->clearRedirectChain(); + } + + // Figure out if this location change is because of a JS-initiated + // client redirect (e.g onload/setTimeout document.location.href=). + // FIXME: (bugs 1085325, 1046841) We don't get proper redirect + // performed/cancelled notifications across anchor navigations, so the + // other redirect-tracking code in this class (see + // dispatch*ClientRedirect() and dispatchDidStartProvisionalLoad) is + // insufficient to catch and properly flag these transitions. Once a + // proper fix for this bug is identified and applied the following + // block may no longer be required. + bool wasClientRedirect = + (url == m_expectedClientRedirectDest && chainEnd == m_expectedClientRedirectSrc) + || !m_webFrame->isProcessingUserGesture(); + + if (wasClientRedirect) { + if (m_webFrame->client()) + m_webFrame->client()->didCompleteClientRedirect(m_webFrame, chainEnd); + ds->appendRedirect(chainEnd); + // Make sure we clear the expected redirect since we just effectively + // completed it. + m_expectedClientRedirectSrc = KURL(); + m_expectedClientRedirectDest = KURL(); + } + + // Regardless of how we got here, we are navigating to a URL so we need to + // add it to the redirect chain. + ds->appendRedirect(url); + } + + bool isNewNavigation; + webView->didCommitLoad(&isNewNavigation); + if (m_webFrame->client()) + m_webFrame->client()->didChangeLocationWithinPage(m_webFrame, isNewNavigation); + + if (webView->client()) + webView->client()->didStopLoading(); +} + +void FrameLoaderClientImpl::dispatchWillClose() +{ + if (m_webFrame->client()) + m_webFrame->client()->willClose(m_webFrame); +} + +void FrameLoaderClientImpl::dispatchDidReceiveIcon() +{ + // The icon database is disabled, so this should never be called. + ASSERT_NOT_REACHED(); +} + +void FrameLoaderClientImpl::dispatchDidStartProvisionalLoad() { + // In case a redirect occurs, we need this to be set so that the redirect + // handling code can tell where the redirect came from. Server redirects + // will occur on the provisional load, so we need to keep track of the most + // recent provisional load URL. + // See dispatchDidReceiveServerRedirectForProvisionalLoad. + WebDataSourceImpl* ds = m_webFrame->provisionalDataSourceImpl(); + if (!ds) { + ASSERT_NOT_REACHED(); + return; + } + KURL url = ds->request().url(); + + // Since the provisional load just started, we should have not gotten + // any redirects yet. + ASSERT(!ds->hasRedirectChain()); + + // If this load is what we expected from a client redirect, treat it as a + // redirect from that original page. The expected redirect urls will be + // cleared by DidCancelClientRedirect. + bool completingClientRedirect = false; + if (m_expectedClientRedirectSrc.isValid()) { + // m_expectedClientRedirectDest could be something like + // "javascript:history.go(-1)" thus we need to exclude url starts with + // "javascript:". See bug: 1080873 + ASSERT(m_expectedClientRedirectDest.protocolIs("javascript") + || m_expectedClientRedirectDest == url); + ds->appendRedirect(m_expectedClientRedirectSrc); + completingClientRedirect = true; + } + ds->appendRedirect(url); + + if (m_webFrame->client()) { + // Whatever information didCompleteClientRedirect contains should only + // be considered relevant until the next provisional load has started. + // So we first tell the client that the load started, and then tell it + // about the client redirect the load is responsible for completing. + m_webFrame->client()->didStartProvisionalLoad(m_webFrame); + if (completingClientRedirect) { + m_webFrame->client()->didCompleteClientRedirect( + m_webFrame, m_expectedClientRedirectSrc); + } + } +} + +void FrameLoaderClientImpl::dispatchDidReceiveTitle(const String& title) +{ + if (m_webFrame->client()) + m_webFrame->client()->didReceiveTitle(m_webFrame, title); +} + +void FrameLoaderClientImpl::dispatchDidCommitLoad() +{ + WebViewImpl* webview = m_webFrame->viewImpl(); + bool isNewNavigation; + webview->didCommitLoad(&isNewNavigation); + + if (m_webFrame->client()) + m_webFrame->client()->didCommitProvisionalLoad(m_webFrame, isNewNavigation); + + WebDevToolsAgentImpl* toolsAgent = webview->devToolsAgentImpl(); + if (toolsAgent) + toolsAgent->DidCommitLoadForFrame(webview, m_webFrame, isNewNavigation); +} + +void FrameLoaderClientImpl::dispatchDidFailProvisionalLoad( + const ResourceError& error) +{ + + // If a policy change occured, then we do not want to inform the plugin + // delegate. See http://b/907789 for details. FIXME: This means the + // plugin won't receive NPP_URLNotify, which seems like it could result in + // a memory leak in the plugin!! + if (error.domain() == internalErrorDomain + && error.errorCode() == PolicyChangeError) { + m_webFrame->didFail(cancelledError(error.failingURL()), true); + return; + } + + OwnPtr<WebPluginLoadObserver> observer = pluginLoadObserver(); + m_webFrame->didFail(error, true); + if (observer) + observer->didFailLoading(error); +} + +void FrameLoaderClientImpl::dispatchDidFailLoad(const ResourceError& error) +{ + OwnPtr<WebPluginLoadObserver> observer = pluginLoadObserver(); + m_webFrame->didFail(error, false); + if (observer) + observer->didFailLoading(error); + + // Don't clear the redirect chain, this will happen in the middle of client + // redirects, and we need the context. The chain will be cleared when the + // provisional load succeeds or fails, not the "real" one. +} + +void FrameLoaderClientImpl::dispatchDidFinishLoad() +{ + OwnPtr<WebPluginLoadObserver> observer = pluginLoadObserver(); + + if (m_webFrame->client()) + m_webFrame->client()->didFinishLoad(m_webFrame); + + if (observer) + observer->didFinishLoading(); + + // Don't clear the redirect chain, this will happen in the middle of client + // redirects, and we need the context. The chain will be cleared when the + // provisional load succeeds or fails, not the "real" one. +} + +void FrameLoaderClientImpl::dispatchDidFirstLayout() +{ +} + +void FrameLoaderClientImpl::dispatchDidFirstVisuallyNonEmptyLayout() +{ + // FIXME: called when webkit finished layout of a page that was visually + // non-empty. + // All resources have not necessarily finished loading. +} + +Frame* FrameLoaderClientImpl::dispatchCreatePage() +{ + struct WindowFeatures features; + Page* newPage = m_webFrame->frame()->page()->chrome()->createWindow( + m_webFrame->frame(), FrameLoadRequest(), features); + + // Make sure that we have a valid disposition. This should have been set in + // the preceeding call to dispatchDecidePolicyForNewWindowAction. + ASSERT(m_nextNavigationPolicy != WebNavigationPolicyIgnore); + WebNavigationPolicy policy = m_nextNavigationPolicy; + m_nextNavigationPolicy = WebNavigationPolicyIgnore; + + // createWindow can return null (e.g., popup blocker denies the window). + if (!newPage) + return 0; + + WebViewImpl::fromPage(newPage)->setInitialNavigationPolicy(policy); + return newPage->mainFrame(); +} + +void FrameLoaderClientImpl::dispatchShow() +{ + WebViewImpl* webView = m_webFrame->viewImpl(); + if (webView && webView->client()) + webView->client()->show(webView->initialNavigationPolicy()); +} + +static bool shouldTreatAsAttachment(const ResourceResponse& response) +{ + const String& contentDisposition = + response.httpHeaderField("Content-Disposition"); + if (contentDisposition.isEmpty()) + return false; + + // Some broken sites just send + // Content-Disposition: ; filename="file" + // screen those out here. + if (contentDisposition.startsWith(";")) + return false; + + if (contentDisposition.startsWith("inline", false)) + return false; + + // Some broken sites just send + // Content-Disposition: filename="file" + // without a disposition token... screen those out. + if (contentDisposition.startsWith("filename", false)) + return false; + + // Also in use is Content-Disposition: name="file" + if (contentDisposition.startsWith("name", false)) + return false; + + // We have a content-disposition of "attachment" or unknown. + // RFC 2183, section 2.8 says that an unknown disposition + // value should be treated as "attachment" + return true; +} + +void FrameLoaderClientImpl::dispatchDecidePolicyForMIMEType( + FramePolicyFunction function, + const String& mimeType, + const ResourceRequest&) +{ + const ResourceResponse& response = + m_webFrame->frame()->loader()->activeDocumentLoader()->response(); + + PolicyAction action; + + int statusCode = response.httpStatusCode(); + if (statusCode == 204 || statusCode == 205) { + // The server does not want us to replace the page contents. + action = PolicyIgnore; + } else if (shouldTreatAsAttachment(response)) { + // The server wants us to download instead of replacing the page contents. + // Downloading is handled by the embedder, but we still get the initial + // response so that we can ignore it and clean up properly. + action = PolicyIgnore; + } else if (!canShowMIMEType(mimeType)) { + // Make sure that we can actually handle this type internally. + action = PolicyIgnore; + } else { + // OK, we will render this page. + action = PolicyUse; + } + + // NOTE: PolicyChangeError will be generated when action is not PolicyUse. + (m_webFrame->frame()->loader()->policyChecker()->*function)(action); +} + +void FrameLoaderClientImpl::dispatchDecidePolicyForNewWindowAction( + FramePolicyFunction function, + const NavigationAction& action, + const ResourceRequest& request, + PassRefPtr<FormState> formState, + const String& frameName) +{ + WebNavigationPolicy navigationPolicy; + if (!actionSpecifiesNavigationPolicy(action, &navigationPolicy)) + navigationPolicy = WebNavigationPolicyNewForegroundTab; + + PolicyAction policyAction; + if (navigationPolicy == WebNavigationPolicyDownload) + policyAction = PolicyDownload; + else { + policyAction = PolicyUse; + + // Remember the disposition for when dispatchCreatePage is called. It is + // unfortunate that WebCore does not provide us with any context when + // creating or showing the new window that would allow us to avoid having + // to keep this state. + m_nextNavigationPolicy = navigationPolicy; + } + (m_webFrame->frame()->loader()->policyChecker()->*function)(policyAction); +} + +void FrameLoaderClientImpl::dispatchDecidePolicyForNavigationAction( + FramePolicyFunction function, + const NavigationAction& action, + const ResourceRequest& request, + PassRefPtr<FormState> formState) { + PolicyAction policyAction = PolicyIgnore; + + // It is valid for this function to be invoked in code paths where the + // the webview is closed. + // The null check here is to fix a crash that seems strange + // (see - https://bugs.webkit.org/show_bug.cgi?id=23554). + if (m_webFrame->client() && !request.url().isNull()) { + WebNavigationPolicy navigationPolicy = WebNavigationPolicyCurrentTab; + actionSpecifiesNavigationPolicy(action, &navigationPolicy); + + // Give the delegate a chance to change the navigation policy. + const WebDataSourceImpl* ds = m_webFrame->provisionalDataSourceImpl(); + if (ds) { + KURL url = ds->request().url(); + if (url.protocolIs(backForwardNavigationScheme)) { + handleBackForwardNavigation(url); + navigationPolicy = WebNavigationPolicyIgnore; + } else { + bool isRedirect = ds->hasRedirectChain(); + + WebNavigationType webnavType = + WebDataSourceImpl::toWebNavigationType(action.type()); + + RefPtr<Node> node; + for (const Event* event = action.event(); event; event = event->underlyingEvent()) { + if (event->isMouseEvent()) { + const MouseEvent* mouseEvent = + static_cast<const MouseEvent*>(event); + node = m_webFrame->frame()->eventHandler()->hitTestResultAtPoint( + mouseEvent->absoluteLocation(), false).innerNonSharedNode(); + break; + } + } + WebNode originatingNode(node); + + navigationPolicy = m_webFrame->client()->decidePolicyForNavigation( + m_webFrame, ds->request(), webnavType, originatingNode, + navigationPolicy, isRedirect); + } + } + + if (navigationPolicy == WebNavigationPolicyCurrentTab) + policyAction = PolicyUse; + else if (navigationPolicy == WebNavigationPolicyDownload) + policyAction = PolicyDownload; + else { + if (navigationPolicy != WebNavigationPolicyIgnore) { + WrappedResourceRequest webreq(request); + m_webFrame->client()->loadURLExternally(m_webFrame, webreq, navigationPolicy); + } + policyAction = PolicyIgnore; + } + } + + (m_webFrame->frame()->loader()->policyChecker()->*function)(policyAction); +} + +void FrameLoaderClientImpl::cancelPolicyCheck() +{ + // FIXME +} + +void FrameLoaderClientImpl::dispatchUnableToImplementPolicy(const ResourceError& error) +{ + m_webFrame->client()->unableToImplementPolicyWithError(m_webFrame, error); +} + +void FrameLoaderClientImpl::dispatchWillSubmitForm(FramePolicyFunction function, + PassRefPtr<FormState> formState) +{ + if (m_webFrame->client()) + m_webFrame->client()->willSubmitForm(m_webFrame, WebForm(formState->form())); + (m_webFrame->frame()->loader()->policyChecker()->*function)(PolicyUse); +} + +void FrameLoaderClientImpl::dispatchDidLoadMainResource(DocumentLoader*) +{ + // FIXME +} + +void FrameLoaderClientImpl::revertToProvisionalState(DocumentLoader*) +{ + m_hasRepresentation = true; +} + +void FrameLoaderClientImpl::setMainDocumentError(DocumentLoader*, + const ResourceError& error) +{ + if (m_pluginWidget.get()) { + if (m_sentInitialResponseToPlugin) { + m_pluginWidget->didFailLoading(error); + m_sentInitialResponseToPlugin = false; + } + m_pluginWidget = 0; + } +} + +void FrameLoaderClientImpl::postProgressStartedNotification() +{ + WebViewImpl* webview = m_webFrame->viewImpl(); + if (webview && webview->client()) + webview->client()->didStartLoading(); +} + +void FrameLoaderClientImpl::postProgressEstimateChangedNotification() +{ + // FIXME +} + +void FrameLoaderClientImpl::postProgressFinishedNotification() +{ + // FIXME: why might the webview be null? http://b/1234461 + WebViewImpl* webview = m_webFrame->viewImpl(); + if (webview && webview->client()) + webview->client()->didStopLoading(); +} + +void FrameLoaderClientImpl::setMainFrameDocumentReady(bool ready) +{ + // FIXME +} + +// Creates a new connection and begins downloading from that (contrast this +// with |download|). +void FrameLoaderClientImpl::startDownload(const ResourceRequest& request) +{ + if (m_webFrame->client()) { + WrappedResourceRequest webreq(request); + m_webFrame->client()->loadURLExternally( + m_webFrame, webreq, WebNavigationPolicyDownload); + } +} + +void FrameLoaderClientImpl::willChangeTitle(DocumentLoader*) +{ + // FIXME +} + +void FrameLoaderClientImpl::didChangeTitle(DocumentLoader*) +{ + // FIXME +} + +// Called whenever data is received. +void FrameLoaderClientImpl::committedLoad(DocumentLoader* loader, const char* data, int length) { + if (!m_pluginWidget.get()) { + if (m_webFrame->client()) { + bool preventDefault = false; + m_webFrame->client()->didReceiveDocumentData(m_webFrame, data, length, preventDefault); + if (!preventDefault) + m_webFrame->commitDocumentData(data, length); + } + } + + // If we are sending data to MediaDocument, we should stop here + // and cancel the request. + if (m_webFrame->frame()->document() + && m_webFrame->frame()->document()->isMediaDocument()) + loader->cancelMainResourceLoad(pluginWillHandleLoadError(loader->response())); + + // The plugin widget could have been created in the m_webFrame->DidReceiveData + // function. + if (m_pluginWidget.get()) { + if (!m_sentInitialResponseToPlugin) { + m_sentInitialResponseToPlugin = true; + m_pluginWidget->didReceiveResponse( + m_webFrame->frame()->loader()->activeDocumentLoader()->response()); + } + m_pluginWidget->didReceiveData(data, length); + } +} + +void FrameLoaderClientImpl::finishedLoading(DocumentLoader* dl) +{ + if (m_pluginWidget.get()) { + m_pluginWidget->didFinishLoading(); + m_pluginWidget = 0; + m_sentInitialResponseToPlugin = false; + } else { + // This is necessary to create an empty document. See bug 634004. + // However, we only want to do this if makeRepresentation has been called, to + // match the behavior on the Mac. + if (m_hasRepresentation) + dl->frameLoader()->setEncoding("", false); + } +} + +void FrameLoaderClientImpl::updateGlobalHistory() +{ +} + +void FrameLoaderClientImpl::updateGlobalHistoryRedirectLinks() +{ +} + +bool FrameLoaderClientImpl::shouldGoToHistoryItem(HistoryItem*) const +{ + // FIXME + return true; +} + +void FrameLoaderClientImpl::didDisplayInsecureContent() +{ + if (m_webFrame->client()) + m_webFrame->client()->didDisplayInsecureContent(m_webFrame); +} + +void FrameLoaderClientImpl::didRunInsecureContent(SecurityOrigin* origin) +{ + if (m_webFrame->client()) + m_webFrame->client()->didRunInsecureContent(m_webFrame, WebSecurityOrigin(origin)); +} + +ResourceError FrameLoaderClientImpl::blockedError(const ResourceRequest&) +{ + // FIXME + return ResourceError(); +} + +ResourceError FrameLoaderClientImpl::cancelledError(const ResourceRequest& request) +{ + if (!m_webFrame->client()) + return ResourceError(); + + return m_webFrame->client()->cancelledError( + m_webFrame, WrappedResourceRequest(request)); +} + +ResourceError FrameLoaderClientImpl::cannotShowURLError(const ResourceRequest& request) +{ + if (!m_webFrame->client()) + return ResourceError(); + + return m_webFrame->client()->cannotHandleRequestError( + m_webFrame, WrappedResourceRequest(request)); +} + +ResourceError FrameLoaderClientImpl::interruptForPolicyChangeError( + const ResourceRequest& request) +{ + return ResourceError(internalErrorDomain, PolicyChangeError, + request.url().string(), String()); +} + +ResourceError FrameLoaderClientImpl::cannotShowMIMETypeError(const ResourceResponse&) +{ + // FIXME + return ResourceError(); +} + +ResourceError FrameLoaderClientImpl::fileDoesNotExistError(const ResourceResponse&) +{ + // FIXME + return ResourceError(); +} + +ResourceError FrameLoaderClientImpl::pluginWillHandleLoadError(const ResourceResponse&) +{ + // FIXME + return ResourceError(); +} + +bool FrameLoaderClientImpl::shouldFallBack(const ResourceError& error) +{ + // This method is called when we fail to load the URL for an <object> tag + // that has fallback content (child elements) and is being loaded as a frame. + // The error parameter indicates the reason for the load failure. + // We should let the fallback content load only if this wasn't a cancelled + // request. + // Note: The mac version also has a case for "WebKitErrorPluginWillHandleLoad" + ResourceError c = cancelledError(ResourceRequest()); + return error.errorCode() != c.errorCode() || error.domain() != c.domain(); +} + +bool FrameLoaderClientImpl::canHandleRequest(const ResourceRequest& request) const +{ + return m_webFrame->client()->canHandleRequest( + m_webFrame, WrappedResourceRequest(request)); +} + +bool FrameLoaderClientImpl::canShowMIMEType(const String& mimeType) const +{ + // This method is called to determine if the media type can be shown + // "internally" (i.e. inside the browser) regardless of whether or not the + // browser or a plugin is doing the rendering. + + // mimeType strings are supposed to be ASCII, but if they are not for some + // reason, then it just means that the mime type will fail all of these "is + // supported" checks and go down the path of an unhandled mime type. + if (net::IsSupportedMimeType(mimeType.latin1().data())) + return true; + + // If Chrome is started with the --disable-plugins switch, pluginData is null. + PluginData* pluginData = m_webFrame->frame()->page()->pluginData(); + + // See if the type is handled by an installed plugin, if so, we can show it. + // FIXME: (http://b/1085524) This is the place to stick a preference to + // disable full page plugins (optionally for certain types!) + return !mimeType.isEmpty() && pluginData && pluginData->supportsMimeType(mimeType); +} + +bool FrameLoaderClientImpl::representationExistsForURLScheme(const String&) const +{ + // FIXME + return false; +} + +String FrameLoaderClientImpl::generatedMIMETypeForURLScheme(const String& scheme) const +{ + // This appears to generate MIME types for protocol handlers that are handled + // internally. The only place I can find in the WebKit code that uses this + // function is WebView::registerViewClass, where it is used as part of the + // process by which custom view classes for certain document representations + // are registered. + String mimeType("x-apple-web-kit/"); + mimeType.append(scheme.lower()); + return mimeType; +} + +void FrameLoaderClientImpl::frameLoadCompleted() +{ + // FIXME: the mac port also conditionally calls setDrawsBackground:YES on + // it's ScrollView here. + + // This comment from the Mac port: + // Note: Can be called multiple times. + // Even if already complete, we might have set a previous item on a frame that + // didn't do any data loading on the past transaction. Make sure to clear these out. + + // FIXME: setPreviousHistoryItem() no longer exists. http://crbug.com/8566 + // m_webFrame->frame()->loader()->setPreviousHistoryItem(0); +} + +void FrameLoaderClientImpl::saveViewStateToItem(HistoryItem*) +{ + // FIXME +} + +void FrameLoaderClientImpl::restoreViewState() +{ + // FIXME: probably scrolls to last position when you go back or forward +} + +void FrameLoaderClientImpl::provisionalLoadStarted() +{ + // FIXME: On mac, this does various caching stuff +} + +void FrameLoaderClientImpl::didFinishLoad() +{ + OwnPtr<WebPluginLoadObserver> observer = pluginLoadObserver(); + if (observer) + observer->didFinishLoading(); +} + +void FrameLoaderClientImpl::prepareForDataSourceReplacement() +{ + // FIXME +} + +PassRefPtr<DocumentLoader> FrameLoaderClientImpl::createDocumentLoader( + const ResourceRequest& request, + const SubstituteData& data) +{ + RefPtr<WebDataSourceImpl> ds = WebDataSourceImpl::create(request, data); + if (m_webFrame->client()) + m_webFrame->client()->didCreateDataSource(m_webFrame, ds.get()); + return ds.release(); +} + +void FrameLoaderClientImpl::setTitle(const String& title, const KURL& url) +{ + // FIXME: inform consumer of changes to the title. +} + +String FrameLoaderClientImpl::userAgent(const KURL& url) +{ + // FIXME: Convert this to a WebKitClient callback. + return webkit_glue::StdStringToString( + webkit_glue::GetUserAgent(webkit_glue::KURLToGURL(url))); +} + +void FrameLoaderClientImpl::savePlatformDataToCachedFrame(CachedFrame*) +{ + // The page cache should be disabled. + ASSERT_NOT_REACHED(); +} + +void FrameLoaderClientImpl::transitionToCommittedFromCachedFrame(CachedFrame*) +{ + ASSERT_NOT_REACHED(); +} + +// Called when the FrameLoader goes into a state in which a new page load +// will occur. +void FrameLoaderClientImpl::transitionToCommittedForNewPage() +{ + makeDocumentView(); +} + +bool FrameLoaderClientImpl::canCachePage() const +{ + // Since we manage the cache, always report this page as non-cacheable to + // FrameLoader. + return false; +} + +// Downloading is handled in the browser process, not WebKit. If we get to this +// point, our download detection code in the ResourceDispatcherHost is broken! +void FrameLoaderClientImpl::download(ResourceHandle* handle, + const ResourceRequest& request, + const ResourceRequest& initialRequest, + const ResourceResponse& response) +{ + ASSERT_NOT_REACHED(); +} + +PassRefPtr<Frame> FrameLoaderClientImpl::createFrame( + const KURL& url, + const String& name, + HTMLFrameOwnerElement* ownerElement, + const String& referrer, + bool allowsScrolling, + int marginWidth, + int marginHeight) +{ + FrameLoadRequest frameRequest(ResourceRequest(url, referrer), name); + return m_webFrame->createChildFrame(frameRequest, ownerElement); +} + +PassRefPtr<Widget> FrameLoaderClientImpl::createPlugin( + const IntSize& size, // FIXME: how do we use this? + HTMLPlugInElement* element, + const KURL& url, + const Vector<String>& paramNames, + const Vector<String>& paramValues, + const String& mimeType, + bool loadManually) +{ +#if !PLATFORM(WIN_OS) + // WebCore asks us to make a plugin even if we don't have a + // registered handler, with a comment saying it's so we can display + // the broken plugin icon. In Chromium, we normally register a + // fallback plugin handler that allows you to install a missing + // plugin. Since we don't yet have a default plugin handler, we + // need to return null here rather than going through all the + // plugin-creation IPCs only to discover we don't have a plugin + // registered, which causes a crash. + // FIXME: remove me once we have a default plugin. + if (objectContentType(url, mimeType) != ObjectContentNetscapePlugin) + return 0; +#endif + + if (!m_webFrame->client()) + return 0; + + WebPluginParams params; + params.url = url; + params.mimeType = mimeType; + params.attributeNames = paramNames; + params.attributeValues = paramValues; + params.loadManually = loadManually; + + WebPlugin* webPlugin = m_webFrame->client()->createPlugin(m_webFrame, params); + if (!webPlugin) + return 0; + + // The container takes ownership of the WebPlugin. + RefPtr<WebPluginContainerImpl> container = + WebPluginContainerImpl::create(element, webPlugin); + + if (!webPlugin->initialize(container.get())) + return 0; + + // The element might have been removed during plugin initialization! + if (!element->renderer()) + return 0; + + return container; +} + +// This method gets called when a plugin is put in place of html content +// (e.g., acrobat reader). +void FrameLoaderClientImpl::redirectDataToPlugin(Widget* pluginWidget) { + m_pluginWidget = static_cast<WebPluginContainerImpl*>(pluginWidget); + ASSERT(m_pluginWidget.get()); +} + +PassRefPtr<Widget> FrameLoaderClientImpl::createJavaAppletWidget( + const IntSize& size, + HTMLAppletElement* element, + const KURL& /* baseURL */, + const Vector<String>& paramNames, + const Vector<String>& paramValues) +{ + return createPlugin(size, element, KURL(), paramNames, paramValues, + "application/x-java-applet", false); +} + +ObjectContentType FrameLoaderClientImpl::objectContentType( + const KURL& url, + const String& explicitMimeType) +{ + // This code is based on Apple's implementation from + // WebCoreSupport/WebFrameBridge.mm. + + String mimeType = explicitMimeType; + if (mimeType.isEmpty()) { + // Try to guess the MIME type based off the extension. + String filename = url.lastPathComponent(); + int extensionPos = filename.reverseFind('.'); + if (extensionPos >= 0) + mimeType = MIMETypeRegistry::getMIMETypeForPath(url.path()); + + if (mimeType.isEmpty()) + return ObjectContentFrame; + } + + if (MIMETypeRegistry::isSupportedImageMIMEType(mimeType)) + return ObjectContentImage; + + // If Chrome is started with the --disable-plugins switch, pluginData is 0. + PluginData* pluginData = m_webFrame->frame()->page()->pluginData(); + if (pluginData && pluginData->supportsMimeType(mimeType)) + return ObjectContentNetscapePlugin; + + if (MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType)) + return ObjectContentFrame; + + return ObjectContentNone; +} + +String FrameLoaderClientImpl::overrideMediaType() const +{ + // FIXME + return String(); +} + +bool FrameLoaderClientImpl::actionSpecifiesNavigationPolicy( + const NavigationAction& action, + WebNavigationPolicy* policy) +{ + if ((action.type() != NavigationTypeLinkClicked) || !action.event()->isMouseEvent()) + return false; + + const MouseEvent* event = static_cast<const MouseEvent*>(action.event()); + return WebViewImpl::navigationPolicyFromMouseEvent( + event->button(), event->ctrlKey(), event->shiftKey(), event->altKey(), + event->metaKey(), policy); +} + +void FrameLoaderClientImpl::handleBackForwardNavigation(const KURL& url) +{ + ASSERT(url.protocolIs(backForwardNavigationScheme)); + + bool ok; + int offset = url.lastPathComponent().toIntStrict(&ok); + if (!ok) + return; + + WebViewImpl* webview = m_webFrame->viewImpl(); + if (webview->client()) + webview->client()->navigateBackForwardSoon(offset); +} + +PassOwnPtr<WebPluginLoadObserver> FrameLoaderClientImpl::pluginLoadObserver() +{ + WebDataSourceImpl* ds = WebDataSourceImpl::fromDocumentLoader( + m_webFrame->frame()->loader()->activeDocumentLoader()); + return ds->releasePluginLoadObserver(); +} + +} // namespace WebKit diff --git a/webkit/api/src/FrameLoaderClientImpl.h b/webkit/api/src/FrameLoaderClientImpl.h new file mode 100644 index 0000000..a3e7f18 --- /dev/null +++ b/webkit/api/src/FrameLoaderClientImpl.h @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FrameLoaderClientImpl_h +#define FrameLoaderClientImpl_h + +#include "FrameLoaderClient.h" +#include "KURL.h" +// FIXME: remove this relative path once consumers from glue are removed. +#include "../public/WebNavigationPolicy.h" +#include <wtf/PassOwnPtr.h> +#include <wtf/RefPtr.h> + +namespace WebKit { +class WebFrameImpl; +class WebPluginContainerImpl; +class WebPluginLoadObserver; + +class FrameLoaderClientImpl : public WebCore::FrameLoaderClient { +public: + FrameLoaderClientImpl(WebFrameImpl* webFrame); + ~FrameLoaderClientImpl(); + + WebFrameImpl* webFrame() const { return m_webFrame; } + + // WebCore::FrameLoaderClient ---------------------------------------------- + + virtual void frameLoaderDestroyed(); + + // Notifies the WebView delegate that the JS window object has been cleared, + // giving it a chance to bind native objects to the window before script + // parsing begins. + virtual void windowObjectCleared(); + virtual void documentElementAvailable(); + + // A frame's V8 context was created or destroyed. + virtual void didCreateScriptContextForFrame(); + virtual void didDestroyScriptContextForFrame(); + + // A context untied to a frame was created (through evaluateInNewContext). + // This context is not tied to the lifetime of its frame, and is destroyed + // in garbage collection. + virtual void didCreateIsolatedScriptContext(); + + virtual bool hasWebView() const; + virtual bool hasFrameView() const; + virtual void makeRepresentation(WebCore::DocumentLoader*); + virtual void forceLayout(); + virtual void forceLayoutForNonHTML(); + virtual void setCopiesOnScroll(); + virtual void detachedFromParent2(); + virtual void detachedFromParent3(); + virtual void assignIdentifierToInitialRequest(unsigned long identifier, WebCore::DocumentLoader*, const WebCore::ResourceRequest&); + virtual void dispatchWillSendRequest(WebCore::DocumentLoader*, unsigned long identifier, WebCore::ResourceRequest&, const WebCore::ResourceResponse& redirectResponse); + virtual bool shouldUseCredentialStorage(WebCore::DocumentLoader*, unsigned long identifier); + virtual void dispatchDidReceiveAuthenticationChallenge(WebCore::DocumentLoader*, unsigned long identifier, const WebCore::AuthenticationChallenge&); + virtual void dispatchDidCancelAuthenticationChallenge(WebCore::DocumentLoader*, unsigned long identifier, const WebCore::AuthenticationChallenge&); + virtual void dispatchDidReceiveResponse(WebCore::DocumentLoader*, unsigned long identifier, const WebCore::ResourceResponse&); + virtual void dispatchDidReceiveContentLength(WebCore::DocumentLoader*, unsigned long identifier, int lengthReceived); + virtual void dispatchDidFinishLoading(WebCore::DocumentLoader*, unsigned long identifier); + virtual void dispatchDidFailLoading(WebCore::DocumentLoader*, unsigned long identifier, const WebCore::ResourceError&); + virtual bool dispatchDidLoadResourceFromMemoryCache(WebCore::DocumentLoader*, const WebCore::ResourceRequest&, const WebCore::ResourceResponse&, int length); + virtual void dispatchDidLoadResourceByXMLHttpRequest(unsigned long identifier, const WebCore::ScriptString&); + virtual void dispatchDidHandleOnloadEvents(); + virtual void dispatchDidReceiveServerRedirectForProvisionalLoad(); + virtual void dispatchDidCancelClientRedirect(); + virtual void dispatchWillPerformClientRedirect(const WebCore::KURL&, double interval, double fireDate); + virtual void dispatchDidChangeLocationWithinPage(); + virtual void dispatchWillClose(); + virtual void dispatchDidReceiveIcon(); + virtual void dispatchDidStartProvisionalLoad(); + virtual void dispatchDidReceiveTitle(const WebCore::String& title); + virtual void dispatchDidCommitLoad(); + virtual void dispatchDidFailProvisionalLoad(const WebCore::ResourceError&); + virtual void dispatchDidFailLoad(const WebCore::ResourceError&); + virtual void dispatchDidFinishDocumentLoad(); + virtual void dispatchDidFinishLoad(); + virtual void dispatchDidFirstLayout(); + virtual void dispatchDidFirstVisuallyNonEmptyLayout(); + virtual WebCore::Frame* dispatchCreatePage(); + virtual void dispatchShow(); + virtual void dispatchDecidePolicyForMIMEType(WebCore::FramePolicyFunction function, const WebCore::String& mime_type, const WebCore::ResourceRequest&); + virtual void dispatchDecidePolicyForNewWindowAction(WebCore::FramePolicyFunction function, const WebCore::NavigationAction& action, const WebCore::ResourceRequest& request, PassRefPtr<WebCore::FormState> form_state, const WebCore::String& frame_name); + virtual void dispatchDecidePolicyForNavigationAction(WebCore::FramePolicyFunction function, const WebCore::NavigationAction& action, const WebCore::ResourceRequest& request, PassRefPtr<WebCore::FormState> form_state); + virtual void cancelPolicyCheck(); + virtual void dispatchUnableToImplementPolicy(const WebCore::ResourceError&); + virtual void dispatchWillSubmitForm(WebCore::FramePolicyFunction, PassRefPtr<WebCore::FormState>); + virtual void dispatchDidLoadMainResource(WebCore::DocumentLoader*); + virtual void revertToProvisionalState(WebCore::DocumentLoader*); + virtual void setMainDocumentError(WebCore::DocumentLoader*, const WebCore::ResourceError&); + virtual void willChangeEstimatedProgress() { } + virtual void didChangeEstimatedProgress() { } + virtual void postProgressStartedNotification(); + virtual void postProgressEstimateChangedNotification(); + virtual void postProgressFinishedNotification(); + virtual void setMainFrameDocumentReady(bool); + virtual void startDownload(const WebCore::ResourceRequest&); + virtual void willChangeTitle(WebCore::DocumentLoader*); + virtual void didChangeTitle(WebCore::DocumentLoader*); + virtual void committedLoad(WebCore::DocumentLoader*, const char*, int); + virtual void finishedLoading(WebCore::DocumentLoader*); + virtual void updateGlobalHistory(); + virtual void updateGlobalHistoryRedirectLinks(); + virtual bool shouldGoToHistoryItem(WebCore::HistoryItem*) const; + virtual void didDisplayInsecureContent(); + virtual void didRunInsecureContent(WebCore::SecurityOrigin*); + virtual WebCore::ResourceError blockedError(const WebCore::ResourceRequest&); + virtual WebCore::ResourceError cancelledError(const WebCore::ResourceRequest&); + virtual WebCore::ResourceError cannotShowURLError(const WebCore::ResourceRequest&); + virtual WebCore::ResourceError interruptForPolicyChangeError(const WebCore::ResourceRequest&); + virtual WebCore::ResourceError cannotShowMIMETypeError(const WebCore::ResourceResponse&); + virtual WebCore::ResourceError fileDoesNotExistError(const WebCore::ResourceResponse&); + virtual WebCore::ResourceError pluginWillHandleLoadError(const WebCore::ResourceResponse&); + virtual bool shouldFallBack(const WebCore::ResourceError&); + virtual bool canHandleRequest(const WebCore::ResourceRequest&) const; + virtual bool canShowMIMEType(const WebCore::String& MIMEType) const; + virtual bool representationExistsForURLScheme(const WebCore::String& URLScheme) const; + virtual WebCore::String generatedMIMETypeForURLScheme(const WebCore::String& URLScheme) const; + virtual void frameLoadCompleted(); + virtual void saveViewStateToItem(WebCore::HistoryItem*); + virtual void restoreViewState(); + virtual void provisionalLoadStarted(); + virtual void didFinishLoad(); + virtual void prepareForDataSourceReplacement(); + virtual PassRefPtr<WebCore::DocumentLoader> createDocumentLoader( + const WebCore::ResourceRequest&, const WebCore::SubstituteData&); + virtual void setTitle(const WebCore::String& title, const WebCore::KURL&); + virtual WebCore::String userAgent(const WebCore::KURL&); + virtual void savePlatformDataToCachedFrame(WebCore::CachedFrame*); + virtual void transitionToCommittedFromCachedFrame(WebCore::CachedFrame*); + virtual void transitionToCommittedForNewPage(); + virtual bool canCachePage() const; + virtual void download( + WebCore::ResourceHandle*, const WebCore::ResourceRequest&, + const WebCore::ResourceRequest& initialRequest, + const WebCore::ResourceResponse&); + virtual PassRefPtr<WebCore::Frame> createFrame( + const WebCore::KURL& url, const WebCore::String& name, + WebCore::HTMLFrameOwnerElement* ownerElement, + const WebCore::String& referrer, bool allowsScrolling, + int marginWidth, int marginHeight); + virtual PassRefPtr<WebCore::Widget> createPlugin( + const WebCore::IntSize&, WebCore::HTMLPlugInElement*, const WebCore::KURL&, + const Vector<WebCore::String>&, const Vector<WebCore::String>&, + const WebCore::String&, bool loadManually); + virtual void redirectDataToPlugin(WebCore::Widget* pluginWidget); + virtual PassRefPtr<WebCore::Widget> createJavaAppletWidget( + const WebCore::IntSize&, + WebCore::HTMLAppletElement*, + const WebCore::KURL& /* base_url */, + const Vector<WebCore::String>& paramNames, + const Vector<WebCore::String>& paramValues); + virtual WebCore::ObjectContentType objectContentType( + const WebCore::KURL& url, const WebCore::String& mimeType); + virtual WebCore::String overrideMediaType() const; + virtual void didPerformFirstNavigation() const; + virtual void registerForIconNotification(bool listen = true); + +private: + void makeDocumentView(); + + // Given a NavigationAction, determine the associated WebNavigationPolicy. + // For example, a middle click means "open in background tab". + static bool actionSpecifiesNavigationPolicy( + const WebCore::NavigationAction& action, WebNavigationPolicy* policy); + + // Called when a dummy back-forward navigation is intercepted. + void handleBackForwardNavigation(const WebCore::KURL&); + + PassOwnPtr<WebPluginLoadObserver> pluginLoadObserver(); + + // The WebFrame that owns this object and manages its lifetime. Therefore, + // the web frame object is guaranteed to exist. + WebFrameImpl* m_webFrame; + + // True if makeRepresentation was called. We don't actually have a concept + // of a "representation", but we need to know when we're expected to have one. + // See finishedLoading(). + bool m_hasRepresentation; + + // Used to help track client redirects. When a provisional load starts, it + // has no redirects in its chain. But in the case of client redirects, we want + // to add that initial load as a redirect. When we get a new provisional load + // and the dest URL matches that load, we know that it was the result of a + // previous client redirect and the source should be added as a redirect. + // Both should be empty if unused. + WebCore::KURL m_expectedClientRedirectSrc; + WebCore::KURL m_expectedClientRedirectDest; + + // Contains a pointer to the plugin widget. + RefPtr<WebPluginContainerImpl> m_pluginWidget; + + // Indicates if we need to send over the initial notification to the plugin + // which specifies that the plugin should be ready to accept data. + bool m_sentInitialResponseToPlugin; + + // The navigation policy to use for the next call to dispatchCreatePage. + WebNavigationPolicy m_nextNavigationPolicy; +}; + +} // namespace WebKit + +#endif diff --git a/webkit/api/src/InspectorClientImpl.cpp b/webkit/api/src/InspectorClientImpl.cpp index 2dd3b7c..9a1cd3f 100644 --- a/webkit/api/src/InspectorClientImpl.cpp +++ b/webkit/api/src/InspectorClientImpl.cpp @@ -40,11 +40,11 @@ #include "WebURL.h" #include "WebURLRequest.h" #include "WebViewClient.h" +#include "WebViewImpl.h" #include <wtf/Vector.h> // FIXME: Remove this once WebDevToolsAgentImpl and WebViewImpl move out of glue/. #include "webkit/glue/webdevtoolsagent_impl.h" -#include "webkit/glue/webview_impl.h" using namespace WebCore; @@ -75,7 +75,7 @@ Page* InspectorClientImpl::createPage() void InspectorClientImpl::showWindow() { - ASSERT(m_inspectedWebView->GetWebDevToolsAgentImpl()); + ASSERT(m_inspectedWebView->devToolsAgentImpl()); m_inspectedWebView->page()->inspectorController()->setWindowVisible(true); } @@ -87,7 +87,7 @@ void InspectorClientImpl::closeWindow() bool InspectorClientImpl::windowVisible() { - ASSERT(m_inspectedWebView->GetWebDevToolsAgentImpl()); + ASSERT(m_inspectedWebView->devToolsAgentImpl()); return false; } diff --git a/webkit/api/src/InspectorClientImpl.h b/webkit/api/src/InspectorClientImpl.h index aaeff93..62216b2 100644 --- a/webkit/api/src/InspectorClientImpl.h +++ b/webkit/api/src/InspectorClientImpl.h @@ -35,9 +35,8 @@ #include "InspectorController.h" #include <wtf/OwnPtr.h> -class WebViewImpl; - namespace WebKit { +class WebViewImpl; class InspectorClientImpl : public WebCore::InspectorClient { public: diff --git a/webkit/api/src/WebFrameImpl.cpp b/webkit/api/src/WebFrameImpl.cpp new file mode 100644 index 0000000..617cfd5 --- /dev/null +++ b/webkit/api/src/WebFrameImpl.cpp @@ -0,0 +1,1890 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// How ownership works +// ------------------- +// +// Big oh represents a refcounted relationship: owner O--- ownee +// +// WebView (for the toplevel frame only) +// O +// | +// Page O------- Frame (m_mainFrame) O-------O FrameView +// || +// || +// FrameLoader O-------- WebFrame (via FrameLoaderClient) +// +// FrameLoader and Frame are formerly one object that was split apart because +// it got too big. They basically have the same lifetime, hence the double line. +// +// WebFrame is refcounted and has one ref on behalf of the FrameLoader/Frame. +// This is not a normal reference counted pointer because that would require +// changing WebKit code that we don't control. Instead, it is created with this +// ref initially and it is removed when the FrameLoader is getting destroyed. +// +// WebFrames are created in two places, first in WebViewImpl when the root +// frame is created, and second in WebFrame::CreateChildFrame when sub-frames +// are created. WebKit will hook up this object to the FrameLoader/Frame +// and the refcount will be correct. +// +// How frames are destroyed +// ------------------------ +// +// The main frame is never destroyed and is re-used. The FrameLoader is re-used +// and a reference to the main frame is kept by the Page. +// +// When frame content is replaced, all subframes are destroyed. This happens +// in FrameLoader::detachFromParent for each subframe. +// +// Frame going away causes the FrameLoader to get deleted. In FrameLoader's +// destructor, it notifies its client with frameLoaderDestroyed. This calls +// WebFrame::Closing and then derefs the WebFrame and will cause it to be +// deleted (unless an external someone is also holding a reference). + +#include "config.h" +#include "WebFrameImpl.h" + +#include <algorithm> + +#include "Chrome.h" +#include "ChromiumBridge.h" +#include "ClipboardUtilitiesChromium.h" +#include "Console.h" +#include "Document.h" +#include "DocumentFragment.h" // Only needed for ReplaceSelectionCommand.h :( +#include "DocumentLoader.h" +#include "DocumentMarker.h" +#include "DOMWindow.h" +#include "DOMUtilitiesPrivate.h" +#include "Editor.h" +#include "EventHandler.h" +#include "FormState.h" +#include "FrameChromium.h" +#include "FrameLoader.h" +#include "FrameLoadRequest.h" +#include "FrameTree.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "HTMLCollection.h" +#include "HTMLHeadElement.h" +#include "HTMLInputElement.h" +#include "HTMLFormElement.h" +#include "HTMLFrameOwnerElement.h" +#include "HTMLLinkElement.h" +#include "HTMLNames.h" +#include "HistoryItem.h" +#include "InspectorController.h" +#include "markup.h" +#include "Page.h" +#include "PasswordAutocompleteListener.h" +#include "PlatformContextSkia.h" +#include "PrintContext.h" +#include "RenderFrame.h" +#include "RenderView.h" +#include "RenderWidget.h" +#include "ReplaceSelectionCommand.h" +#include "ResourceHandle.h" +#include "ResourceRequest.h" +#include "ScriptController.h" +#include "ScriptSourceCode.h" +#include "ScriptValue.h" +#include "ScrollbarTheme.h" +#include "ScrollTypes.h" +#include "SelectionController.h" +#include "Settings.h" +#include "SkiaUtils.h" +#include "SubstituteData.h" +#include "TextIterator.h" +#include "TextAffinity.h" +#include "XPathResult.h" +#include "WebConsoleMessage.h" +#include "WebDataSourceImpl.h" +#include "WebFindOptions.h" +#include "WebForm.h" +#include "WebFrameClient.h" +#include "WebHistoryItem.h" +#include "WebRange.h" +#include "WebRect.h" +#include "WebScriptSource.h" +#include "WebSecurityOrigin.h" +#include "WebSize.h" +#include "WebURLError.h" +#include "WebVector.h" +#include "WebViewImpl.h" +#include <wtf/CurrentTime.h> + +#if PLATFORM(DARWIN) +#include "LocalCurrentGraphicsContext.h" +#endif + +#if PLATFORM(LINUX) +#include <gdk/gdk.h> +#endif + +using namespace WebCore; + +namespace WebKit { + +// Key for a StatsCounter tracking how many WebFrames are active. +static const char* const webFrameActiveCount = "WebFrameActiveCount"; + +static const char* const osdType = "application/opensearchdescription+xml"; +static const char* const osdRel = "search"; + +// Backend for contentAsPlainText, this is a recursive function that gets +// the text for the current frame and all of its subframes. It will append +// the text of each frame in turn to the |output| up to |maxChars| length. +// +// The |frame| must be non-null. +static void frameContentAsPlainText(size_t maxChars, Frame* frame, + Vector<UChar>* output) +{ + Document* doc = frame->document(); + if (!doc) + return; + + if (!frame->view()) + return; + + // TextIterator iterates over the visual representation of the DOM. As such, + // it requires you to do a layout before using it (otherwise it'll crash). + if (frame->view()->needsLayout()) + frame->view()->layout(); + + // Select the document body. + RefPtr<Range> range(doc->createRange()); + ExceptionCode exception = 0; + range->selectNodeContents(doc->body(), exception); + + if (exception == 0) { + // The text iterator will walk nodes giving us text. This is similar to + // the plainText() function in TextIterator.h, but we implement the maximum + // size and also copy the results directly into a wstring, avoiding the + // string conversion. + for (TextIterator it(range.get()); !it.atEnd(); it.advance()) { + const UChar* chars = it.characters(); + if (!chars) { + if (it.length() != 0) { + // It appears from crash reports that an iterator can get into a state + // where the character count is nonempty but the character pointer is + // null. advance()ing it will then just add that many to the null + // pointer which won't be caught in a null check but will crash. + // + // A null pointer and 0 length is common for some nodes. + // + // IF YOU CATCH THIS IN A DEBUGGER please let brettw know. We don't + // currently understand the conditions for this to occur. Ideally, the + // iterators would never get into the condition so we should fix them + // if we can. + ASSERT_NOT_REACHED(); + break; + } + + // Just got a null node, we can forge ahead! + continue; + } + size_t toAppend = + std::min(static_cast<size_t>(it.length()), maxChars - output->size()); + output->append(chars, toAppend); + if (output->size() >= maxChars) + return; // Filled up the buffer. + } + } + + // The separator between frames when the frames are converted to plain text. + const UChar frameSeparator[] = { '\n', '\n' }; + const size_t frameSeparatorLen = 2; + + // Recursively walk the children. + FrameTree* frameTree = frame->tree(); + for (Frame* curChild = frameTree->firstChild(); curChild; curChild = curChild->tree()->nextSibling()) { + // Make sure the frame separator won't fill up the buffer, and give up if + // it will. The danger is if the separator will make the buffer longer than + // maxChars. This will cause the computation above: + // maxChars - output->size() + // to be a negative number which will crash when the subframe is added. + if (output->size() >= maxChars - frameSeparatorLen) + return; + + output->append(frameSeparator, frameSeparatorLen); + frameContentAsPlainText(maxChars, curChild, output); + if (output->size() >= maxChars) + return; // Filled up the buffer. + } +} + +// Simple class to override some of PrintContext behavior. +class ChromePrintContext : public PrintContext, public Noncopyable { +public: + ChromePrintContext(Frame* frame) + : PrintContext(frame) + , m_printedPageWidth(0) + { + } + + void begin(float width) + { + ASSERT(!m_printedPageWidth); + m_printedPageWidth = width; + PrintContext::begin(m_printedPageWidth); + } + + float getPageShrink(int pageNumber) const + { + IntRect pageRect = m_pageRects[pageNumber]; + return m_printedPageWidth / pageRect.width(); + } + + // Spools the printed page, a subrect of m_frame. Skip the scale step. + // NativeTheme doesn't play well with scaling. Scaling is done browser side + // instead. Returns the scale to be applied. + float spoolPage(GraphicsContext& ctx, int pageNumber) + { + IntRect pageRect = m_pageRects[pageNumber]; + float scale = m_printedPageWidth / pageRect.width(); + + ctx.save(); + ctx.translate(static_cast<float>(-pageRect.x()), + static_cast<float>(-pageRect.y())); + ctx.clip(pageRect); + m_frame->view()->paintContents(&ctx, pageRect); + ctx.restore(); + return scale; + } + +private: + // Set when printing. + float m_printedPageWidth; +}; + +static WebDataSource* DataSourceForDocLoader(DocumentLoader* loader) +{ + return loader ? WebDataSourceImpl::fromDocumentLoader(loader) : 0; +} + + +// WebFrame ------------------------------------------------------------------- + +class WebFrameImpl::DeferredScopeStringMatches { +public: + DeferredScopeStringMatches(WebFrameImpl* webFrame, + int identifier, + const WebString& searchText, + const WebFindOptions& options, + bool reset) + : m_timer(this, &DeferredScopeStringMatches::doTimeout) + , m_webFrame(webFrame) + , m_identifier(identifier) + , m_searchText(searchText) + , m_options(options) + , m_reset(reset) + { + m_timer.startOneShot(0.0); + } + +private: + void doTimeout(Timer<DeferredScopeStringMatches>*) + { + m_webFrame->callScopeStringMatches( + this, m_identifier, m_searchText, m_options, m_reset); + } + + Timer<DeferredScopeStringMatches> m_timer; + RefPtr<WebFrameImpl> m_webFrame; + int m_identifier; + WebString m_searchText; + WebFindOptions m_options; + bool m_reset; +}; + + +// WebFrame ------------------------------------------------------------------- + +WebFrame* WebFrame::frameForEnteredContext() +{ + Frame* frame = + ScriptController::retrieveFrameForEnteredContext(); + return WebFrameImpl::fromFrame(frame); +} + +WebFrame* WebFrame::frameForCurrentContext() +{ + Frame* frame = + ScriptController::retrieveFrameForCurrentContext(); + return WebFrameImpl::fromFrame(frame); +} + +WebString WebFrameImpl::name() const +{ + return m_frame->tree()->name(); +} + +WebURL WebFrameImpl::url() const +{ + const WebDataSource* ds = dataSource(); + if (!ds) + return WebURL(); + return ds->request().url(); +} + +WebURL WebFrameImpl::favIconURL() const +{ + FrameLoader* frameLoader = m_frame->loader(); + // The URL to the favicon may be in the header. As such, only + // ask the loader for the favicon if it's finished loading. + if (frameLoader->state() == FrameStateComplete) { + const KURL& url = frameLoader->iconURL(); + if (!url.isEmpty()) + return url; + } + return WebURL(); +} + +WebURL WebFrameImpl::openSearchDescriptionURL() const +{ + FrameLoader* frameLoader = m_frame->loader(); + if (frameLoader->state() == FrameStateComplete + && m_frame->document() && m_frame->document()->head() + && !m_frame->tree()->parent()) { + HTMLHeadElement* head = m_frame->document()->head(); + if (head) { + RefPtr<HTMLCollection> children = head->children(); + for (Node* child = children->firstItem(); child != 0; child = children->nextItem()) { + HTMLLinkElement* linkElement = toHTMLLinkElement(child); + if (linkElement + && linkElement->type() == osdType + && linkElement->rel() == osdRel + && !linkElement->href().isEmpty()) + return linkElement->href(); + } + } + } + return WebURL(); +} + +WebSize WebFrameImpl::scrollOffset() const +{ + FrameView* view = frameView(); + if (view) + return view->scrollOffset(); + + return WebSize(); +} + +WebSize WebFrameImpl::contentsSize() const +{ + return frame()->view()->contentsSize(); +} + +int WebFrameImpl::contentsPreferredWidth() const +{ + if ((m_frame->document() != 0) && (m_frame->document()->renderView() != 0)) + return m_frame->document()->renderView()->minPrefWidth(); + + return 0; +} + +bool WebFrameImpl::hasVisibleContent() const +{ + return frame()->view()->visibleWidth() > 0 && frame()->view()->visibleHeight() > 0; +} + +WebView* WebFrameImpl::view() const +{ + return viewImpl(); +} + +WebFrame* WebFrameImpl::opener() const +{ + Frame* opener = 0; + if (m_frame) + opener = m_frame->loader()->opener(); + return fromFrame(opener); +} + +WebFrame* WebFrameImpl::parent() const +{ + Frame *parent = 0; + if (m_frame) + parent = m_frame->tree()->parent(); + return fromFrame(parent); +} + +WebFrame* WebFrameImpl::top() const +{ + if (m_frame) + return fromFrame(m_frame->tree()->top()); + + return 0; +} + +WebFrame* WebFrameImpl::firstChild() const +{ + return fromFrame(frame()->tree()->firstChild()); +} + +WebFrame* WebFrameImpl::lastChild() const +{ + return fromFrame(frame()->tree()->lastChild()); +} + +WebFrame* WebFrameImpl::nextSibling() const +{ + return fromFrame(frame()->tree()->nextSibling()); +} + +WebFrame* WebFrameImpl::previousSibling() const +{ + return fromFrame(frame()->tree()->previousSibling()); +} + +WebFrame* WebFrameImpl::traverseNext(bool wrap) const +{ + return fromFrame(frame()->tree()->traverseNextWithWrap(wrap)); +} + +WebFrame* WebFrameImpl::traversePrevious(bool wrap) const +{ + return fromFrame(frame()->tree()->traversePreviousWithWrap(wrap)); +} + +WebFrame* WebFrameImpl::findChildByName(const WebString& name) const +{ + return fromFrame(frame()->tree()->child(name)); +} + +WebFrame* WebFrameImpl::findChildByExpression(const WebString& xpath) const +{ + if (xpath.isEmpty()) + return 0; + + Document* document = m_frame->document(); + + ExceptionCode ec = 0; + PassRefPtr<XPathResult> xpathResult = + document->evaluate(xpath, + document, + 0, // namespace + XPathResult::ORDERED_NODE_ITERATOR_TYPE, + 0, // XPathResult object + ec); + if (!xpathResult.get()) + return 0; + + Node* node = xpathResult->iterateNext(ec); + + if (!node || !node->isFrameOwnerElement()) + return 0; + HTMLFrameOwnerElement* frameElement = + static_cast<HTMLFrameOwnerElement*>(node); + return fromFrame(frameElement->contentFrame()); +} + +void WebFrameImpl::forms(WebVector<WebForm>& results) const +{ + if (!m_frame) + return; + + RefPtr<HTMLCollection> forms = m_frame->document()->forms(); + size_t formCount = forms->length(); + + WebVector<WebForm> temp(formCount); + for (size_t i = 0; i < formCount; ++i) { + Node* node = forms->item(i); + // Strange but true, sometimes item can be 0. + if (node) + temp[i] = static_cast<HTMLFormElement*>(node); + } + results.swap(temp); +} + +WebSecurityOrigin WebFrameImpl::securityOrigin() const +{ + if (!m_frame || !m_frame->document()) + return WebSecurityOrigin(); + + return WebSecurityOrigin(m_frame->document()->securityOrigin()); +} + +void WebFrameImpl::grantUniversalAccess() +{ + ASSERT(m_frame && m_frame->document()); + if (m_frame && m_frame->document()) + m_frame->document()->securityOrigin()->grantUniversalAccess(); +} + +NPObject* WebFrameImpl::windowObject() const +{ + if (!m_frame) + return 0; + + return m_frame->script()->windowScriptNPObject(); +} + +void WebFrameImpl::bindToWindowObject(const WebString& name, NPObject* object) +{ + ASSERT(m_frame); + if (!m_frame || !m_frame->script()->isEnabled()) + return; + + String key = name; +#if USE(V8) + m_frame->script()->bindToWindowObject(m_frame, key, object); +#else + notImplemented(); +#endif +} + +void WebFrameImpl::executeScript(const WebScriptSource& source) +{ + m_frame->script()->executeScript( + ScriptSourceCode(source.code, source.url, source.startLine)); +} + +void WebFrameImpl::executeScriptInNewContext( + const WebScriptSource* sourcesIn, unsigned numSources, int extensionGroup) +{ + Vector<ScriptSourceCode> sources; + + for (unsigned i = 0; i < numSources; ++i) { + sources.append(ScriptSourceCode( + sourcesIn[i].code, sourcesIn[i].url, sourcesIn[i].startLine)); + } + + m_frame->script()->evaluateInNewContext(sources, extensionGroup); +} + +void WebFrameImpl::executeScriptInIsolatedWorld( + int worldId, const WebScriptSource* sourcesIn, unsigned numSources, + int extensionGroup) +{ + Vector<ScriptSourceCode> sources; + + for (unsigned i = 0; i < numSources; ++i) { + sources.append(ScriptSourceCode( + sourcesIn[i].code, sourcesIn[i].url, sourcesIn[i].startLine)); + } + + m_frame->script()->evaluateInIsolatedWorld(worldId, sources, extensionGroup); +} + +void WebFrameImpl::addMessageToConsole(const WebConsoleMessage& message) +{ + ASSERT(frame()); + + MessageLevel webCoreMessageLevel; + switch (message.level) { + case WebConsoleMessage::LevelTip: + webCoreMessageLevel = TipMessageLevel; + break; + case WebConsoleMessage::LevelLog: + webCoreMessageLevel = LogMessageLevel; + break; + case WebConsoleMessage::LevelWarning: + webCoreMessageLevel = WarningMessageLevel; + break; + case WebConsoleMessage::LevelError: + webCoreMessageLevel = ErrorMessageLevel; + break; + default: + ASSERT_NOT_REACHED(); + return; + } + + frame()->domWindow()->console()->addMessage( + OtherMessageSource, LogMessageType, webCoreMessageLevel, message.text, + 1, String()); +} + +void WebFrameImpl::collectGarbage() +{ + if (!m_frame) + return; + if (!m_frame->settings()->isJavaScriptEnabled()) + return; + // FIXME: Move this to the ScriptController and make it JS neutral. +#if USE(V8) + m_frame->script()->collectGarbage(); +#else + notImplemented(); +#endif +} + +#if USE(V8) +// Returns the V8 context for this frame, or an empty handle if there is none. +v8::Local<v8::Context> WebFrameImpl::mainWorldScriptContext() const +{ + if (!m_frame) + return v8::Local<v8::Context>(); + + return V8Proxy::mainWorldContext(m_frame); +} +#endif + +bool WebFrameImpl::insertStyleText( + const WebString& css, const WebString& id) { + Document* document = frame()->document(); + if (!document) + return false; + Element* documentElement = document->documentElement(); + if (!documentElement) + return false; + + ExceptionCode err = 0; + + if (!id.isEmpty()) { + Element* oldElement = document->getElementById(id); + if (oldElement) { + Node* parent = oldElement->parent(); + if (!parent) + return false; + parent->removeChild(oldElement, err); + } + } + + RefPtr<Element> stylesheet = document->createElement( + HTMLNames::styleTag, false); + if (!id.isEmpty()) + stylesheet->setAttribute(HTMLNames::idAttr, id); + stylesheet->setTextContent(css, err); + ASSERT(!err); + Node* first = documentElement->firstChild(); + bool success = documentElement->insertBefore(stylesheet, first, err); + ASSERT(success); + return success; +} + +void WebFrameImpl::reload() +{ + m_frame->loader()->history()->saveDocumentAndScrollState(); + + stopLoading(); // Make sure existing activity stops. + m_frame->loader()->reload(); +} + +void WebFrameImpl::loadRequest(const WebURLRequest& request) +{ + ASSERT(!request.isNull()); + const ResourceRequest& resourceRequest = request.toResourceRequest(); + + if (resourceRequest.url().protocolIs("javascript")) { + loadJavaScriptURL(resourceRequest.url()); + return; + } + + stopLoading(); // Make sure existing activity stops. + m_frame->loader()->load(resourceRequest, false); +} + +void WebFrameImpl::loadHistoryItem(const WebHistoryItem& item) +{ + RefPtr<HistoryItem> historyItem = PassRefPtr<HistoryItem>(item); + ASSERT(historyItem.get()); + + stopLoading(); // Make sure existing activity stops. + + // If there is no currentItem, which happens when we are navigating in + // session history after a crash, we need to manufacture one otherwise WebKit + // hoarks. This is probably the wrong thing to do, but it seems to work. + RefPtr<HistoryItem> currentItem = m_frame->loader()->history()->currentItem(); + if (!currentItem) { + currentItem = HistoryItem::create(); + currentItem->setLastVisitWasFailure(true); + m_frame->loader()->history()->setCurrentItem(currentItem.get()); + viewImpl()->setCurrentHistoryItem(currentItem.get()); + } + + m_frame->loader()->history()->goToItem( + historyItem.get(), FrameLoadTypeIndexedBackForward); +} + +void WebFrameImpl::loadData(const WebData& data, + const WebString& mimeType, + const WebString& textEncoding, + const WebURL& baseURL, + const WebURL& unreachableURL, + bool replace) +{ + SubstituteData substData(data, mimeType, textEncoding, unreachableURL); + ASSERT(substData.isValid()); + + stopLoading(); // Make sure existing activity stops. + m_frame->loader()->load(ResourceRequest(baseURL), substData, false); + if (replace) { + // Do this to force WebKit to treat the load as replacing the currently + // loaded page. + m_frame->loader()->setReplacing(); + } +} + +void WebFrameImpl::loadHTMLString(const WebData& data, + const WebURL& baseURL, + const WebURL& unreachableURL, + bool replace) +{ + loadData(data, + WebString::fromUTF8("text/html"), + WebString::fromUTF8("UTF-8"), + baseURL, + unreachableURL, + replace); +} + +bool WebFrameImpl::isLoading() const +{ + if (!m_frame) + return false; + return m_frame->loader()->isLoading(); +} + +void WebFrameImpl::stopLoading() +{ + if (!m_frame) + return; + + // FIXME: Figure out what we should really do here. It seems like a bug + // that FrameLoader::stopLoading doesn't call stopAllLoaders. + m_frame->loader()->stopAllLoaders(); + m_frame->loader()->stopLoading(UnloadEventPolicyNone); +} + +WebDataSource* WebFrameImpl::provisionalDataSource() const +{ + FrameLoader* frameLoader = m_frame->loader(); + + // We regard the policy document loader as still provisional. + DocumentLoader* docLoader = frameLoader->provisionalDocumentLoader(); + if (!docLoader) + docLoader = frameLoader->policyDocumentLoader(); + + return DataSourceForDocLoader(docLoader); +} + +WebDataSource* WebFrameImpl::dataSource() const +{ + return DataSourceForDocLoader(m_frame->loader()->documentLoader()); +} + +WebHistoryItem WebFrameImpl::previousHistoryItem() const +{ + // We use the previous item here because documentState (filled-out forms) + // only get saved to history when it becomes the previous item. The caller + // is expected to query the history item after a navigation occurs, after + // the desired history item has become the previous entry. + return WebHistoryItem(viewImpl()->previousHistoryItem()); +} + +WebHistoryItem WebFrameImpl::currentHistoryItem() const +{ + m_frame->loader()->history()->saveDocumentAndScrollState(); + + return WebHistoryItem(m_frame->page()->backForwardList()->currentItem()); +} + +void WebFrameImpl::enableViewSourceMode(bool enable) +{ + if (m_frame) + m_frame->setInViewSourceMode(enable); +} + +bool WebFrameImpl::isViewSourceModeEnabled() const +{ + if (m_frame) + return m_frame->inViewSourceMode(); + + return false; +} + +void WebFrameImpl::setReferrerForRequest( + WebURLRequest& request, const WebURL& referrerURL) { + String referrer; + if (referrerURL.isEmpty()) + referrer = m_frame->loader()->outgoingReferrer(); + else + referrer = referrerURL.spec().utf16(); + if (SecurityOrigin::shouldHideReferrer(request.url(), referrer)) + return; + request.setHTTPHeaderField(WebString::fromUTF8("Referer"), referrer); +} + +void WebFrameImpl::dispatchWillSendRequest(WebURLRequest& request) +{ + ResourceResponse response; + m_frame->loader()->client()->dispatchWillSendRequest( + 0, 0, request.toMutableResourceRequest(), response); +} + +void WebFrameImpl::commitDocumentData(const char* data, size_t dataLen) +{ + DocumentLoader* documentLoader = m_frame->loader()->documentLoader(); + + // Set the text encoding. This calls begin() for us. It is safe to call + // this multiple times (Mac does: page/mac/WebCoreFrameBridge.mm). + bool userChosen = true; + String encoding = documentLoader->overrideEncoding(); + if (encoding.isNull()) { + userChosen = false; + encoding = documentLoader->response().textEncodingName(); + } + m_frame->loader()->setEncoding(encoding, userChosen); + + // NOTE: mac only does this if there is a document + m_frame->loader()->addData(data, dataLen); +} + +unsigned WebFrameImpl::unloadListenerCount() const +{ + return frame()->domWindow()->pendingUnloadEventListeners(); +} + +bool WebFrameImpl::isProcessingUserGesture() const +{ + return frame()->loader()->isProcessingUserGesture(); +} + +bool WebFrameImpl::willSuppressOpenerInNewFrame() const +{ + return frame()->loader()->suppressOpenerInNewFrame(); +} + +void WebFrameImpl::replaceSelection(const WebString& text) +{ + RefPtr<DocumentFragment> fragment = createFragmentFromText( + frame()->selection()->toNormalizedRange().get(), text); + applyCommand(ReplaceSelectionCommand::create( + frame()->document(), fragment.get(), false, true, true)); +} + +void WebFrameImpl::insertText(const WebString& text) +{ + frame()->editor()->insertText(text, 0); +} + +void WebFrameImpl::setMarkedText( + const WebString& text, unsigned location, unsigned length) +{ + Editor* editor = frame()->editor(); + + editor->confirmComposition(text); + + Vector<CompositionUnderline> decorations; + editor->setComposition(text, decorations, location, length); +} + +void WebFrameImpl::unmarkText() +{ + frame()->editor()->confirmCompositionWithoutDisturbingSelection(); +} + +bool WebFrameImpl::hasMarkedText() const +{ + return frame()->editor()->hasComposition(); +} + +WebRange WebFrameImpl::markedRange() const +{ + return frame()->editor()->compositionRange(); +} + +bool WebFrameImpl::executeCommand(const WebString& name) +{ + ASSERT(frame()); + + if (name.length() <= 2) + return false; + + // Since we don't have NSControl, we will convert the format of command + // string and call the function on Editor directly. + String command = name; + + // Make sure the first letter is upper case. + command.replace(0, 1, command.substring(0, 1).upper()); + + // Remove the trailing ':' if existing. + if (command[command.length() - 1] == UChar(':')) + command = command.substring(0, command.length() - 1); + + bool rv = true; + + // Specially handling commands that Editor::execCommand does not directly + // support. + if (command == "DeleteToEndOfParagraph") { + Editor* editor = frame()->editor(); + if (!editor->deleteWithDirection(SelectionController::FORWARD, + ParagraphBoundary, + true, + false)) { + editor->deleteWithDirection(SelectionController::FORWARD, + CharacterGranularity, + true, + false); + } + } else if (command == "Indent") + frame()->editor()->indent(); + else if (command == "Outdent") + frame()->editor()->outdent(); + else if (command == "DeleteBackward") + rv = frame()->editor()->command(AtomicString("BackwardDelete")).execute(); + else if (command == "DeleteForward") + rv = frame()->editor()->command(AtomicString("ForwardDelete")).execute(); + else if (command == "AdvanceToNextMisspelling") { + // False must be passed here, or the currently selected word will never be + // skipped. + frame()->editor()->advanceToNextMisspelling(false); + } else if (command == "ToggleSpellPanel") + frame()->editor()->showSpellingGuessPanel(); + else + rv = frame()->editor()->command(command).execute(); + return rv; +} + +bool WebFrameImpl::executeCommand(const WebString& name, const WebString& value) +{ + ASSERT(frame()); + String webName = name; + + // moveToBeginningOfDocument and moveToEndfDocument are only handled by WebKit + // for editable nodes. + if (!frame()->editor()->canEdit() && webName == "moveToBeginningOfDocument") + return viewImpl()->propagateScroll(ScrollUp, ScrollByDocument); + + if (!frame()->editor()->canEdit() && webName == "moveToEndOfDocument") + return viewImpl()->propagateScroll(ScrollDown, ScrollByDocument); + + return frame()->editor()->command(webName).execute(value); +} + +bool WebFrameImpl::isCommandEnabled(const WebString& name) const +{ + ASSERT(frame()); + return frame()->editor()->command(name).isEnabled(); +} + +void WebFrameImpl::enableContinuousSpellChecking(bool enable) +{ + if (enable == isContinuousSpellCheckingEnabled()) + return; + frame()->editor()->toggleContinuousSpellChecking(); +} + +bool WebFrameImpl::isContinuousSpellCheckingEnabled() const +{ + return frame()->editor()->isContinuousSpellCheckingEnabled(); +} + +bool WebFrameImpl::hasSelection() const +{ + // frame()->selection()->isNone() never returns true. + return (frame()->selection()->start() != frame()->selection()->end()); +} + +WebRange WebFrameImpl::selectionRange() const +{ + return frame()->selection()->toNormalizedRange(); +} + +WebString WebFrameImpl::selectionAsText() const +{ + RefPtr<Range> range = frame()->selection()->toNormalizedRange(); + if (!range.get()) + return WebString(); + + String text = range->text(); +#if PLATFORM(WIN_OS) + replaceNewlinesWithWindowsStyleNewlines(text); +#endif + replaceNBSPWithSpace(text); + return text; +} + +WebString WebFrameImpl::selectionAsMarkup() const +{ + RefPtr<Range> range = frame()->selection()->toNormalizedRange(); + if (!range.get()) + return WebString(); + + return createMarkup(range.get(), 0); +} + +int WebFrameImpl::printBegin(const WebSize& pageSize) +{ + ASSERT(!frame()->document()->isFrameSet()); + + m_printContext.set(new ChromePrintContext(frame())); + FloatRect rect(0, 0, static_cast<float>(pageSize.width), + static_cast<float>(pageSize.height)); + m_printContext->begin(rect.width()); + float pageHeight; + // We ignore the overlays calculation for now since they are generated in the + // browser. pageHeight is actually an output parameter. + m_printContext->computePageRects(rect, 0, 0, 1.0, pageHeight); + return m_printContext->pageCount(); +} + +float WebFrameImpl::getPrintPageShrink(int page) +{ + // Ensure correct state. + if (!m_printContext.get() || page < 0) { + ASSERT_NOT_REACHED(); + return 0; + } + + return m_printContext->getPageShrink(page); +} + +float WebFrameImpl::printPage(int page, WebCanvas* canvas) +{ + // Ensure correct state. + if (!m_printContext.get() || page < 0 || !frame() || !frame()->document()) { + ASSERT_NOT_REACHED(); + return 0; + } + +#if PLATFORM(WIN_OS) || PLATFORM(LINUX) || PLATFORM(FREEBSD) + PlatformContextSkia context(canvas); + GraphicsContext spool(&context); +#elif PLATFORM(DARWIN) + GraphicsContext spool(canvas); + LocalCurrentGraphicsContext localContext(&spool); +#endif + + return m_printContext->spoolPage(spool, page); +} + +void WebFrameImpl::printEnd() +{ + ASSERT(m_printContext.get()); + if (m_printContext.get()) + m_printContext->end(); + m_printContext.clear(); +} + +bool WebFrameImpl::find(int identifier, + const WebString& searchText, + const WebFindOptions& options, + bool wrapWithinFrame, + WebRect* selectionRect) +{ + WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl(); + + if (!options.findNext) + frame()->page()->unmarkAllTextMatches(); + else + setMarkerActive(m_activeMatch.get(), false); // Active match is changing. + + // Starts the search from the current selection. + bool startInSelection = true; + + // If the user has selected something since the last Find operation we want + // to start from there. Otherwise, we start searching from where the last Find + // operation left off (either a Find or a FindNext operation). + VisibleSelection selection(frame()->selection()->selection()); + if (selection.isNone() && m_activeMatch) { + selection = VisibleSelection(m_activeMatch.get()); + frame()->selection()->setSelection(selection); + } + + ASSERT(frame() && frame()->view()); + bool found = frame()->findString( + searchText, options.forward, options.matchCase, wrapWithinFrame, + startInSelection); + if (found) { + // Store which frame was active. This will come in handy later when we + // change the active match ordinal below. + WebFrameImpl* oldActiveFrame = mainFrameImpl->m_activeMatchFrame; + // Set this frame as the active frame (the one with the active highlight). + mainFrameImpl->m_activeMatchFrame = this; + + // We found something, so we can now query the selection for its position. + VisibleSelection newSelection(frame()->selection()->selection()); + IntRect currSelectionRect; + + // If we thought we found something, but it couldn't be selected (perhaps + // because it was marked -webkit-user-select: none), we can't set it to + // be active but we still continue searching. This matches Safari's + // behavior, including some oddities when selectable and un-selectable text + // are mixed on a page: see https://bugs.webkit.org/show_bug.cgi?id=19127. + if (newSelection.isNone() || (newSelection.start() == newSelection.end())) + m_activeMatch = 0; + else { + m_activeMatch = newSelection.toNormalizedRange(); + currSelectionRect = m_activeMatch->boundingBox(); + setMarkerActive(m_activeMatch.get(), true); // Active. + // WebKit draws the highlighting for all matches. + executeCommand(WebString::fromUTF8("Unselect")); + } + + if (!options.findNext) { + // This is a Find operation, so we set the flag to ask the scoping effort + // to find the active rect for us so we can update the ordinal (n of m). + m_locatingActiveRect = true; + } else { + if (oldActiveFrame != this) { + // If the active frame has changed it means that we have a multi-frame + // page and we just switch to searching in a new frame. Then we just + // want to reset the index. + if (options.forward) + m_activeMatchIndex = 0; + else + m_activeMatchIndex = m_lastMatchCount - 1; + } else { + // We are still the active frame, so increment (or decrement) the + // |m_activeMatchIndex|, wrapping if needed (on single frame pages). + options.forward ? ++m_activeMatchIndex : --m_activeMatchIndex; + if (m_activeMatchIndex + 1 > m_lastMatchCount) + m_activeMatchIndex = 0; + if (m_activeMatchIndex + 1 == 0) + m_activeMatchIndex = m_lastMatchCount - 1; + } + if (selectionRect) { + WebRect rect = frame()->view()->convertToContainingWindow(currSelectionRect); + rect.x -= frameView()->scrollOffset().width(); + rect.y -= frameView()->scrollOffset().height(); + *selectionRect = rect; + + reportFindInPageSelection(rect, m_activeMatchIndex + 1, identifier); + } + } + } else { + // Nothing was found in this frame. + m_activeMatch = 0; + + // Erase all previous tickmarks and highlighting. + invalidateArea(InvalidateAll); + } + + return found; +} + +void WebFrameImpl::stopFinding(bool clearSelection) +{ + if (!clearSelection) + setFindEndstateFocusAndSelection(); + cancelPendingScopingEffort(); + + // Remove all markers for matches found and turn off the highlighting. + if (!parent()) + frame()->document()->removeMarkers(DocumentMarker::TextMatch); + frame()->setMarkedTextMatchesAreHighlighted(false); + + // Let the frame know that we don't want tickmarks or highlighting anymore. + invalidateArea(InvalidateAll); +} + +void WebFrameImpl::scopeStringMatches(int identifier, + const WebString& searchText, + const WebFindOptions& options, + bool reset) +{ + if (!shouldScopeMatches(searchText)) + return; + + WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl(); + + if (reset) { + // This is a brand new search, so we need to reset everything. + // Scoping is just about to begin. + m_scopingComplete = false; + // Clear highlighting for this frame. + if (frame()->markedTextMatchesAreHighlighted()) + frame()->page()->unmarkAllTextMatches(); + // Clear the counters from last operation. + m_lastMatchCount = 0; + m_nextInvalidateAfter = 0; + + m_resumeScopingFromRange = 0; + + mainFrameImpl->m_framesScopingCount++; + + // Now, defer scoping until later to allow find operation to finish quickly. + scopeStringMatchesSoon( + identifier, + searchText, + options, + false); // false=we just reset, so don't do it again. + return; + } + + RefPtr<Range> searchRange(rangeOfContents(frame()->document())); + + ExceptionCode ec = 0, ec2 = 0; + if (m_resumeScopingFromRange.get()) { + // This is a continuation of a scoping operation that timed out and didn't + // complete last time around, so we should start from where we left off. + searchRange->setStart(m_resumeScopingFromRange->startContainer(), + m_resumeScopingFromRange->startOffset(ec2) + 1, + ec); + if (ec != 0 || ec2 != 0) { + if (ec2 != 0) // A non-zero |ec| happens when navigating during search. + ASSERT_NOT_REACHED(); + return; + } + } + + // This timeout controls how long we scope before releasing control. This + // value does not prevent us from running for longer than this, but it is + // periodically checked to see if we have exceeded our allocated time. + const double maxScopingDuration = 0.1; // seconds + + int matchCount = 0; + bool timedOut = false; + double startTime = currentTime(); + do { + // Find next occurrence of the search string. + // FIXME: (http://b/1088245) This WebKit operation may run for longer + // than the timeout value, and is not interruptible as it is currently + // written. We may need to rewrite it with interruptibility in mind, or + // find an alternative. + RefPtr<Range> resultRange(findPlainText(searchRange.get(), + searchText, + true, + options.matchCase)); + if (resultRange->collapsed(ec)) { + if (!resultRange->startContainer()->isInShadowTree()) + break; + + searchRange = rangeOfContents(frame()->document()); + searchRange->setStartAfter( + resultRange->startContainer()->shadowAncestorNode(), ec); + 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. (This function is based on the implementation of + // Frame::markAllMatchesForText, which is where this safeguard comes from). + VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM); + if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM)) + break; + + // Only treat the result as a match if it is visible + if (frame()->editor()->insideVisibleArea(resultRange.get())) { + ++matchCount; + + setStart(searchRange.get(), newStart); + Node* shadowTreeRoot = searchRange->shadowTreeRootNode(); + if (searchRange->collapsed(ec) && shadowTreeRoot) + searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), ec); + + // Catch a special case where Find found something but doesn't know what + // the bounding box for it is. In this case we set the first match we find + // as the active rect. + IntRect resultBounds = resultRange->boundingBox(); + IntRect activeSelectionRect; + if (m_locatingActiveRect) { + activeSelectionRect = m_activeMatch.get() ? + m_activeMatch->boundingBox() : resultBounds; + } + + // If the Find function found a match it will have stored where the + // match was found in m_activeSelectionRect on the current frame. If we + // find this rect during scoping it means we have found the active + // tickmark. + bool foundActiveMatch = false; + if (m_locatingActiveRect && (activeSelectionRect == resultBounds)) { + // We have found the active tickmark frame. + mainFrameImpl->m_activeMatchFrame = this; + foundActiveMatch = true; + // We also know which tickmark is active now. + m_activeMatchIndex = matchCount - 1; + // To stop looking for the active tickmark, we set this flag. + m_locatingActiveRect = false; + + // Notify browser of new location for the selected rectangle. + resultBounds.move(-frameView()->scrollOffset().width(), + -frameView()->scrollOffset().height()); + reportFindInPageSelection( + frame()->view()->convertToContainingWindow(resultBounds), + m_activeMatchIndex + 1, + identifier); + } + + addMarker(resultRange.get(), foundActiveMatch); + } + + m_resumeScopingFromRange = resultRange; + timedOut = (currentTime() - startTime) >= maxScopingDuration; + } while (!timedOut); + + // Remember what we search for last time, so we can skip searching if more + // letters are added to the search string (and last outcome was 0). + m_lastSearchString = searchText; + + if (matchCount > 0) { + frame()->setMarkedTextMatchesAreHighlighted(true); + + m_lastMatchCount += matchCount; + + // Let the mainframe know how much we found during this pass. + mainFrameImpl->increaseMatchCount(matchCount, identifier); + } + + if (timedOut) { + // If we found anything during this pass, we should redraw. However, we + // don't want to spam too much if the page is extremely long, so if we + // reach a certain point we start throttling the redraw requests. + if (matchCount > 0) + invalidateIfNecessary(); + + // Scoping effort ran out of time, lets ask for another time-slice. + scopeStringMatchesSoon( + identifier, + searchText, + options, + false); // don't reset. + return; // Done for now, resume work later. + } + + // This frame has no further scoping left, so it is done. Other frames might, + // of course, continue to scope matches. + m_scopingComplete = true; + mainFrameImpl->m_framesScopingCount--; + + // If this is the last frame to finish scoping we need to trigger the final + // update to be sent. + if (mainFrameImpl->m_framesScopingCount == 0) + mainFrameImpl->increaseMatchCount(0, identifier); + + // This frame is done, so show any scrollbar tickmarks we haven't drawn yet. + invalidateArea(InvalidateScrollbar); +} + +void WebFrameImpl::cancelPendingScopingEffort() +{ + deleteAllValues(m_deferredScopingWork); + m_deferredScopingWork.clear(); + + m_activeMatchIndex = -1; +} + +void WebFrameImpl::increaseMatchCount(int count, int identifier) +{ + // This function should only be called on the mainframe. + ASSERT(!parent()); + + m_totalMatchCount += count; + + // Update the UI with the latest findings. + if (client()) { + client()->reportFindInPageMatchCount(identifier, m_totalMatchCount, + m_framesScopingCount == 0); + } +} + +void WebFrameImpl::reportFindInPageSelection(const WebRect& selectionRect, + int activeMatchOrdinal, + int identifier) +{ + // Update the UI with the latest selection rect. + if (client()) { + client()->reportFindInPageSelection( + identifier, ordinalOfFirstMatchForFrame(this) + activeMatchOrdinal, + selectionRect); + } +} + +void WebFrameImpl::resetMatchCount() +{ + m_totalMatchCount = 0; + m_framesScopingCount = 0; +} + +WebURL WebFrameImpl::completeURL(const WebString& url) const +{ + if (!m_frame || !m_frame->document()) + return WebURL(); + + return m_frame->document()->completeURL(url); +} + +WebString WebFrameImpl::contentAsText(size_t maxChars) const +{ + if (!m_frame) + return WebString(); + + Vector<UChar> text; + frameContentAsPlainText(maxChars, m_frame, &text); + return String::adopt(text); +} + +WebString WebFrameImpl::contentAsMarkup() const +{ + return createFullMarkup(m_frame->document()); +} + +// WebFrameImpl public --------------------------------------------------------- + +int WebFrameImpl::m_liveObjectCount = 0; + +PassRefPtr<WebFrameImpl> WebFrameImpl::create(WebFrameClient* client) +{ + return adoptRef(new WebFrameImpl(ClientHandle::create(client))); +} + +WebFrameImpl::WebFrameImpl(PassRefPtr<ClientHandle> clientHandle) + : m_frameLoaderClient(this) + , m_clientHandle(clientHandle) + , m_activeMatchFrame(0) + , m_activeMatchIndex(-1) + , m_locatingActiveRect(false) + , m_resumeScopingFromRange(0) + , m_lastMatchCount(-1) + , m_totalMatchCount(-1) + , m_framesScopingCount(-1) + , m_scopingComplete(false) + , m_nextInvalidateAfter(0) +{ + ChromiumBridge::incrementStatsCounter(webFrameActiveCount); + m_liveObjectCount++; +} + +WebFrameImpl::~WebFrameImpl() +{ + ChromiumBridge::decrementStatsCounter(webFrameActiveCount); + m_liveObjectCount--; + + cancelPendingScopingEffort(); + clearPasswordListeners(); +} + +void WebFrameImpl::initializeAsMainFrame(WebViewImpl* webViewImpl) +{ + RefPtr<Frame> frame = Frame::create(webViewImpl->page(), 0, &m_frameLoaderClient); + m_frame = frame.get(); + + // Add reference on behalf of FrameLoader. See comments in + // WebFrameLoaderClient::frameLoaderDestroyed for more info. + ref(); + + // We must call init() after m_frame is assigned because it is referenced + // during init(). + m_frame->init(); +} + +PassRefPtr<Frame> WebFrameImpl::createChildFrame( + const FrameLoadRequest& request, HTMLFrameOwnerElement* ownerElement) +{ + RefPtr<WebFrameImpl> webframe(adoptRef(new WebFrameImpl(m_clientHandle))); + + // Add an extra ref on behalf of the Frame/FrameLoader, which references the + // WebFrame via the FrameLoaderClient interface. See the comment at the top + // of this file for more info. + webframe->ref(); + + RefPtr<Frame> childFrame = Frame::create( + m_frame->page(), ownerElement, &webframe->m_frameLoaderClient); + webframe->m_frame = childFrame.get(); + + childFrame->tree()->setName(request.frameName()); + + m_frame->tree()->appendChild(childFrame); + + // Frame::init() can trigger onload event in the parent frame, + // which may detach this frame and trigger a null-pointer access + // in FrameTree::removeChild. Move init() after appendChild call + // so that webframe->mFrame is in the tree before triggering + // onload event handler. + // Because the event handler may set webframe->mFrame to null, + // it is necessary to check the value after calling init() and + // return without loading URL. + // (b:791612) + childFrame->init(); // create an empty document + if (!childFrame->tree()->parent()) + return 0; + + m_frame->loader()->loadURLIntoChildFrame( + request.resourceRequest().url(), + request.resourceRequest().httpReferrer(), + childFrame.get()); + + // A synchronous navigation (about:blank) would have already processed + // onload, so it is possible for the frame to have already been destroyed by + // script in the page. + if (!childFrame->tree()->parent()) + return 0; + + return childFrame.release(); +} + +void WebFrameImpl::layout() +{ + // layout this frame + FrameView* view = m_frame->view(); + if (view) + view->layoutIfNeededRecursive(); +} + +void WebFrameImpl::paint(WebCanvas* canvas, const WebRect& rect) +{ + if (rect.isEmpty()) + return; + IntRect dirtyRect(rect); +#if WEBKIT_USING_CG + GraphicsContext gc(canvas); + LocalCurrentGraphicsContext localContext(&gc); +#elif WEBKIT_USING_SKIA + PlatformContextSkia context(canvas); + + // PlatformGraphicsContext is actually a pointer to PlatformContextSkia + GraphicsContext gc(reinterpret_cast<PlatformGraphicsContext*>(&context)); +#else + notImplemented(); +#endif + gc.save(); + if (m_frame->document() && frameView()) { + gc.clip(dirtyRect); + frameView()->paint(&gc, dirtyRect); + m_frame->page()->inspectorController()->drawNodeHighlight(gc); + } else + gc.fillRect(dirtyRect, Color::white); + gc.restore(); +} + +void WebFrameImpl::createFrameView() +{ + ASSERT(m_frame); // If m_frame doesn't exist, we probably didn't init properly. + + Page* page = m_frame->page(); + ASSERT(page); + + ASSERT(page->mainFrame() != 0); + + bool isMainFrame = m_frame == page->mainFrame(); + if (isMainFrame && m_frame->view()) + m_frame->view()->setParentVisible(false); + + m_frame->setView(0); + + WebViewImpl* webView = viewImpl(); + + RefPtr<FrameView> view; + if (isMainFrame) + view = FrameView::create(m_frame, webView->size()); + else + view = FrameView::create(m_frame); + + m_frame->setView(view); + + if (webView->isTransparent()) + view->setTransparent(true); + + // FIXME: The Mac code has a comment about this possibly being unnecessary. + // See installInFrame in WebCoreFrameBridge.mm + if (m_frame->ownerRenderer()) + m_frame->ownerRenderer()->setWidget(view.get()); + + if (HTMLFrameOwnerElement* owner = m_frame->ownerElement()) + view->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff); + + if (isMainFrame) + view->setParentVisible(true); +} + +WebFrameImpl* WebFrameImpl::fromFrame(Frame* frame) +{ + if (!frame) + return 0; + + return static_cast<FrameLoaderClientImpl*>(frame->loader()->client())->webFrame(); +} + +WebViewImpl* WebFrameImpl::viewImpl() const +{ + if (!m_frame) + return 0; + + return WebViewImpl::fromPage(m_frame->page()); +} + +WebDataSourceImpl* WebFrameImpl::dataSourceImpl() const +{ + return static_cast<WebDataSourceImpl*>(dataSource()); +} + +WebDataSourceImpl* WebFrameImpl::provisionalDataSourceImpl() const +{ + return static_cast<WebDataSourceImpl*>(provisionalDataSource()); +} + +void WebFrameImpl::setFindEndstateFocusAndSelection() +{ + WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl(); + + if (this == mainFrameImpl->activeMatchFrame() && m_activeMatch.get()) { + // If the user has set the selection since the match was found, we + // don't focus anything. + VisibleSelection selection(frame()->selection()->selection()); + if (!selection.isNone()) + return; + + // Try to find the first focusable node up the chain, which will, for + // example, focus links if we have found text within the link. + Node* node = m_activeMatch->firstNode(); + while (node && !node->isFocusable() && node != frame()->document()) + node = node->parent(); + + if (node && node != frame()->document()) { + // Found a focusable parent node. Set focus to it. + frame()->document()->setFocusedNode(node); + } else { + // Iterate over all the nodes in the range until we find a focusable node. + // This, for example, sets focus to the first link if you search for + // text and text that is within one or more links. + node = m_activeMatch->firstNode(); + while (node && node != m_activeMatch->pastLastNode()) { + if (node->isFocusable()) { + frame()->document()->setFocusedNode(node); + break; + } + node = node->traverseNextNode(); + } + } + } +} + +void WebFrameImpl::didFail(const ResourceError& error, bool wasProvisional) +{ + if (!client()) + return; + WebURLError webError = error; + if (wasProvisional) + client()->didFailProvisionalLoad(this, webError); + else + client()->didFailLoad(this, webError); +} + +void WebFrameImpl::setAllowsScrolling(bool flag) +{ + m_frame->view()->setCanHaveScrollbars(flag); +} + +void WebFrameImpl::registerPasswordListener( + PassRefPtr<HTMLInputElement> inputElement, + PasswordAutocompleteListener* listener) +{ + RefPtr<HTMLInputElement> element = inputElement; + ASSERT(m_passwordListeners.find(element) == m_passwordListeners.end()); + m_passwordListeners.set(element, listener); +} + +PasswordAutocompleteListener* WebFrameImpl::getPasswordListener( + HTMLInputElement* inputElement) +{ + return m_passwordListeners.get(RefPtr<HTMLInputElement>(inputElement)); +} + +// WebFrameImpl private -------------------------------------------------------- + +void WebFrameImpl::closing() +{ + m_frame = 0; +} + +void WebFrameImpl::invalidateArea(AreaToInvalidate area) +{ + ASSERT(frame() && frame()->view()); + FrameView* view = frame()->view(); + + if ((area & InvalidateAll) == InvalidateAll) + view->invalidateRect(view->frameRect()); + else { + if ((area & InvalidateContentArea) == InvalidateContentArea) { + IntRect contentArea( + view->x(), view->y(), view->visibleWidth(), view->visibleHeight()); + view->invalidateRect(contentArea); + } + + if ((area & InvalidateScrollbar) == InvalidateScrollbar) { + // Invalidate the vertical scroll bar region for the view. + IntRect scrollBarVert( + view->x() + view->visibleWidth(), view->y(), + ScrollbarTheme::nativeTheme()->scrollbarThickness(), + view->visibleHeight()); + view->invalidateRect(scrollBarVert); + } + } +} + +void WebFrameImpl::addMarker(Range* range, bool activeMatch) +{ + // Use a TextIterator to visit the potentially multiple nodes the range + // covers. + TextIterator markedText(range); + for (; !markedText.atEnd(); markedText.advance()) { + RefPtr<Range> textPiece = markedText.range(); + int exception = 0; + + DocumentMarker marker = { + DocumentMarker::TextMatch, + textPiece->startOffset(exception), + textPiece->endOffset(exception), + "", + activeMatch + }; + + if (marker.endOffset > marker.startOffset) { + // Find the node to add a marker to and add it. + Node* node = textPiece->startContainer(exception); + frame()->document()->addMarker(node, marker); + + // Rendered rects for markers in WebKit are not populated until each time + // the markers are painted. However, we need it to happen sooner, because + // the whole purpose of tickmarks on the scrollbar is to show where + // matches off-screen are (that haven't been painted yet). + Vector<DocumentMarker> markers = frame()->document()->markersForNode(node); + frame()->document()->setRenderedRectForMarker( + textPiece->startContainer(exception), + markers[markers.size() - 1], + range->boundingBox()); + } + } +} + +void WebFrameImpl::setMarkerActive(Range* range, bool active) +{ + if (!range) + return; + + frame()->document()->setMarkersActive(range, active); +} + +int WebFrameImpl::ordinalOfFirstMatchForFrame(WebFrameImpl* frame) const +{ + int ordinal = 0; + WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl(); + // Iterate from the main frame up to (but not including) |frame| and + // add up the number of matches found so far. + for (WebFrameImpl* it = mainFrameImpl; + it != frame; + it = static_cast<WebFrameImpl*>(it->traverseNext(true))) { + if (it->m_lastMatchCount > 0) + ordinal += it->m_lastMatchCount; + } + return ordinal; +} + +bool WebFrameImpl::shouldScopeMatches(const String& searchText) +{ + // Don't scope if we can't find a frame or if the frame is not visible. + // The user may have closed the tab/application, so abort. + if (!frame() || !hasVisibleContent()) + return false; + + ASSERT(frame()->document() && frame()->view()); + + // If the frame completed the scoping operation and found 0 matches the last + // time it was searched, then we don't have to search it again if the user is + // just adding to the search string or sending the same search string again. + if (m_scopingComplete && !m_lastSearchString.isEmpty() && m_lastMatchCount == 0) { + // Check to see if the search string prefixes match. + String previousSearchPrefix = + searchText.substring(0, m_lastSearchString.length()); + + if (previousSearchPrefix == m_lastSearchString) + return false; // Don't search this frame, it will be fruitless. + } + + return true; +} + +void WebFrameImpl::scopeStringMatchesSoon(int identifier, const WebString& searchText, + const WebFindOptions& options, bool reset) +{ + m_deferredScopingWork.append(new DeferredScopeStringMatches( + this, identifier, searchText, options, reset)); +} + +void WebFrameImpl::callScopeStringMatches(DeferredScopeStringMatches* caller, + int identifier, const WebString& searchText, + const WebFindOptions& options, bool reset) +{ + m_deferredScopingWork.remove(m_deferredScopingWork.find(caller)); + + scopeStringMatches(identifier, searchText, options, reset); + + // This needs to happen last since searchText is passed by reference. + delete caller; +} + +void WebFrameImpl::invalidateIfNecessary() +{ + if (m_lastMatchCount > m_nextInvalidateAfter) { + // FIXME: (http://b/1088165) Optimize the drawing of the tickmarks and + // remove this. This calculation sets a milestone for when next to + // invalidate the scrollbar and the content area. We do this so that we + // don't spend too much time drawing the scrollbar over and over again. + // Basically, up until the first 500 matches there is no throttle. + // After the first 500 matches, we set set the milestone further and + // further out (750, 1125, 1688, 2K, 3K). + static const int startSlowingDownAfter = 500; + static const int slowdown = 750; + int i = (m_lastMatchCount / startSlowingDownAfter); + m_nextInvalidateAfter += i * slowdown; + + invalidateArea(InvalidateScrollbar); + } +} + +void WebFrameImpl::clearPasswordListeners() +{ + deleteAllValues(m_passwordListeners); + m_passwordListeners.clear(); +} + +void WebFrameImpl::loadJavaScriptURL(const KURL& url) +{ + // This is copied from FrameLoader::executeIfJavaScriptURL. Unfortunately, + // we cannot just use that method since it is private, and it also doesn't + // quite behave as we require it to for bookmarklets. The key difference is + // that we need to suppress loading the string result from evaluating the JS + // URL if executing the JS URL resulted in a location change. We also allow + // a JS URL to be loaded even if scripts on the page are otherwise disabled. + + if (!m_frame->document() || !m_frame->page()) + return; + + String script = decodeURLEscapeSequences(url.string().substring(strlen("javascript:"))); + ScriptValue result = m_frame->script()->executeScript(script, true); + + String scriptResult; + if (!result.getString(scriptResult)) + return; + + SecurityOrigin* securityOrigin = m_frame->document()->securityOrigin(); + + if (!m_frame->redirectScheduler()->locationChangePending()) { + m_frame->loader()->stopAllLoaders(); + m_frame->loader()->begin(m_frame->loader()->url(), true, securityOrigin); + m_frame->loader()->write(scriptResult); + m_frame->loader()->end(); + } +} + +} // namespace WebKit diff --git a/webkit/api/src/WebFrameImpl.h b/webkit/api/src/WebFrameImpl.h new file mode 100644 index 0000000..8a3772c --- /dev/null +++ b/webkit/api/src/WebFrameImpl.h @@ -0,0 +1,376 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WebFrameImpl_h +#define WebFrameImpl_h + +#include "Frame.h" +#include "FrameLoaderClientImpl.h" +#include "PlatformString.h" +// FIXME: remove this relative path once consumers from glue are removed. +#include "../public/WebFrame.h" +#include <wtf/OwnPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { +class HistoryItem; +class KURL; +class Node; +class Range; +class SubstituteData; +struct WindowFeatures; +} + +namespace WebKit { +class ChromePrintContext; +class PasswordAutocompleteListener; +class WebDataSourceImpl; +class WebFrameClient; +class WebView; +class WebViewImpl; + +// Implementation of WebFrame, note that this is a reference counted object. +class WebFrameImpl : public WebFrame, public RefCounted<WebFrameImpl> { +public: + // WebFrame methods: + virtual WebString name() const; + virtual WebURL url() const; + virtual WebURL favIconURL() const; + virtual WebURL openSearchDescriptionURL() const; + virtual WebSize scrollOffset() const; + virtual WebSize contentsSize() const; + virtual int contentsPreferredWidth() const; + virtual bool hasVisibleContent() const; + virtual WebView* view() const; + virtual WebFrame* opener() const; + virtual WebFrame* parent() const; + virtual WebFrame* top() const; + virtual WebFrame* firstChild() const; + virtual WebFrame* lastChild() const; + virtual WebFrame* nextSibling() const; + virtual WebFrame* previousSibling() const; + virtual WebFrame* traverseNext(bool wrap) const; + virtual WebFrame* traversePrevious(bool wrap) const; + virtual WebFrame* findChildByName(const WebString&) const; + virtual WebFrame* findChildByExpression(const WebString&) const; + virtual void forms(WebVector<WebForm>&) const; + virtual WebSecurityOrigin securityOrigin() const; + virtual void grantUniversalAccess(); + virtual NPObject* windowObject() const; + virtual void bindToWindowObject(const WebString& name, NPObject*); + virtual void executeScript(const WebScriptSource&); + virtual void executeScriptInNewContext( + const WebScriptSource* sources, unsigned numSources, int extensionGroup); + virtual void executeScriptInIsolatedWorld( + int worldId, const WebScriptSource* sources, unsigned numSources, + int extensionGroup); + virtual void addMessageToConsole(const WebConsoleMessage&); + virtual void collectGarbage(); +#if WEBKIT_USING_V8 + virtual v8::Local<v8::Context> mainWorldScriptContext() const; +#endif + virtual bool insertStyleText(const WebString& css, const WebString& id); + virtual void reload(); + virtual void loadRequest(const WebURLRequest&); + virtual void loadHistoryItem(const WebHistoryItem&); + virtual void loadData( + const WebData&, const WebString& mimeType, const WebString& textEncoding, + const WebURL& baseURL, const WebURL& unreachableURL, bool replace); + virtual void loadHTMLString( + const WebData& html, const WebURL& baseURL, const WebURL& unreachableURL, + bool replace); + virtual bool isLoading() const; + virtual void stopLoading(); + virtual WebDataSource* provisionalDataSource() const; + virtual WebDataSource* dataSource() const; + virtual WebHistoryItem previousHistoryItem() const; + virtual WebHistoryItem currentHistoryItem() const; + virtual void enableViewSourceMode(bool enable); + virtual bool isViewSourceModeEnabled() const; + virtual void setReferrerForRequest(WebURLRequest&, const WebURL& referrer); + virtual void dispatchWillSendRequest(WebURLRequest&); + virtual void commitDocumentData(const char* data, size_t length); + virtual unsigned unloadListenerCount() const; + virtual bool isProcessingUserGesture() const; + virtual bool willSuppressOpenerInNewFrame() const; + virtual void replaceSelection(const WebString&); + virtual void insertText(const WebString&); + virtual void setMarkedText(const WebString&, unsigned location, unsigned length); + virtual void unmarkText(); + virtual bool hasMarkedText() const; + virtual WebRange markedRange() const; + virtual bool executeCommand(const WebString&); + virtual bool executeCommand(const WebString&, const WebString& value); + virtual bool isCommandEnabled(const WebString&) const; + virtual void enableContinuousSpellChecking(bool); + virtual bool isContinuousSpellCheckingEnabled() const; + virtual bool hasSelection() const; + virtual WebRange selectionRange() const; + virtual WebString selectionAsText() const; + virtual WebString selectionAsMarkup() const; + virtual int printBegin(const WebSize& pageSize); + virtual float printPage(int pageToPrint, WebCanvas*); + virtual float getPrintPageShrink(int page); + virtual void printEnd(); + virtual bool find( + int identifier, const WebString& searchText, const WebFindOptions&, + bool wrapWithinFrame, WebRect* selectionRect); + virtual void stopFinding(bool clearSelection); + virtual void scopeStringMatches( + int identifier, const WebString& searchText, const WebFindOptions&, + bool reset); + virtual void cancelPendingScopingEffort(); + virtual void increaseMatchCount(int count, int identifier); + virtual void resetMatchCount(); + virtual WebURL completeURL(const WebString& url) const; + virtual WebString contentAsText(size_t maxChars) const; + virtual WebString contentAsMarkup() const; + + static PassRefPtr<WebFrameImpl> create(WebFrameClient* client); + ~WebFrameImpl(); + + static int liveObjectCount() { + return m_liveObjectCount; + } + + // Called by the WebViewImpl to initialize its main frame: + void initializeAsMainFrame(WebViewImpl*); + + PassRefPtr<WebCore::Frame> createChildFrame( + const WebCore::FrameLoadRequest&, WebCore::HTMLFrameOwnerElement*); + + void layout(); + void paint(WebCanvas*, const WebRect&); + void createFrameView(); + + static WebFrameImpl* fromFrame(WebCore::Frame* frame); + + WebViewImpl* viewImpl() const; + + WebCore::Frame* frame() const { return m_frame; } + WebCore::FrameView* frameView() const { return m_frame ? m_frame->view() : 0; } + + // Getters for the impls corresponding to Get(Provisional)DataSource. They + // may return NULL if there is no corresponding data source. + WebDataSourceImpl* dataSourceImpl() const; + WebDataSourceImpl* provisionalDataSourceImpl() const; + + // Returns which frame has an active match. This function should only be + // called on the main frame, as it is the only frame keeping track. Returned + // value can be NULL if no frame has an active match. + const WebFrameImpl* activeMatchFrame() const { return m_activeMatchFrame; } + + // When a Find operation ends, we want to set the selection to what was active + // and set focus to the first focusable node we find (starting with the first + // node in the matched range and going up the inheritance chain). If we find + // nothing to focus we focus the first focusable node in the range. This + // allows us to set focus to a link (when we find text inside a link), which + // allows us to navigate by pressing Enter after closing the Find box. + void setFindEndstateFocusAndSelection(); + + void didFail(const WebCore::ResourceError&, bool wasProvisional); + + // Sets whether the WebFrameImpl allows its document to be scrolled. + // If the parameter is true, allow the document to be scrolled. + // Otherwise, disallow scrolling. + void setAllowsScrolling(bool); + + // Registers a listener for the specified user name input element. The + // listener will receive notifications for blur and when autocomplete should + // be triggered. + // The WebFrameImpl becomes the owner of the passed listener. + void registerPasswordListener( + PassRefPtr<WebCore::HTMLInputElement>, + PasswordAutocompleteListener*); + + // Returns the password autocomplete listener associated with the passed + // user name input element, or NULL if none available. + // Note that the returned listener is owner by the WebFrameImpl and should not + // be kept around as it is deleted when the page goes away. + PasswordAutocompleteListener* getPasswordListener(WebCore::HTMLInputElement*); + + WebFrameClient* client() const { return m_clientHandle->client(); } + void dropClient() { m_clientHandle->dropClient(); } + +private: + class DeferredScopeStringMatches; + friend class DeferredScopeStringMatches; + friend class FrameLoaderClientImpl; + + // A weak reference to the WebFrameClient. Each WebFrame in the hierarchy + // owns a reference to a ClientHandle. When the main frame is destroyed, it + // clears the WebFrameClient. + class ClientHandle : public RefCounted<ClientHandle> { + public: + static PassRefPtr<ClientHandle> create(WebFrameClient* client) + { + return adoptRef(new ClientHandle(client)); + } + WebFrameClient* client() { return m_client; } + void dropClient() { m_client = NULL; } + private: + ClientHandle(WebFrameClient* client) : m_client(client) {} + WebFrameClient* m_client; + }; + + // A bit mask specifying area of the frame to invalidate. + enum AreaToInvalidate { + InvalidateNothing, + InvalidateContentArea, + InvalidateScrollbar, // Vertical scrollbar only. + InvalidateAll // Both content area and the scrollbar. + }; + + WebFrameImpl(PassRefPtr<ClientHandle>); + + // Informs the WebFrame that the Frame is being closed, called by the + // WebFrameLoaderClient + void closing(); + + // Notifies the delegate about a new selection rect. + void reportFindInPageSelection( + const WebRect& selectionRect, int activeMatchOrdinal, int identifier); + + // Invalidates a certain area within the frame. + void invalidateArea(AreaToInvalidate); + + // Add a WebKit TextMatch-highlight marker to nodes in a range. + void addMarker(WebCore::Range*, bool activeMatch); + + // Sets the markers within a range as active or inactive. + void setMarkerActive(WebCore::Range*, bool active); + + // Returns the ordinal of the first match in the frame specified. This + // function enumerates the frames, starting with the main frame and up to (but + // not including) the frame passed in as a parameter and counts how many + // matches have been found. + int ordinalOfFirstMatchForFrame(WebFrameImpl*) const; + + // Determines whether the scoping effort is required for a particular frame. + // It is not necessary if the frame is invisible, for example, or if this + // is a repeat search that already returned nothing last time the same prefix + // was searched. + bool shouldScopeMatches(const WebCore::String& searchText); + + // Queue up a deferred call to scopeStringMatches. + void scopeStringMatchesSoon( + int identifier, const WebString& searchText, const WebFindOptions&, + bool reset); + + // Called by a DeferredScopeStringMatches instance. + void callScopeStringMatches( + DeferredScopeStringMatches*, int identifier, const WebString& searchText, + const WebFindOptions&, bool reset); + + // Determines whether to invalidate the content area and scrollbar. + void invalidateIfNecessary(); + + // Clears the map of password listeners. + void clearPasswordListeners(); + + void loadJavaScriptURL(const WebCore::KURL&); + + // Used to check for leaks of this object. + static int m_liveObjectCount; + + FrameLoaderClientImpl m_frameLoaderClient; + + RefPtr<ClientHandle> m_clientHandle; + + // This is a weak pointer to our corresponding WebCore frame. A reference to + // ourselves is held while frame_ is valid. See our Closing method. + WebCore::Frame* m_frame; + + // A way for the main frame to keep track of which frame has an active + // match. Should be NULL for all other frames. + WebFrameImpl* m_activeMatchFrame; + + // The range of the active match for the current frame. + RefPtr<WebCore::Range> m_activeMatch; + + // The index of the active match. + int m_activeMatchIndex; + + // This flag is used by the scoping effort to determine if we need to figure + // out which rectangle is the active match. Once we find the active + // rectangle we clear this flag. + bool m_locatingActiveRect; + + // The scoping effort can time out and we need to keep track of where we + // ended our last search so we can continue from where we left of. + RefPtr<WebCore::Range> m_resumeScopingFromRange; + + // Keeps track of the last string this frame searched for. This is used for + // short-circuiting searches in the following scenarios: When a frame has + // been searched and returned 0 results, we don't need to search that frame + // again if the user is just adding to the search (making it more specific). + WebCore::String m_lastSearchString; + + // Keeps track of how many matches this frame has found so far, so that we + // don't loose count between scoping efforts, and is also used (in conjunction + // with m_lastSearchString and m_scopingComplete) to figure out if we need to + // search the frame again. + int m_lastMatchCount; + + // This variable keeps a cumulative total of matches found so far for ALL the + // frames on the page, and is only incremented by calling IncreaseMatchCount + // (on the main frame only). It should be -1 for all other frames. + size_t m_totalMatchCount; + + // This variable keeps a cumulative total of how many frames are currently + // scoping, and is incremented/decremented on the main frame only. + // It should be -1 for all other frames. + int m_framesScopingCount; + + // Keeps track of whether the scoping effort was completed (the user may + // interrupt it before it completes by submitting a new search). + bool m_scopingComplete; + + // Keeps track of when the scoping effort should next invalidate the scrollbar + // and the frame area. + int m_nextInvalidateAfter; + + // A list of all of the pending calls to scopeStringMatches. + Vector<DeferredScopeStringMatches*> m_deferredScopingWork; + + // Valid between calls to BeginPrint() and EndPrint(). Containts the print + // information. Is used by PrintPage(). + OwnPtr<ChromePrintContext> m_printContext; + + // The input fields that are interested in edit events and their associated + // listeners. + typedef HashMap<RefPtr<WebCore::HTMLInputElement>, + PasswordAutocompleteListener*> PasswordListenerMap; + PasswordListenerMap m_passwordListeners; +}; + +} // namespace WebKit + +#endif diff --git a/webkit/api/src/WebStorageEventDispatcherImpl.cpp b/webkit/api/src/WebStorageEventDispatcherImpl.cpp index a6da503..2e6df47 100644 --- a/webkit/api/src/WebStorageEventDispatcherImpl.cpp +++ b/webkit/api/src/WebStorageEventDispatcherImpl.cpp @@ -35,10 +35,10 @@ #include "SecurityOrigin.h" -extern const char* pageGroupName; - namespace WebKit { +extern const char* pageGroupName; + WebStorageEventDispatcher* WebStorageEventDispatcher::create() { return new WebStorageEventDispatcherImpl(); diff --git a/webkit/api/src/WebViewImpl.cpp b/webkit/api/src/WebViewImpl.cpp new file mode 100644 index 0000000..3aa2279 --- /dev/null +++ b/webkit/api/src/WebViewImpl.cpp @@ -0,0 +1,1767 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebViewImpl.h" + +#include "AutocompletePopupMenuClient.h" +#include "AXObjectCache.h" +#include "CSSStyleSelector.h" +#include "CSSValueKeywords.h" +#include "Cursor.h" +#include "Document.h" +#include "DocumentLoader.h" +#include "DOMUtilitiesPrivate.h" +#include "DragController.h" +#include "DragData.h" +#include "Editor.h" +#include "EventHandler.h" +#include "FocusController.h" +#include "FontDescription.h" +#include "FrameLoader.h" +#include "FrameTree.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "HTMLNames.h" +#include "HTMLInputElement.h" +#include "HTMLMediaElement.h" +#include "HitTestResult.h" +#include "Image.h" +#include "InspectorController.h" +#include "IntRect.h" +#include "KeyboardCodes.h" +#include "KeyboardEvent.h" +#include "MIMETypeRegistry.h" +#include "NodeRenderStyle.h" +#include "Page.h" +#include "PageGroup.h" +#include "Pasteboard.h" +#include "PlatformContextSkia.h" +#include "PlatformKeyboardEvent.h" +#include "PlatformMouseEvent.h" +#include "PlatformWheelEvent.h" +#include "PluginInfoStore.h" +#include "PopupMenuChromium.h" +#include "PopupMenuClient.h" +#include "RenderView.h" +#include "ResourceHandle.h" +#include "SecurityOrigin.h" +#include "SelectionController.h" +#include "Settings.h" +#include "TypingCommand.h" +#include "WebAccessibilityObject.h" +#include "WebDragData.h" +#include "WebFrameImpl.h" +#include "WebInputEvent.h" +#include "WebInputEventConversion.h" +#include "WebMediaPlayerAction.h" +#include "WebNode.h" +#include "WebPoint.h" +#include "WebPopupMenuImpl.h" +#include "WebRect.h" +#include "WebSettingsImpl.h" +#include "WebString.h" +#include "WebVector.h" +#include "WebViewClient.h" + +#if PLATFORM(WIN_OS) +#include "KeyboardCodesWin.h" +#include "RenderThemeChromiumWin.h" +#else +#include "KeyboardCodesPosix.h" +#include "RenderTheme.h" +#endif + +// FIXME +#include "webkit/glue/webdevtoolsagent_impl.h" + +// Get rid of WTF's pow define so we can use std::pow. +#undef pow +#include <cmath> // for std::pow + +using namespace WebCore; + +namespace WebKit { + +// Change the text zoom level by kTextSizeMultiplierRatio each time the user +// zooms text in or out (ie., change by 20%). The min and max values limit +// text zoom to half and 3x the original text size. These three values match +// those in Apple's port in WebKit/WebKit/WebView/WebView.mm +static const double textSizeMultiplierRatio = 1.2; +static const double minTextSizeMultiplier = 0.5; +static const double maxTextSizeMultiplier = 3.0; + +// The group name identifies a namespace of pages. Page group is used on OSX +// for some programs that use HTML views to display things that don't seem like +// web pages to the user (so shouldn't have visited link coloring). We only use +// one page group. +const char* pageGroupName = "default"; + +// Ensure that the WebDragOperation enum values stay in sync with the original +// DragOperation constants. +#define COMPILE_ASSERT_MATCHING_ENUM(coreName) \ + COMPILE_ASSERT(int(coreName) == int(Web##coreName), dummy##coreName) +COMPILE_ASSERT_MATCHING_ENUM(DragOperationNone); +COMPILE_ASSERT_MATCHING_ENUM(DragOperationCopy); +COMPILE_ASSERT_MATCHING_ENUM(DragOperationLink); +COMPILE_ASSERT_MATCHING_ENUM(DragOperationGeneric); +COMPILE_ASSERT_MATCHING_ENUM(DragOperationPrivate); +COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove); +COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete); +COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery); + +// Note that focusOnShow is false so that the autocomplete popup is shown not +// activated. We need the page to still have focus so the user can keep typing +// while the popup is showing. +static const PopupContainerSettings autocompletePopupSettings = { + false, // focusOnShow + false, // setTextOnIndexChange + false, // acceptOnAbandon + true, // loopSelectionNavigation + true, // restrictWidthOfListBox. Same as other browser (Fx, IE, and safari) + // For autocomplete, we use the direction of the input field as the direction + // of the popup items. The main reason is to keep the display of items in + // drop-down the same as the items in the input field. + PopupContainerSettings::DOMElementDirection, +}; + +// WebView ---------------------------------------------------------------- + +WebView* WebView::create(WebViewClient* client) +{ + return new WebViewImpl(client); +} + +void WebView::updateVisitedLinkState(unsigned long long linkHash) +{ + Page::visitedStateChanged(PageGroup::pageGroup(pageGroupName), linkHash); +} + +void WebView::resetVisitedLinkState() +{ + Page::allVisitedStateChanged(PageGroup::pageGroup(pageGroupName)); +} + +void WebViewImpl::initializeMainFrame(WebFrameClient* frameClient) { + // NOTE: The WebFrameImpl takes a reference to itself within InitMainFrame + // and releases that reference once the corresponding Frame is destroyed. + RefPtr<WebFrameImpl> frame = WebFrameImpl::create(frameClient); + + frame->initializeAsMainFrame(this); + + if (m_client) { + WebDevToolsAgentClient* toolsClient = m_client->devToolsAgentClient(); + if (toolsClient) + m_devToolsAgent.set(new WebDevToolsAgentImpl(this, toolsClient)); + } + + // Restrict the access to the local file system + // (see WebView.mm WebView::_commonInitializationWithFrameName). + SecurityOrigin::setLocalLoadPolicy(SecurityOrigin::AllowLocalLoadsForLocalOnly); +} + +WebViewImpl::WebViewImpl(WebViewClient* client) + : m_client(client) + , m_backForwardListClientImpl(this) + , m_chromeClientImpl(this) + , m_contextMenuClientImpl(this) + , m_dragClientImpl(this) + , m_editorClientImpl(this) + , m_inspectorClientImpl(this) + , m_observedNewNavigation(false) +#ifndef NDEBUG + , m_newNavigationLoader(0) +#endif + , m_zoomLevel(0) + , m_contextMenuAllowed(false) + , m_doingDragAndDrop(false) + , m_ignoreInputEvents(false) + , m_suppressNextKeypressEvent(false) + , m_initialNavigationPolicy(WebNavigationPolicyIgnore) + , m_imeAcceptEvents(true) + , m_dragTargetDispatch(false) + , m_dragIdentity(0) + , m_dropEffect(DropEffectDefault) + , m_operationsAllowed(WebDragOperationNone) + , m_dragOperation(WebDragOperationNone) + , m_autocompletePopupShowing(false) + , m_isTransparent(false) + , m_tabsToLinks(false) +{ + // WebKit/win/WebView.cpp does the same thing, except they call the + // KJS specific wrapper around this method. We need to have threading + // initialized because CollatorICU requires it. + WTF::initializeThreading(); + + // set to impossible point so we always get the first mouse pos + m_lastMousePosition = WebPoint(-1, -1); + + // the page will take ownership of the various clients + m_page.set(new Page(&m_chromeClientImpl, + &m_contextMenuClientImpl, + &m_editorClientImpl, + &m_dragClientImpl, + &m_inspectorClientImpl, + 0)); + + m_page->backForwardList()->setClient(&m_backForwardListClientImpl); + m_page->setGroupName(pageGroupName); +} + +WebViewImpl::~WebViewImpl() +{ + ASSERT(!m_page); +} + +RenderTheme* WebViewImpl::theme() const +{ + return m_page.get() ? m_page->theme() : RenderTheme::defaultTheme().get(); +} + +WebFrameImpl* WebViewImpl::mainFrameImpl() +{ + return m_page.get() ? WebFrameImpl::fromFrame(m_page->mainFrame()) : 0; +} + +bool WebViewImpl::tabKeyCyclesThroughElements() const +{ + ASSERT(m_page.get()); + return m_page->tabKeyCyclesThroughElements(); +} + +void WebViewImpl::setTabKeyCyclesThroughElements(bool value) +{ + if (m_page) + m_page->setTabKeyCyclesThroughElements(value); +} + +void WebViewImpl::mouseMove(const WebMouseEvent& event) +{ + if (!mainFrameImpl() || !mainFrameImpl()->frameView()) + return; + + m_lastMousePosition = WebPoint(event.x, event.y); + + // We call mouseMoved here instead of handleMouseMovedEvent because we need + // our ChromeClientImpl to receive changes to the mouse position and + // tooltip text, and mouseMoved handles all of that. + mainFrameImpl()->frame()->eventHandler()->mouseMoved( + PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event)); +} + +void WebViewImpl::mouseLeave(const WebMouseEvent& event) +{ + // This event gets sent as the main frame is closing. In that case, just + // ignore it. + if (!mainFrameImpl() || !mainFrameImpl()->frameView()) + return; + + m_client->setMouseOverURL(WebURL()); + + mainFrameImpl()->frame()->eventHandler()->handleMouseMoveEvent( + PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event)); +} + +void WebViewImpl::mouseDown(const WebMouseEvent& event) +{ + if (!mainFrameImpl() || !mainFrameImpl()->frameView()) + return; + + m_lastMouseDownPoint = WebPoint(event.x, event.y); + + // If a text field that has focus is clicked again, we should display the + // autocomplete popup. + RefPtr<Node> clickedNode; + if (event.button == WebMouseEvent::ButtonLeft) { + RefPtr<Node> focusedNode = focusedWebCoreNode(); + if (focusedNode.get() && toHTMLInputElement(focusedNode.get())) { + IntPoint point(event.x, event.y); + point = m_page->mainFrame()->view()->windowToContents(point); + HitTestResult result(point); + result = m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, false); + if (result.innerNonSharedNode() == focusedNode) { + // Already focused text field was clicked, let's remember this. If + // focus has not changed after the mouse event is processed, we'll + // trigger the autocomplete. + clickedNode = focusedNode; + } + } + } + + mainFrameImpl()->frame()->eventHandler()->handleMousePressEvent( + PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event)); + + if (clickedNode.get() && clickedNode == focusedWebCoreNode()) { + // Focus has not changed, show the autocomplete popup. + static_cast<EditorClientImpl*>(m_page->editorClient())-> + showFormAutofillForNode(clickedNode.get()); + } + + // Dispatch the contextmenu event regardless of if the click was swallowed. + // On Windows, we handle it on mouse up, not down. +#if PLATFORM(DARWIN) + if (event.button == WebMouseEvent::ButtonRight + || (event.button == WebMouseEvent::ButtonLeft + && event.modifiers & WebMouseEvent::ControlKey)) + mouseContextMenu(event); +#elif PLATFORM(LINUX) + if (event.button == WebMouseEvent::ButtonRight) + mouseContextMenu(event); +#endif +} + +void WebViewImpl::mouseContextMenu(const WebMouseEvent& event) +{ + if (!mainFrameImpl() || !mainFrameImpl()->frameView()) + return; + + m_page->contextMenuController()->clearContextMenu(); + + PlatformMouseEventBuilder pme(mainFrameImpl()->frameView(), event); + + // Find the right target frame. See issue 1186900. + HitTestResult result = hitTestResultForWindowPos(pme.pos()); + Frame* targetFrame; + if (result.innerNonSharedNode()) + targetFrame = result.innerNonSharedNode()->document()->frame(); + else + targetFrame = m_page->focusController()->focusedOrMainFrame(); + +#if PLATFORM(WIN_OS) + targetFrame->view()->setCursor(pointerCursor()); +#endif + + m_contextMenuAllowed = true; + targetFrame->eventHandler()->sendContextMenuEvent(pme); + m_contextMenuAllowed = false; + // Actually showing the context menu is handled by the ContextMenuClient + // implementation... +} + +void WebViewImpl::mouseUp(const WebMouseEvent& event) +{ + if (!mainFrameImpl() || !mainFrameImpl()->frameView()) + return; + +#if PLATFORM(LINUX) + // If the event was a middle click, attempt to copy text into the focused + // frame. We execute this before we let the page have a go at the event + // because the page may change what is focused during in its event handler. + // + // This code is in the mouse up handler. There is some debate about putting + // this here, as opposed to the mouse down handler. + // xterm: pastes on up. + // GTK: pastes on down. + // Firefox: pastes on up. + // Midori: couldn't paste at all with 0.1.2 + // + // There is something of a webcompat angle to this well, as highlighted by + // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on + // down then the text is pasted just before the onclick handler runs and + // clears the text box. So it's important this happens after the + // handleMouseReleaseEvent() earlier in this function + if (event.button == WebMouseEvent::ButtonMiddle) { + Frame* focused = focusedWebCoreFrame(); + IntPoint clickPoint(m_lastMouseDownPoint.x, m_lastMouseDownPoint.y); + clickPoint = m_page->mainFrame()->view()->windowToContents(clickPoint); + HitTestResult hitTestResult = + focused->eventHandler()->hitTestResultAtPoint(clickPoint, false, false, + ShouldHitTestScrollbars); + // We don't want to send a paste when middle clicking a scroll bar or a + // link (which will navigate later in the code). + if (!hitTestResult.scrollbar() && !hitTestResult.isLiveLink() && focused) { + Editor* editor = focused->editor(); + Pasteboard* pasteboard = Pasteboard::generalPasteboard(); + bool oldSelectionMode = pasteboard->isSelectionMode(); + pasteboard->setSelectionMode(true); + editor->command(AtomicString("Paste")).execute(); + pasteboard->setSelectionMode(oldSelectionMode); + } + } +#endif + + mouseCaptureLost(); + mainFrameImpl()->frame()->eventHandler()->handleMouseReleaseEvent( + PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event)); + +#if PLATFORM(WIN_OS) + // Dispatch the contextmenu event regardless of if the click was swallowed. + // On Mac/Linux, we handle it on mouse down, not up. + if (event.button == WebMouseEvent::ButtonRight) + mouseContextMenu(event); +#endif +} + +void WebViewImpl::mouseWheel(const WebMouseWheelEvent& event) +{ + PlatformWheelEventBuilder platformEvent(mainFrameImpl()->frameView(), event); + mainFrameImpl()->frame()->eventHandler()->handleWheelEvent(platformEvent); +} + +bool WebViewImpl::keyEvent(const WebKeyboardEvent& event) +{ + ASSERT((event.type == WebInputEvent::RawKeyDown) + || (event.type == WebInputEvent::KeyDown) + || (event.type == WebInputEvent::KeyUp)); + + // Please refer to the comments explaining the m_suppressNextKeypressEvent + // member. + // The m_suppressNextKeypressEvent is set if the KeyDown is handled by + // Webkit. A keyDown event is typically associated with a keyPress(char) + // event and a keyUp event. We reset this flag here as this is a new keyDown + // event. + m_suppressNextKeypressEvent = false; + + // Give autocomplete a chance to consume the key events it is interested in. + if (autocompleteHandleKeyEvent(event)) + return true; + + Frame* frame = focusedWebCoreFrame(); + if (!frame) + return false; + + EventHandler* handler = frame->eventHandler(); + if (!handler) + return keyEventDefault(event); + +#if PLATFORM(WIN_OS) || PLATFORM(LINUX) + if (((event.modifiers == 0) && (event.windowsKeyCode == VKEY_APPS)) + || ((event.modifiers == WebInputEvent::ShiftKey) && (event.windowsKeyCode == VKEY_F10))) { + sendContextMenuEvent(event); + return true; + } +#endif + + // It's not clear if we should continue after detecting a capslock keypress. + // I'll err on the side of continuing, which is the pre-existing behaviour. + if (event.windowsKeyCode == VKEY_CAPITAL) + handler->capsLockStateMayHaveChanged(); + + PlatformKeyboardEventBuilder evt(event); + + if (handler->keyEvent(evt)) { + if (WebInputEvent::RawKeyDown == event.type && !evt.isSystemKey()) + m_suppressNextKeypressEvent = true; + return true; + } + + return keyEventDefault(event); +} + +bool WebViewImpl::autocompleteHandleKeyEvent(const WebKeyboardEvent& event) +{ + if (!m_autocompletePopupShowing + // Home and End should be left to the text field to process. + || event.windowsKeyCode == VKEY_HOME + || event.windowsKeyCode == VKEY_END) + return false; + + // Pressing delete triggers the removal of the selected suggestion from the DB. + if (event.windowsKeyCode == VKEY_DELETE + && m_autocompletePopup->selectedIndex() != -1) { + Node* node = focusedWebCoreNode(); + if (!node || (node->nodeType() != Node::ELEMENT_NODE)) { + ASSERT_NOT_REACHED(); + return false; + } + Element* element = static_cast<Element*>(node); + if (!element->hasLocalName(HTMLNames::inputTag)) { + ASSERT_NOT_REACHED(); + return false; + } + + int selectedIndex = m_autocompletePopup->selectedIndex(); + HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(element); + WebString name = inputElement->name(); + WebString value = m_autocompletePopupClient->itemText(selectedIndex); + m_client->removeAutofillSuggestions(name, value); + // Update the entries in the currently showing popup to reflect the + // deletion. + m_autocompletePopupClient->removeItemAtIndex(selectedIndex); + refreshAutofillPopup(); + return false; + } + + if (!m_autocompletePopup->isInterestedInEventForKey(event.windowsKeyCode)) + return false; + + if (m_autocompletePopup->handleKeyEvent(PlatformKeyboardEventBuilder(event))) { + // We need to ignore the next Char event after this otherwise pressing + // enter when selecting an item in the menu will go to the page. + if (WebInputEvent::RawKeyDown == event.type) + m_suppressNextKeypressEvent = true; + return true; + } + + return false; +} + +bool WebViewImpl::charEvent(const WebKeyboardEvent& event) +{ + ASSERT(event.type == WebInputEvent::Char); + + // Please refer to the comments explaining the m_suppressNextKeypressEvent + // member. The m_suppressNextKeypressEvent is set if the KeyDown is + // handled by Webkit. A keyDown event is typically associated with a + // keyPress(char) event and a keyUp event. We reset this flag here as it + // only applies to the current keyPress event. + if (m_suppressNextKeypressEvent) { + m_suppressNextKeypressEvent = false; + return true; + } + + Frame* frame = focusedWebCoreFrame(); + if (!frame) + return false; + + EventHandler* handler = frame->eventHandler(); + if (!handler) + return keyEventDefault(event); + + PlatformKeyboardEventBuilder evt(event); + if (!evt.isCharacterKey()) + return true; + + // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to + // the eventHandler::keyEvent. We mimic this behavior on all platforms since + // for now we are converting other platform's key events to windows key + // events. + if (evt.isSystemKey()) + return handler->handleAccessKey(evt); + + if (!handler->keyEvent(evt)) + return keyEventDefault(event); + + return true; +} + +// The WebViewImpl::SendContextMenuEvent function is based on the Webkit +// function +// bool WebView::handleContextMenuEvent(WPARAM wParam, LPARAM lParam) in +// webkit\webkit\win\WebView.cpp. The only significant change in this +// function is the code to convert from a Keyboard event to the Right +// Mouse button up event. +// +// This function is an ugly copy/paste and should be cleaned up when the +// WebKitWin version is cleaned: https://bugs.webkit.org/show_bug.cgi?id=20438 +#if PLATFORM(WIN_OS) || PLATFORM(LINUX) +// FIXME: implement on Mac +bool WebViewImpl::sendContextMenuEvent(const WebKeyboardEvent& event) +{ + static const int kContextMenuMargin = 1; + Frame* mainFrameImpl = page()->mainFrame(); + FrameView* view = mainFrameImpl->view(); + if (!view) + return false; + + IntPoint coords(-1, -1); +#if PLATFORM(WIN_OS) + int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT); +#else + int rightAligned = 0; +#endif + IntPoint location; + + // The context menu event was generated from the keyboard, so show the + // context menu by the current selection. + Position start = mainFrameImpl->selection()->selection().start(); + Position end = mainFrameImpl->selection()->selection().end(); + + if (!start.node() || !end.node()) { + location = IntPoint( + rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin, + kContextMenuMargin); + } else { + RenderObject* renderer = start.node()->renderer(); + if (!renderer) + return false; + + RefPtr<Range> selection = mainFrameImpl->selection()->toNormalizedRange(); + IntRect firstRect = mainFrameImpl->firstRectForRange(selection.get()); + + int x = rightAligned ? firstRect.right() : firstRect.x(); + location = IntPoint(x, firstRect.bottom()); + } + + location = view->contentsToWindow(location); + // FIXME: The IntSize(0, -1) is a hack to get the hit-testing to result in + // the selected element. Ideally we'd have the position of a context menu + // event be separate from its target node. + coords = location + IntSize(0, -1); + + // The contextMenuController() holds onto the last context menu that was + // popped up on the page until a new one is created. We need to clear + // this menu before propagating the event through the DOM so that we can + // detect if we create a new menu for this event, since we won't create + // a new menu if the DOM swallows the event and the defaultEventHandler does + // not run. + page()->contextMenuController()->clearContextMenu(); + + Frame* focusedFrame = page()->focusController()->focusedOrMainFrame(); + focusedFrame->view()->setCursor(pointerCursor()); + WebMouseEvent mouseEvent; + mouseEvent.button = WebMouseEvent::ButtonRight; + mouseEvent.x = coords.x(); + mouseEvent.y = coords.y(); + mouseEvent.type = WebInputEvent::MouseUp; + + PlatformMouseEventBuilder platformEvent(view, mouseEvent); + + m_contextMenuAllowed = true; + bool handled = focusedFrame->eventHandler()->sendContextMenuEvent(platformEvent); + m_contextMenuAllowed = false; + return handled; +} +#endif + +bool WebViewImpl::keyEventDefault(const WebKeyboardEvent& event) +{ + Frame* frame = focusedWebCoreFrame(); + if (!frame) + return false; + + switch (event.type) { + case WebInputEvent::Char: + if (event.windowsKeyCode == VKEY_SPACE) { + int keyCode = ((event.modifiers & WebInputEvent::ShiftKey) ? VKEY_PRIOR : VKEY_NEXT); + return scrollViewWithKeyboard(keyCode, event.modifiers); + } + break; + case WebInputEvent::RawKeyDown: + if (event.modifiers == WebInputEvent::ControlKey) { + switch (event.windowsKeyCode) { + case 'A': + focusedFrame()->executeCommand(WebString::fromUTF8("SelectAll")); + return true; + case VKEY_INSERT: + case 'C': + focusedFrame()->executeCommand(WebString::fromUTF8("Copy")); + return true; + // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl + // key combinations which affect scrolling. Safari is buggy in the + // sense that it scrolls the page for all Ctrl+scrolling key + // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc. + case VKEY_HOME: + case VKEY_END: + break; + default: + return false; + } + } + if (!event.isSystemKey && !(event.modifiers & WebInputEvent::ShiftKey)) + return scrollViewWithKeyboard(event.windowsKeyCode, event.modifiers); + break; + default: + break; + } + return false; +} + +bool WebViewImpl::scrollViewWithKeyboard(int keyCode, int modifiers) +{ + ScrollDirection scrollDirection; + ScrollGranularity scrollGranularity; + + switch (keyCode) { + case VKEY_LEFT: + scrollDirection = ScrollLeft; + scrollGranularity = ScrollByLine; + break; + case VKEY_RIGHT: + scrollDirection = ScrollRight; + scrollGranularity = ScrollByLine; + break; + case VKEY_UP: + scrollDirection = ScrollUp; + scrollGranularity = ScrollByLine; + break; + case VKEY_DOWN: + scrollDirection = ScrollDown; + scrollGranularity = ScrollByLine; + break; + case VKEY_HOME: + scrollDirection = ScrollUp; + scrollGranularity = ScrollByDocument; + break; + case VKEY_END: + scrollDirection = ScrollDown; + scrollGranularity = ScrollByDocument; + break; + case VKEY_PRIOR: // page up + scrollDirection = ScrollUp; + scrollGranularity = ScrollByPage; + break; + case VKEY_NEXT: // page down + scrollDirection = ScrollDown; + scrollGranularity = ScrollByPage; + break; + default: + return false; + } + + return propagateScroll(scrollDirection, scrollGranularity); +} + +bool WebViewImpl::propagateScroll(ScrollDirection scrollDirection, + ScrollGranularity scrollGranularity) +{ + Frame* frame = focusedWebCoreFrame(); + if (!frame) + return false; + + bool scrollHandled = + frame->eventHandler()->scrollOverflow(scrollDirection, + scrollGranularity); + Frame* currentFrame = frame; + while (!scrollHandled && currentFrame) { + scrollHandled = currentFrame->view()->scroll(scrollDirection, + scrollGranularity); + currentFrame = currentFrame->tree()->parent(); + } + return scrollHandled; +} + +Frame* WebViewImpl::focusedWebCoreFrame() +{ + return m_page.get() ? m_page->focusController()->focusedOrMainFrame() : 0; +} + +WebViewImpl* WebViewImpl::fromPage(Page* page) +{ + if (!page) + return 0; + + return static_cast<ChromeClientImpl*>(page->chrome()->client())->webview(); +} + +// WebWidget ------------------------------------------------------------------ + +void WebViewImpl::close() +{ + RefPtr<WebFrameImpl> mainFrameImpl; + + if (m_page.get()) { + // Initiate shutdown for the entire frameset. This will cause a lot of + // notifications to be sent. + if (m_page->mainFrame()) { + mainFrameImpl = WebFrameImpl::fromFrame(m_page->mainFrame()); + m_page->mainFrame()->loader()->frameDetached(); + } + m_page.clear(); + } + + // Should happen after m_page.reset(). + if (m_devToolsAgent.get()) + m_devToolsAgent.clear(); + + // We drop the client after the page has been destroyed to support the + // WebFrameClient::didDestroyScriptContext method. + if (mainFrameImpl) + mainFrameImpl->dropClient(); + + // Reset the delegate to prevent notifications being sent as we're being + // deleted. + m_client = 0; + + deref(); // Balances ref() acquired in WebView::create +} + +void WebViewImpl::resize(const WebSize& newSize) +{ + if (m_size == newSize) + return; + m_size = newSize; + + if (mainFrameImpl()->frameView()) { + mainFrameImpl()->frameView()->resize(m_size.width, m_size.height); + mainFrameImpl()->frame()->eventHandler()->sendResizeEvent(); + } + + if (m_client) { + WebRect damagedRect(0, 0, m_size.width, m_size.height); + m_client->didInvalidateRect(damagedRect); + } +} + +void WebViewImpl::layout() +{ + WebFrameImpl* webframe = mainFrameImpl(); + if (webframe) { + // In order for our child HWNDs (NativeWindowWidgets) to update properly, + // they need to be told that we are updating the screen. The problem is + // that the native widgets need to recalculate their clip region and not + // overlap any of our non-native widgets. To force the resizing, call + // setFrameRect(). This will be a quick operation for most frames, but + // the NativeWindowWidgets will update a proper clipping region. + FrameView* view = webframe->frameView(); + if (view) + view->setFrameRect(view->frameRect()); + + // setFrameRect may have the side-effect of causing existing page + // layout to be invalidated, so layout needs to be called last. + + webframe->layout(); + } +} + +void WebViewImpl::paint(WebCanvas* canvas, const WebRect& rect) +{ + WebFrameImpl* webframe = mainFrameImpl(); + if (webframe) + webframe->paint(canvas, rect); +} + +// FIXME: m_currentInputEvent should be removed once ChromeClient::show() can +// get the current-event information from WebCore. +const WebInputEvent* WebViewImpl::m_currentInputEvent = 0; + +bool WebViewImpl::handleInputEvent(const WebInputEvent& inputEvent) +{ + // If we've started a drag and drop operation, ignore input events until + // we're done. + if (m_doingDragAndDrop) + return true; + + if (m_ignoreInputEvents) + return true; + + // FIXME: Remove m_currentInputEvent. + // This only exists to allow ChromeClient::show() to know which mouse button + // triggered a window.open event. + // Safari must perform a similar hack, ours is in our WebKit glue layer + // theirs is in the application. This should go when WebCore can be fixed + // to pass more event information to ChromeClient::show() + m_currentInputEvent = &inputEvent; + + bool handled = true; + + // FIXME: WebKit seems to always return false on mouse events processing + // methods. For now we'll assume it has processed them (as we are only + // interested in whether keyboard events are processed). + switch (inputEvent.type) { + case WebInputEvent::MouseMove: + mouseMove(*static_cast<const WebMouseEvent*>(&inputEvent)); + break; + + case WebInputEvent::MouseLeave: + mouseLeave(*static_cast<const WebMouseEvent*>(&inputEvent)); + break; + + case WebInputEvent::MouseWheel: + mouseWheel(*static_cast<const WebMouseWheelEvent*>(&inputEvent)); + break; + + case WebInputEvent::MouseDown: + mouseDown(*static_cast<const WebMouseEvent*>(&inputEvent)); + break; + + case WebInputEvent::MouseUp: + mouseUp(*static_cast<const WebMouseEvent*>(&inputEvent)); + break; + + case WebInputEvent::RawKeyDown: + case WebInputEvent::KeyDown: + case WebInputEvent::KeyUp: + handled = keyEvent(*static_cast<const WebKeyboardEvent*>(&inputEvent)); + break; + + case WebInputEvent::Char: + handled = charEvent(*static_cast<const WebKeyboardEvent*>(&inputEvent)); + break; + + default: + handled = false; + } + + m_currentInputEvent = 0; + + return handled; +} + +void WebViewImpl::mouseCaptureLost() +{ +} + +void WebViewImpl::setFocus(bool enable) +{ + m_page->focusController()->setFocused(enable); + if (enable) { + // Note that we don't call setActive() when disabled as this cause extra + // focus/blur events to be dispatched. + m_page->focusController()->setActive(true); + m_imeAcceptEvents = true; + } else { + hideAutoCompletePopup(); + + // Clear focus on the currently focused frame if any. + if (!m_page.get()) + return; + + Frame* frame = m_page->mainFrame(); + if (!frame) + return; + + RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame(); + if (focusedFrame.get()) { + // Finish an ongoing composition to delete the composition node. + Editor* editor = focusedFrame->editor(); + if (editor && editor->hasComposition()) + editor->confirmComposition(); + m_imeAcceptEvents = false; + } + } +} + +bool WebViewImpl::handleCompositionEvent(WebCompositionCommand command, + int cursorPosition, + int targetStart, + int targetEnd, + const WebString& imeString) +{ + Frame* focused = focusedWebCoreFrame(); + if (!focused || !m_imeAcceptEvents) + return false; + Editor* editor = focused->editor(); + if (!editor) + return false; + if (!editor->canEdit()) { + // The input focus has been moved to another WebWidget object. + // We should use this |editor| object only to complete the ongoing + // composition. + if (!editor->hasComposition()) + return false; + } + + // We should verify the parent node of this IME composition node are + // editable because JavaScript may delete a parent node of the composition + // node. In this case, WebKit crashes while deleting texts from the parent + // node, which doesn't exist any longer. + PassRefPtr<Range> range = editor->compositionRange(); + if (range) { + const Node* node = range->startPosition().node(); + if (!node || !node->isContentEditable()) + return false; + } + + if (command == WebCompositionCommandDiscard) { + // A browser process sent an IPC message which does not contain a valid + // string, which means an ongoing composition has been canceled. + // If the ongoing composition has been canceled, replace the ongoing + // composition string with an empty string and complete it. + String emptyString; + Vector<CompositionUnderline> emptyUnderlines; + editor->setComposition(emptyString, emptyUnderlines, 0, 0); + } else { + // A browser process sent an IPC message which contains a string to be + // displayed in this Editor object. + // To display the given string, set the given string to the + // m_compositionNode member of this Editor object and display it. + if (targetStart < 0) + targetStart = 0; + if (targetEnd < 0) + targetEnd = static_cast<int>(imeString.length()); + String compositionString(imeString); + // Create custom underlines. + // To emphasize the selection, the selected region uses a solid black + // for its underline while other regions uses a pale gray for theirs. + Vector<CompositionUnderline> underlines(3); + underlines[0].startOffset = 0; + underlines[0].endOffset = targetStart; + underlines[0].thick = true; + underlines[0].color.setRGB(0xd3, 0xd3, 0xd3); + underlines[1].startOffset = targetStart; + underlines[1].endOffset = targetEnd; + underlines[1].thick = true; + underlines[1].color.setRGB(0x00, 0x00, 0x00); + underlines[2].startOffset = targetEnd; + underlines[2].endOffset = static_cast<int>(imeString.length()); + underlines[2].thick = true; + underlines[2].color.setRGB(0xd3, 0xd3, 0xd3); + // When we use custom underlines, WebKit ("InlineTextBox.cpp" Line 282) + // prevents from writing a text in between 'selectionStart' and + // 'selectionEnd' somehow. + // Therefore, we use the 'cursorPosition' for these arguments so that + // there are not any characters in the above region. + editor->setComposition(compositionString, underlines, + cursorPosition, cursorPosition); + // The given string is a result string, which means the ongoing + // composition has been completed. I have to call the + // Editor::confirmCompletion() and complete this composition. + if (command == WebCompositionCommandConfirm) + editor->confirmComposition(); + } + + return editor->hasComposition(); +} + +bool WebViewImpl::queryCompositionStatus(bool* enableIME, WebRect* caretRect) +{ + // Store whether the selected node needs IME and the caret rectangle. + // This process consists of the following four steps: + // 1. Retrieve the selection controller of the focused frame; + // 2. Retrieve the caret rectangle from the controller; + // 3. Convert the rectangle, which is relative to the parent view, to the + // one relative to the client window, and; + // 4. Store the converted rectangle. + const Frame* focused = focusedWebCoreFrame(); + if (!focused) + return false; + + const Editor* editor = focused->editor(); + if (!editor || !editor->canEdit()) + return false; + + SelectionController* controller = focused->selection(); + if (!controller) + return false; + + const Node* node = controller->start().node(); + if (!node) + return false; + + *enableIME = node->shouldUseInputMethod() && !controller->isInPasswordField(); + const FrameView* view = node->document()->view(); + if (!view) + return false; + + *caretRect = view->contentsToWindow(controller->absoluteCaretBounds()); + return true; +} + +void WebViewImpl::setTextDirection(WebTextDirection direction) +{ + // The Editor::setBaseWritingDirection() function checks if we can change + // the text direction of the selected node and updates its DOM "dir" + // attribute and its CSS "direction" property. + // So, we just call the function as Safari does. + const Frame* focused = focusedWebCoreFrame(); + if (!focused) + return; + + Editor* editor = focused->editor(); + if (!editor || !editor->canEdit()) + return; + + switch (direction) { + case WebTextDirectionDefault: + editor->setBaseWritingDirection(NaturalWritingDirection); + break; + + case WebTextDirectionLeftToRight: + editor->setBaseWritingDirection(LeftToRightWritingDirection); + break; + + case WebTextDirectionRightToLeft: + editor->setBaseWritingDirection(RightToLeftWritingDirection); + break; + + default: + notImplemented(); + break; + } +} + +// WebView -------------------------------------------------------------------- + +WebSettings* WebViewImpl::settings() +{ + if (!m_webSettings.get()) + m_webSettings.set(new WebSettingsImpl(m_page->settings())); + ASSERT(m_webSettings.get()); + return m_webSettings.get(); +} + +WebString WebViewImpl::pageEncoding() const +{ + if (!m_page.get()) + return WebString(); + + return m_page->mainFrame()->loader()->encoding(); +} + +void WebViewImpl::setPageEncoding(const WebString& encodingName) +{ + if (!m_page.get()) + return; + + // Only change override encoding, don't change default encoding. + // Note that the new encoding must be 0 if it isn't supposed to be set. + String newEncodingName; + if (!encodingName.isEmpty()) + newEncodingName = encodingName; + m_page->mainFrame()->loader()->reloadWithOverrideEncoding(newEncodingName); +} + +bool WebViewImpl::dispatchBeforeUnloadEvent() +{ + // FIXME: This should really cause a recursive depth-first walk of all + // frames in the tree, calling each frame's onbeforeunload. At the moment, + // we're consistent with Safari 3.1, not IE/FF. + Frame* frame = m_page->focusController()->focusedOrMainFrame(); + if (!frame) + return true; + + return frame->shouldClose(); +} + +void WebViewImpl::dispatchUnloadEvent() +{ + // Run unload handlers. + m_page->mainFrame()->loader()->closeURL(); +} + +WebFrame* WebViewImpl::mainFrame() +{ + return mainFrameImpl(); +} + +WebFrame* WebViewImpl::findFrameByName( + const WebString& name, WebFrame* relativeToFrame) +{ + if (!relativeToFrame) + relativeToFrame = mainFrame(); + Frame* frame = static_cast<WebFrameImpl*>(relativeToFrame)->frame(); + frame = frame->tree()->find(name); + return WebFrameImpl::fromFrame(frame); +} + +WebFrame* WebViewImpl::focusedFrame() +{ + return WebFrameImpl::fromFrame(focusedWebCoreFrame()); +} + +void WebViewImpl::setFocusedFrame(WebFrame* frame) +{ + if (!frame) { + // Clears the focused frame if any. + Frame* frame = focusedWebCoreFrame(); + if (frame) + frame->selection()->setFocused(false); + return; + } + WebFrameImpl* frameImpl = static_cast<WebFrameImpl*>(frame); + Frame* webcoreFrame = frameImpl->frame(); + webcoreFrame->page()->focusController()->setFocusedFrame(webcoreFrame); +} + +void WebViewImpl::setInitialFocus(bool reverse) +{ + if (!m_page.get()) + return; + + // Since we don't have a keyboard event, we'll create one. + WebKeyboardEvent keyboardEvent; + keyboardEvent.type = WebInputEvent::RawKeyDown; + if (reverse) + keyboardEvent.modifiers = WebInputEvent::ShiftKey; + + // VK_TAB which is only defined on Windows. + keyboardEvent.windowsKeyCode = 0x09; + PlatformKeyboardEventBuilder platformEvent(keyboardEvent); + RefPtr<KeyboardEvent> webkitEvent = KeyboardEvent::create(platformEvent, 0); + page()->focusController()->setInitialFocus( + reverse ? FocusDirectionBackward : FocusDirectionForward, + webkitEvent.get()); +} + +void WebViewImpl::clearFocusedNode() +{ + if (!m_page.get()) + return; + + RefPtr<Frame> frame = m_page->mainFrame(); + if (!frame.get()) + return; + + RefPtr<Document> document = frame->document(); + if (!document.get()) + return; + + RefPtr<Node> oldFocusedNode = document->focusedNode(); + + // Clear the focused node. + document->setFocusedNode(0); + + if (!oldFocusedNode.get()) + return; + + // If a text field has focus, we need to make sure the selection controller + // knows to remove selection from it. Otherwise, the text field is still + // processing keyboard events even though focus has been moved to the page and + // keystrokes get eaten as a result. + if (oldFocusedNode->hasTagName(HTMLNames::textareaTag) + || (oldFocusedNode->hasTagName(HTMLNames::inputTag) + && static_cast<HTMLInputElement*>(oldFocusedNode.get())->isTextField())) { + // Clear the selection. + SelectionController* selection = frame->selection(); + selection->clear(); + } +} + +void WebViewImpl::zoomIn(bool textOnly) +{ + Frame* frame = mainFrameImpl()->frame(); + double multiplier = std::min(std::pow(textSizeMultiplierRatio, m_zoomLevel + 1), + maxTextSizeMultiplier); + float zoomFactor = static_cast<float>(multiplier); + if (zoomFactor != frame->zoomFactor()) { + ++m_zoomLevel; + frame->setZoomFactor(zoomFactor, textOnly); + } +} + +void WebViewImpl::zoomOut(bool textOnly) +{ + Frame* frame = mainFrameImpl()->frame(); + double multiplier = std::max(std::pow(textSizeMultiplierRatio, m_zoomLevel - 1), + minTextSizeMultiplier); + float zoomFactor = static_cast<float>(multiplier); + if (zoomFactor != frame->zoomFactor()) { + --m_zoomLevel; + frame->setZoomFactor(zoomFactor, textOnly); + } +} + +void WebViewImpl::zoomDefault() +{ + // We don't change the zoom mode (text only vs. full page) here. We just want + // to reset whatever is already set. + m_zoomLevel = 0; + mainFrameImpl()->frame()->setZoomFactor( + 1.0f, mainFrameImpl()->frame()->isZoomFactorTextOnly()); +} + +void WebViewImpl::performMediaPlayerAction(const WebMediaPlayerAction& action, + const WebPoint& location) +{ + HitTestResult result = + hitTestResultForWindowPos(location); + RefPtr<Node> node = result.innerNonSharedNode(); + if (!node->hasTagName(HTMLNames::videoTag) && !node->hasTagName(HTMLNames::audioTag)) + return; + + RefPtr<HTMLMediaElement> mediaElement = + static_pointer_cast<HTMLMediaElement>(node); + switch (action.type) { + case WebMediaPlayerAction::Play: + if (action.enable) + mediaElement->play(); + else + mediaElement->pause(); + break; + case WebMediaPlayerAction::Mute: + mediaElement->setMuted(action.enable); + break; + case WebMediaPlayerAction::Loop: + mediaElement->setLoop(action.enable); + break; + default: + ASSERT_NOT_REACHED(); + } +} + +void WebViewImpl::copyImageAt(const WebPoint& point) +{ + if (!m_page.get()) + return; + + HitTestResult result = hitTestResultForWindowPos(point); + + if (result.absoluteImageURL().isEmpty()) { + // There isn't actually an image at these coordinates. Might be because + // the window scrolled while the context menu was open or because the page + // changed itself between when we thought there was an image here and when + // we actually tried to retreive the image. + // + // FIXME: implement a cache of the most recent HitTestResult to avoid having + // to do two hit tests. + return; + } + + m_page->mainFrame()->editor()->copyImage(result); +} + +void WebViewImpl::dragSourceEndedAt( + const WebPoint& clientPoint, + const WebPoint& screenPoint, + WebDragOperation operation) +{ + PlatformMouseEvent pme(clientPoint, + screenPoint, + LeftButton, MouseEventMoved, 0, false, false, false, + false, 0); + m_page->mainFrame()->eventHandler()->dragSourceEndedAt(pme, + static_cast<DragOperation>(operation)); +} + +void WebViewImpl::dragSourceMovedTo( + const WebPoint& clientPoint, + const WebPoint& screenPoint) +{ + PlatformMouseEvent pme(clientPoint, + screenPoint, + LeftButton, MouseEventMoved, 0, false, false, false, + false, 0); + m_page->mainFrame()->eventHandler()->dragSourceMovedTo(pme); +} + +void WebViewImpl::dragSourceSystemDragEnded() +{ + // It's possible for us to get this callback while not doing a drag if + // it's from a previous page that got unloaded. + if (m_doingDragAndDrop) { + m_page->dragController()->dragEnded(); + m_doingDragAndDrop = false; + } +} + +WebDragOperation WebViewImpl::dragTargetDragEnter( + const WebDragData& webDragData, int identity, + const WebPoint& clientPoint, + const WebPoint& screenPoint, + WebDragOperationsMask operationsAllowed) +{ + ASSERT(!m_currentDragData.get()); + + m_currentDragData = webDragData; + m_dragIdentity = identity; + m_operationsAllowed = operationsAllowed; + + DragData dragData( + m_currentDragData.get(), + clientPoint, + screenPoint, + static_cast<DragOperation>(operationsAllowed)); + + m_dropEffect = DropEffectDefault; + m_dragTargetDispatch = true; + DragOperation effect = m_page->dragController()->dragEntered(&dragData); + // Mask the operation against the drag source's allowed operations. + if ((effect & dragData.draggingSourceOperationMask()) != effect) + effect = DragOperationNone; + m_dragTargetDispatch = false; + + if (m_dropEffect != DropEffectDefault) { + m_dragOperation = (m_dropEffect != DropEffectNone) ? WebDragOperationCopy + : WebDragOperationNone; + } else + m_dragOperation = static_cast<WebDragOperation>(effect); + return m_dragOperation; +} + +WebDragOperation WebViewImpl::dragTargetDragOver( + const WebPoint& clientPoint, + const WebPoint& screenPoint, + WebDragOperationsMask operationsAllowed) +{ + ASSERT(m_currentDragData.get()); + + m_operationsAllowed = operationsAllowed; + DragData dragData( + m_currentDragData.get(), + clientPoint, + screenPoint, + static_cast<DragOperation>(operationsAllowed)); + + m_dropEffect = DropEffectDefault; + m_dragTargetDispatch = true; + DragOperation effect = m_page->dragController()->dragUpdated(&dragData); + // Mask the operation against the drag source's allowed operations. + if ((effect & dragData.draggingSourceOperationMask()) != effect) + effect = DragOperationNone; + m_dragTargetDispatch = false; + + if (m_dropEffect != DropEffectDefault) { + m_dragOperation = (m_dropEffect != DropEffectNone) ? WebDragOperationCopy + : WebDragOperationNone; + } else + m_dragOperation = static_cast<WebDragOperation>(effect); + return m_dragOperation; +} + +void WebViewImpl::dragTargetDragLeave() +{ + ASSERT(m_currentDragData.get()); + + DragData dragData( + m_currentDragData.get(), + IntPoint(), + IntPoint(), + static_cast<DragOperation>(m_operationsAllowed)); + + m_dragTargetDispatch = true; + m_page->dragController()->dragExited(&dragData); + m_dragTargetDispatch = false; + + m_currentDragData = 0; + m_dropEffect = DropEffectDefault; + m_dragOperation = WebDragOperationNone; + m_dragIdentity = 0; +} + +void WebViewImpl::dragTargetDrop(const WebPoint& clientPoint, + const WebPoint& screenPoint) +{ + ASSERT(m_currentDragData.get()); + + // If this webview transitions from the "drop accepting" state to the "not + // accepting" state, then our IPC message reply indicating that may be in- + // flight, or else delayed by javascript processing in this webview. If a + // drop happens before our IPC reply has reached the browser process, then + // the browser forwards the drop to this webview. So only allow a drop to + // proceed if our webview m_dragOperation state is not DragOperationNone. + + if (m_dragOperation == WebDragOperationNone) { // IPC RACE CONDITION: do not allow this drop. + dragTargetDragLeave(); + return; + } + + DragData dragData( + m_currentDragData.get(), + clientPoint, + screenPoint, + static_cast<DragOperation>(m_operationsAllowed)); + + m_dragTargetDispatch = true; + m_page->dragController()->performDrag(&dragData); + m_dragTargetDispatch = false; + + m_currentDragData = 0; + m_dropEffect = DropEffectDefault; + m_dragOperation = WebDragOperationNone; + m_dragIdentity = 0; +} + +int WebViewImpl::dragIdentity() +{ + if (m_dragTargetDispatch) + return m_dragIdentity; + return 0; +} + +void WebViewImpl::inspectElementAt(const WebPoint& point) +{ + if (!m_page.get()) + return; + + if (point.x == -1 || point.y == -1) + m_page->inspectorController()->inspect(0); + else { + HitTestResult result = hitTestResultForWindowPos(point); + + if (!result.innerNonSharedNode()) + return; + + m_page->inspectorController()->inspect(result.innerNonSharedNode()); + } +} + +WebString WebViewImpl::inspectorSettings() const +{ + return m_inspectorSettings; +} + +void WebViewImpl::setInspectorSettings(const WebString& settings) +{ + m_inspectorSettings = settings; +} + +WebDevToolsAgent* WebViewImpl::devToolsAgent() +{ + return m_devToolsAgent.get(); +} + +WebAccessibilityObject WebViewImpl::accessibilityObject() +{ + if (!mainFrameImpl()) + return WebAccessibilityObject(); + + Document* document = mainFrameImpl()->frame()->document(); + return WebAccessibilityObject( + document->axObjectCache()->getOrCreate(document->renderer())); +} + +void WebViewImpl::applyAutofillSuggestions( + const WebNode& node, + const WebVector<WebString>& suggestions, + int defaultSuggestionIndex) +{ + if (!m_page.get() || suggestions.isEmpty()) { + hideAutoCompletePopup(); + return; + } + + ASSERT(defaultSuggestionIndex < static_cast<int>(suggestions.size())); + + if (RefPtr<Frame> focused = m_page->focusController()->focusedFrame()) { + RefPtr<Document> document = focused->document(); + if (!document.get()) { + hideAutoCompletePopup(); + return; + } + + RefPtr<Node> focusedNode = document->focusedNode(); + // If the node for which we queried the autofill suggestions is not the + // focused node, then we have nothing to do. FIXME: also check the + // carret is at the end and that the text has not changed. + if (!focusedNode.get() || focusedNode != PassRefPtr<Node>(node)) { + hideAutoCompletePopup(); + return; + } + + if (!focusedNode->hasTagName(HTMLNames::inputTag)) { + ASSERT_NOT_REACHED(); + return; + } + + HTMLInputElement* inputElem = + static_cast<HTMLInputElement*>(focusedNode.get()); + + // The first time the autocomplete is shown we'll create the client and the + // popup. + if (!m_autocompletePopupClient.get()) + m_autocompletePopupClient.set(new AutocompletePopupMenuClient(this)); + m_autocompletePopupClient->initialize(inputElem, + suggestions, + defaultSuggestionIndex); + if (!m_autocompletePopup.get()) { + m_autocompletePopup = + PopupContainer::create(m_autocompletePopupClient.get(), + autocompletePopupSettings); + } + + if (m_autocompletePopupShowing) { + m_autocompletePopupClient->setSuggestions(suggestions); + refreshAutofillPopup(); + } else { + m_autocompletePopup->show(focusedNode->getRect(), + focusedNode->ownerDocument()->view(), 0); + m_autocompletePopupShowing = true; + } + } +} + +void WebViewImpl::hideAutofillPopup() +{ + hideAutoCompletePopup(); +} + +// WebView -------------------------------------------------------------------- + +bool WebViewImpl::setDropEffect(bool accept) { + if (m_dragTargetDispatch) { + m_dropEffect = accept ? DropEffectCopy : DropEffectNone; + return true; + } + return false; +} + +WebDevToolsAgentImpl* WebViewImpl::devToolsAgentImpl() +{ + return m_devToolsAgent.get(); +} + +void WebViewImpl::setIsTransparent(bool isTransparent) +{ + // Set any existing frames to be transparent. + Frame* frame = m_page->mainFrame(); + while (frame) { + frame->view()->setTransparent(isTransparent); + frame = frame->tree()->traverseNext(); + } + + // Future frames check this to know whether to be transparent. + m_isTransparent = isTransparent; +} + +bool WebViewImpl::isTransparent() const +{ + return m_isTransparent; +} + +void WebViewImpl::setIsActive(bool active) +{ + if (page() && page()->focusController()) + page()->focusController()->setActive(active); +} + +bool WebViewImpl::isActive() const +{ + return (page() && page()->focusController()) ? page()->focusController()->isActive() : false; +} + +void WebViewImpl::didCommitLoad(bool* isNewNavigation) +{ + if (isNewNavigation) + *isNewNavigation = m_observedNewNavigation; + +#ifndef NDEBUG + ASSERT(!m_observedNewNavigation + || m_page->mainFrame()->loader()->documentLoader() == m_newNavigationLoader); + m_newNavigationLoader = 0; +#endif + m_observedNewNavigation = false; +} + +bool WebViewImpl::navigationPolicyFromMouseEvent(unsigned short button, + bool ctrl, bool shift, + bool alt, bool meta, + WebNavigationPolicy* policy) +{ +#if PLATFORM(WIN_OS) || PLATFORM(LINUX) || PLATFORM(FREEBSD) + const bool newTabModifier = (button == 1) || ctrl; +#elif PLATFORM(DARWIN) + const bool newTabModifier = (button == 1) || meta; +#endif + if (!newTabModifier && !shift && !alt) + return false; + + ASSERT(policy); + if (newTabModifier) { + if (shift) + *policy = WebNavigationPolicyNewForegroundTab; + else + *policy = WebNavigationPolicyNewBackgroundTab; + } else { + if (shift) + *policy = WebNavigationPolicyNewWindow; + else + *policy = WebNavigationPolicyDownload; + } + return true; +} + +void WebViewImpl::startDragging(const WebPoint& eventPos, + const WebDragData& dragData, + WebDragOperationsMask mask) +{ + if (!m_client) + return; + ASSERT(!m_doingDragAndDrop); + m_doingDragAndDrop = true; + m_client->startDragging(eventPos, dragData, mask); +} + +void WebViewImpl::setCurrentHistoryItem(HistoryItem* item) +{ + m_backForwardListClientImpl.setCurrentHistoryItem(item); +} + +HistoryItem* WebViewImpl::previousHistoryItem() +{ + return m_backForwardListClientImpl.previousHistoryItem(); +} + +void WebViewImpl::observeNewNavigation() +{ + m_observedNewNavigation = true; +#ifndef NDEBUG + m_newNavigationLoader = m_page->mainFrame()->loader()->documentLoader(); +#endif +} + +void WebViewImpl::hideAutoCompletePopup() +{ + if (m_autocompletePopupShowing) { + m_autocompletePopup->hidePopup(); + autoCompletePopupDidHide(); + } +} + +void WebViewImpl::autoCompletePopupDidHide() +{ + m_autocompletePopupShowing = false; +} + +void WebViewImpl::setIgnoreInputEvents(bool newValue) +{ + ASSERT(m_ignoreInputEvents != newValue); + m_ignoreInputEvents = newValue; +} + +#if ENABLE(NOTIFICATIONS) +NotificationPresenterImpl* WebViewImpl::notificationPresenterImpl() +{ + if (!m_notificationPresenter.isInitialized() && m_client) + m_notificationPresenter.initialize(m_client->notificationPresenter()); + return &m_notificationPresenter; +} +#endif + +void WebViewImpl::refreshAutofillPopup() { + ASSERT(m_autocompletePopupShowing); + + // Hide the popup if it has become empty. + if (m_autocompletePopupClient->listSize() == 0) { + hideAutoCompletePopup(); + return; + } + + IntRect oldBounds = m_autocompletePopup->boundsRect(); + m_autocompletePopup->refresh(); + IntRect newBounds = m_autocompletePopup->boundsRect(); + // Let's resize the backing window if necessary. + if (oldBounds != newBounds) { + WebPopupMenuImpl* popupMenu = + static_cast<WebPopupMenuImpl*>(m_autocompletePopup->client()); + popupMenu->client()->setWindowRect(newBounds); + } +} + +Node* WebViewImpl::focusedWebCoreNode() +{ + Frame* frame = m_page->focusController()->focusedFrame(); + if (!frame) + return 0; + + Document* document = frame->document(); + if (!document) + return 0; + + return document->focusedNode(); +} + +HitTestResult WebViewImpl::hitTestResultForWindowPos(const IntPoint& pos) +{ + IntPoint docPoint(m_page->mainFrame()->view()->windowToContents(pos)); + return m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(docPoint, false); +} + +void WebViewImpl::setTabsToLinks(bool enable) +{ + m_tabsToLinks = enable; +} + +bool WebViewImpl::tabsToLinks() const +{ + return m_tabsToLinks; +} + +} // namespace WebKit diff --git a/webkit/api/src/WebViewImpl.h b/webkit/api/src/WebViewImpl.h new file mode 100644 index 0000000..7f99256 --- /dev/null +++ b/webkit/api/src/WebViewImpl.h @@ -0,0 +1,419 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WebViewImpl_h +#define WebViewImpl_h + +#include "BackForwardListClientImpl.h" +#include "ChromeClientImpl.h" +#include "ContextMenuClientImpl.h" +#include "DragClientImpl.h" +#include "EditorClientImpl.h" +#include "InspectorClientImpl.h" +#include "NotificationPresenterImpl.h" +// FIXME: remove this relative path once consumers from glue are removed. +#include "../public/WebNavigationPolicy.h" +#include "../public/WebPoint.h" +#include "../public/WebSize.h" +#include "../public/WebString.h" +#include "../public/WebView.h" +#include <wtf/OwnPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { +class ChromiumDataObject; +class Frame; +class HistoryItem; +class HitTestResult; +class KeyboardEvent; +class Page; +class PlatformKeyboardEvent; +class PopupContainer; +class Range; +class RenderTheme; +class Widget; +} + +class WebDevToolsAgentImpl; + +namespace WebKit { +class AutocompletePopupMenuClient; +class ContextMenuClientImpl; +class WebAccessibilityObject; +class WebFrameImpl; +class WebKeyboardEvent; +class WebMouseEvent; +class WebMouseWheelEvent; +class WebSettingsImpl; + +class WebViewImpl : public WebView, public RefCounted<WebViewImpl> { +public: + // WebWidget methods: + virtual void close(); + virtual WebSize size() { return m_size; } + virtual void resize(const WebSize&); + virtual void layout(); + virtual void paint(WebCanvas*, const WebRect&); + virtual bool handleInputEvent(const WebInputEvent&); + virtual void mouseCaptureLost(); + virtual void setFocus(bool enable); + virtual bool handleCompositionEvent(WebCompositionCommand command, + int cursorPosition, + int targetStart, + int targetEnd, + const WebString& text); + virtual bool queryCompositionStatus(bool* enabled, + WebRect* caretRect); + virtual void setTextDirection(WebTextDirection direction); + + // WebView methods: + virtual void initializeMainFrame(WebFrameClient*); + virtual WebSettings* settings(); + virtual WebString pageEncoding() const; + virtual void setPageEncoding(const WebString& encoding); + virtual bool isTransparent() const; + virtual void setIsTransparent(bool value); + virtual bool tabsToLinks() const; + virtual void setTabsToLinks(bool value); + virtual bool tabKeyCyclesThroughElements() const; + virtual void setTabKeyCyclesThroughElements(bool value); + virtual bool isActive() const; + virtual void setIsActive(bool value); + virtual bool dispatchBeforeUnloadEvent(); + virtual void dispatchUnloadEvent(); + virtual WebFrame* mainFrame(); + virtual WebFrame* findFrameByName( + const WebString& name, WebFrame* relativeToFrame); + virtual WebFrame* focusedFrame(); + virtual void setFocusedFrame(WebFrame* frame); + virtual void setInitialFocus(bool reverse); + virtual void clearFocusedNode(); + virtual void zoomIn(bool textOnly); + virtual void zoomOut(bool textOnly); + virtual void zoomDefault(); + virtual void performMediaPlayerAction( + const WebMediaPlayerAction& action, + const WebPoint& location); + virtual void copyImageAt(const WebPoint& point); + virtual void dragSourceEndedAt( + const WebPoint& clientPoint, + const WebPoint& screenPoint, + WebDragOperation operation); + virtual void dragSourceMovedTo( + const WebPoint& clientPoint, + const WebPoint& screenPoint); + virtual void dragSourceSystemDragEnded(); + virtual WebDragOperation dragTargetDragEnter( + const WebDragData& dragData, int identity, + const WebPoint& clientPoint, + const WebPoint& screenPoint, + WebDragOperationsMask operationsAllowed); + virtual WebDragOperation dragTargetDragOver( + const WebPoint& clientPoint, + const WebPoint& screenPoint, + WebDragOperationsMask operationsAllowed); + virtual void dragTargetDragLeave(); + virtual void dragTargetDrop( + const WebPoint& clientPoint, + const WebPoint& screenPoint); + virtual int dragIdentity(); + virtual bool setDropEffect(bool accept); + virtual void inspectElementAt(const WebPoint& point); + virtual WebString inspectorSettings() const; + virtual void setInspectorSettings(const WebString& settings); + virtual WebDevToolsAgent* devToolsAgent(); + virtual WebAccessibilityObject accessibilityObject(); + virtual void applyAutofillSuggestions( + const WebNode&, + const WebVector<WebString>& suggestions, + int defaultSuggestionIndex); + virtual void hideAutofillPopup(); + + // WebViewImpl + + void setIgnoreInputEvents(bool newValue); + WebDevToolsAgentImpl* devToolsAgentImpl(); + + const WebPoint& lastMouseDownPoint() const + { + return m_lastMouseDownPoint; + } + + WebCore::Frame* focusedWebCoreFrame(); + + // Returns the currently focused Node or null if no node has focus. + WebCore::Node* focusedWebCoreNode(); + + static WebViewImpl* fromPage(WebCore::Page*); + + WebViewClient* client() + { + return m_client; + } + + // Returns the page object associated with this view. This may be null when + // the page is shutting down, but will be valid at all other times. + WebCore::Page* page() const + { + return m_page.get(); + } + + WebCore::RenderTheme* theme() const; + + // Returns the main frame associated with this view. This may be null when + // the page is shutting down, but will be valid at all other times. + WebFrameImpl* mainFrameImpl(); + + // History related methods: + void setCurrentHistoryItem(WebCore::HistoryItem*); + WebCore::HistoryItem* previousHistoryItem(); + void observeNewNavigation(); + + // Event related methods: + void mouseMove(const WebMouseEvent&); + void mouseLeave(const WebMouseEvent&); + void mouseDown(const WebMouseEvent&); + void mouseUp(const WebMouseEvent&); + void mouseContextMenu(const WebMouseEvent&); + void mouseDoubleClick(const WebMouseEvent&); + void mouseWheel(const WebMouseWheelEvent&); + bool keyEvent(const WebKeyboardEvent&); + bool charEvent(const WebKeyboardEvent&); + + // Handles context menu events orignated via the the keyboard. These + // include the VK_APPS virtual key and the Shift+F10 combine. Code is + // based on the Webkit function bool WebView::handleContextMenuEvent(WPARAM + // wParam, LPARAM lParam) in webkit\webkit\win\WebView.cpp. The only + // significant change in this function is the code to convert from a + // Keyboard event to the Right Mouse button down event. + bool sendContextMenuEvent(const WebKeyboardEvent&); + + // Notifies the WebView that a load has been committed. isNewNavigation + // will be true if a new session history item should be created for that + // load. + void didCommitLoad(bool* isNewNavigation); + + bool contextMenuAllowed() const + { + return m_contextMenuAllowed; + } + + // Set the disposition for how this webview is to be initially shown. + void setInitialNavigationPolicy(WebNavigationPolicy policy) + { + m_initialNavigationPolicy = policy; + } + WebNavigationPolicy initialNavigationPolicy() const + { + return m_initialNavigationPolicy; + } + + // Determines whether a page should e.g. be opened in a background tab. + // Returns false if it has no opinion, in which case it doesn't set *policy. + static bool navigationPolicyFromMouseEvent( + unsigned short button, + bool ctrl, + bool shift, + bool alt, + bool meta, + WebNavigationPolicy*); + + // Start a system drag and drop operation. + void startDragging( + const WebPoint& eventPos, + const WebDragData& dragData, + WebDragOperationsMask dragSourceOperationMask); + + // Hides the autocomplete popup if it is showing. + void hideAutoCompletePopup(); + void autoCompletePopupDidHide(); + +#if ENABLE(NOTIFICATIONS) + // Returns the provider of desktop notifications. + NotificationPresenterImpl* notificationPresenterImpl(); +#endif + + // Tries to scroll a frame or any parent of a frame. Returns true if the view + // was scrolled. + bool propagateScroll(WebCore::ScrollDirection, WebCore::ScrollGranularity); + + // HACK: currentInputEvent() is for ChromeClientImpl::show(), until we can + // fix WebKit to pass enough information up into ChromeClient::show() so we + // can decide if the window.open event was caused by a middle-mouse click + static const WebInputEvent* currentInputEvent() + { + return m_currentInputEvent; + } + +private: + friend class WebView; // So WebView::Create can call our constructor + friend class WTF::RefCounted<WebViewImpl>; + + WebViewImpl(WebViewClient* client); + ~WebViewImpl(); + + void modifySelection(uint32 message, WebCore::Frame*, const WebCore::PlatformKeyboardEvent&); + + // Returns true if the event was actually processed. + bool keyEventDefault(const WebKeyboardEvent&); + + // Returns true if the autocomple has consumed the event. + bool autocompleteHandleKeyEvent(const WebKeyboardEvent&); + + // Repaints the autofill popup. Should be called when the suggestions have + // changed. Note that this should only be called when the autofill popup is + // showing. + void refreshAutofillPopup(); + + // Returns true if the view was scrolled. + bool scrollViewWithKeyboard(int keyCode, int modifiers); + + // Converts |pos| from window coordinates to contents coordinates and gets + // the HitTestResult for it. + WebCore::HitTestResult hitTestResultForWindowPos(const WebCore::IntPoint&); + + WebViewClient* m_client; + + BackForwardListClientImpl m_backForwardListClientImpl; + ChromeClientImpl m_chromeClientImpl; + ContextMenuClientImpl m_contextMenuClientImpl; + DragClientImpl m_dragClientImpl; + EditorClientImpl m_editorClientImpl; + InspectorClientImpl m_inspectorClientImpl; + + WebSize m_size; + + WebPoint m_lastMousePosition; + OwnPtr<WebCore::Page> m_page; + + // This flag is set when a new navigation is detected. It is used to satisfy + // the corresponding argument to WebFrameClient::didCommitProvisionalLoad. + bool m_observedNewNavigation; +#ifndef NDEBUG + // Used to assert that the new navigation we observed is the same navigation + // when we make use of m_observedNewNavigation. + const WebCore::DocumentLoader* m_newNavigationLoader; +#endif + + // An object that can be used to manipulate m_page->settings() without linking + // against WebCore. This is lazily allocated the first time GetWebSettings() + // is called. + OwnPtr<WebSettingsImpl> m_webSettings; + + // A copy of the web drop data object we received from the browser. + RefPtr<WebCore::ChromiumDataObject> m_currentDragData; + + // The point relative to the client area where the mouse was last pressed + // down. This is used by the drag client to determine what was under the + // mouse when the drag was initiated. We need to track this here in + // WebViewImpl since DragClient::startDrag does not pass the position the + // mouse was at when the drag was initiated, only the current point, which + // can be misleading as it is usually not over the element the user actually + // dragged by the time a drag is initiated. + WebPoint m_lastMouseDownPoint; + + // Keeps track of the current text zoom level. 0 means no zoom, positive + // values mean larger text, negative numbers mean smaller. + int m_zoomLevel; + + bool m_contextMenuAllowed; + + bool m_doingDragAndDrop; + + bool m_ignoreInputEvents; + + // Webkit expects keyPress events to be suppressed if the associated keyDown + // event was handled. Safari implements this behavior by peeking out the + // associated WM_CHAR event if the keydown was handled. We emulate + // this behavior by setting this flag if the keyDown was handled. + bool m_suppressNextKeypressEvent; + + // The policy for how this webview is to be initially shown. + WebNavigationPolicy m_initialNavigationPolicy; + + // Represents whether or not this object should process incoming IME events. + bool m_imeAcceptEvents; + + // True while dispatching system drag and drop events to drag/drop targets + // within this WebView. + bool m_dragTargetDispatch; + + // Valid when m_dragTargetDispatch is true; the identity of the drag data + // copied from the WebDropData object sent from the browser process. + int32 m_dragIdentity; + + // Valid when m_dragTargetDispatch is true. Used to override the default + // browser drop effect with the effects "none" or "copy". + enum DragTargetDropEffect { + DropEffectDefault = -1, + DropEffectNone, + DropEffectCopy + } m_dropEffect; + + // The available drag operations (copy, move link...) allowed by the source. + WebDragOperation m_operationsAllowed; + + // The current drag operation as negotiated by the source and destination. + // When not equal to DragOperationNone, the drag data can be dropped onto the + // current drop target in this WebView (the drop target can accept the drop). + WebDragOperation m_dragOperation; + + // The autocomplete popup. Kept around and reused every-time new suggestions + // should be shown. + RefPtr<WebCore::PopupContainer> m_autocompletePopup; + + // Whether the autocomplete popup is currently showing. + bool m_autocompletePopupShowing; + + // The autocomplete client. + OwnPtr<AutocompletePopupMenuClient> m_autocompletePopupClient; + + OwnPtr<WebDevToolsAgentImpl> m_devToolsAgent; + + // Whether the webview is rendering transparently. + bool m_isTransparent; + + // Whether the user can press tab to focus links. + bool m_tabsToLinks; + + // Inspector settings. + WebString m_inspectorSettings; + +#if ENABLE(NOTIFICATIONS) + // The provider of desktop notifications; + NotificationPresenterImpl m_notificationPresenter; +#endif + + static const WebInputEvent* m_currentInputEvent; +}; + +} // namespace WebKit + +#endif diff --git a/webkit/api/src/WebWorkerClientImpl.cpp b/webkit/api/src/WebWorkerClientImpl.cpp index 16d7134..5e99b57 100644 --- a/webkit/api/src/WebWorkerClientImpl.cpp +++ b/webkit/api/src/WebWorkerClientImpl.cpp @@ -47,21 +47,19 @@ #include "WorkerContextExecutionProxy.h" #include "WorkerMessagingProxy.h" #include <wtf/Threading.h> -#undef LOG +#include "FrameLoaderClientImpl.h" #include "PlatformMessagePortChannel.h" #include "WebFrameClient.h" +#include "WebFrameImpl.h" #include "WebKit.h" #include "WebKitClient.h" #include "WebMessagePortChannel.h" #include "WebString.h" #include "WebURL.h" +#include "WebViewImpl.h" #include "WebWorker.h" #include "WebWorkerImpl.h" -// FIXME: remove the includes below -#include "webkit/glue/webframeloaderclient_impl.h" -#include "webkit/glue/webframe_impl.h" -#include "webkit/glue/webview_impl.h" using namespace WebCore; @@ -93,7 +91,7 @@ WorkerContextProxy* WebWorkerClientImpl::createWorkerContextProxy(Worker* worker if (worker->scriptExecutionContext()->isDocument()) { Document* document = static_cast<Document*>( worker->scriptExecutionContext()); - WebFrameImpl* webFrame = WebFrameImpl::FromFrame(document->frame()); + WebFrameImpl* webFrame = WebFrameImpl::fromFrame(document->frame()); webWorker = webFrame->client()->createWorker(webFrame, proxy); } else { WorkerContextExecutionProxy* currentContext = diff --git a/webkit/api/src/WebWorkerImpl.cpp b/webkit/api/src/WebWorkerImpl.cpp index 8e6f6df..4028b71 100644 --- a/webkit/api/src/WebWorkerImpl.cpp +++ b/webkit/api/src/WebWorkerImpl.cpp @@ -48,14 +48,13 @@ #include "PlatformMessagePortChannel.h" #include "WebDataSourceImpl.h" #include "WebFrameClient.h" +#include "WebFrameImpl.h" #include "WebMessagePortChannel.h" #include "WebScreenInfo.h" #include "WebString.h" #include "WebURL.h" #include "WebView.h" #include "WebWorkerClient.h" -// FIXME: webframe should eventually move to api/src too. -#include "webkit/glue/webframe_impl.h" using namespace WebCore; diff --git a/webkit/glue/devtools/debugger_agent_impl.cc b/webkit/glue/devtools/debugger_agent_impl.cc index 9080869..a32b9a2 100644 --- a/webkit/glue/devtools/debugger_agent_impl.cc +++ b/webkit/glue/devtools/debugger_agent_impl.cc @@ -9,6 +9,7 @@ #include <wtf/Vector.h> #include "Document.h" +#include "Frame.h" #include "Page.h" #include "V8Binding.h" #include "V8DOMWindow.h" @@ -17,12 +18,12 @@ #undef LOG #include "grit/webkit_resources.h" +#include "webkit/api/src/WebViewImpl.h" #include "webkit/glue/devtools/debugger_agent_impl.h" #include "webkit/glue/devtools/debugger_agent_manager.h" #include "webkit/glue/glue_util.h" #include "webkit/glue/webdevtoolsagent_impl.h" #include "webkit/glue/webkit_glue.h" -#include "webkit/glue/webview_impl.h" using WebCore::DOMWindow; using WebCore::Document; @@ -34,6 +35,7 @@ using WebCore::V8Custom; using WebCore::V8DOMWindow; using WebCore::V8DOMWrapper; using WebCore::V8Proxy; +using WebKit::WebViewImpl; DebuggerAgentImpl::DebuggerAgentImpl( WebViewImpl* web_view_impl, diff --git a/webkit/glue/devtools/debugger_agent_impl.h b/webkit/glue/devtools/debugger_agent_impl.h index 0659dd7..95ea2d8 100644 --- a/webkit/glue/devtools/debugger_agent_impl.h +++ b/webkit/glue/devtools/debugger_agent_impl.h @@ -12,7 +12,6 @@ #include "webkit/glue/devtools/debugger_agent.h" class WebDevToolsAgentImpl; -class WebViewImpl; namespace WebCore { class Document; @@ -21,13 +20,17 @@ class Page; class String; } +namespace WebKit { +class WebViewImpl; +} + class DebuggerAgentImpl : public DebuggerAgent { public: // Creates utility context with injected js agent. static void CreateUtilityContext(WebCore::Frame* frame, v8::Persistent<v8::Context>* context); - DebuggerAgentImpl(WebViewImpl* web_view_impl, + DebuggerAgentImpl(WebKit::WebViewImpl* web_view_impl, DebuggerAgentDelegate* delegate, WebDevToolsAgentImpl* webdevtools_agent); virtual ~DebuggerAgentImpl(); @@ -66,10 +69,10 @@ class DebuggerAgentImpl : public DebuggerAgent { WebCore::Page* GetPage(); WebDevToolsAgentImpl* webdevtools_agent() { return webdevtools_agent_; }; - WebViewImpl* web_view() { return web_view_impl_; } + WebKit::WebViewImpl* web_view() { return web_view_impl_; } private: - WebViewImpl* web_view_impl_; + WebKit::WebViewImpl* web_view_impl_; DebuggerAgentDelegate* delegate_; WebDevToolsAgentImpl* webdevtools_agent_; int profiler_log_position_; diff --git a/webkit/glue/devtools/debugger_agent_manager.cc b/webkit/glue/devtools/debugger_agent_manager.cc index edf6738..2cfb459 100644 --- a/webkit/glue/devtools/debugger_agent_manager.cc +++ b/webkit/glue/devtools/debugger_agent_manager.cc @@ -11,16 +11,19 @@ #undef LOG #include "webkit/api/public/WebDevToolsAgent.h" +#include "webkit/api/src/WebFrameImpl.h" +#include "webkit/api/src/WebViewImpl.h" #include "webkit/glue/devtools/debugger_agent_impl.h" #include "webkit/glue/devtools/debugger_agent_manager.h" #include "webkit/glue/webdevtoolsagent_impl.h" -#include "webkit/glue/webview_impl.h" #if USE(V8) #include "v8/include/v8-debug.h" #endif using WebKit::WebDevToolsAgent; +using WebKit::WebFrameImpl; +using WebKit::WebViewImpl; WebDevToolsAgent::MessageLoopDispatchHandler DebuggerAgentManager::message_loop_dispatch_handler_ = NULL; @@ -77,7 +80,7 @@ void DebuggerAgentManager::V8DebugHostDispatchHandler() { agent->web_view(), new WebCore::PageGroupLoadDeferrer(agent->GetPage(), true)); views.append(agent->web_view()); - agent->web_view()->SetIgnoreInputEvents(true); + agent->web_view()->setIgnoreInputEvents(true); } // 2. Process messages. @@ -89,7 +92,7 @@ void DebuggerAgentManager::V8DebugHostDispatchHandler() { ++it) { if (page_deferrers_.contains(*it)) { // The view was not closed during the dispatch. - (*it)->SetIgnoreInputEvents(false); + (*it)->setIgnoreInputEvents(false); } } deleteAllValues(page_deferrers_); diff --git a/webkit/glue/devtools/debugger_agent_manager.h b/webkit/glue/devtools/debugger_agent_manager.h index 22a1f93..3d49ed7 100644 --- a/webkit/glue/devtools/debugger_agent_manager.h +++ b/webkit/glue/devtools/debugger_agent_manager.h @@ -15,10 +15,13 @@ namespace WebCore { class PageGroupLoadDeferrer; } -class DebuggerAgentImpl; -class DictionaryValue; +namespace WebKit { class WebFrameImpl; class WebViewImpl; +} + +class DebuggerAgentImpl; +class DictionaryValue; // There is single v8 instance per render process. Also there may be several // RenderViews and consequently devtools agents in the process that want to talk @@ -46,9 +49,9 @@ class DebuggerAgentManager : public Noncopyable { // Sets |host_id| as the frame context data. This id is used to filter scripts // related to the inspected page. - static void SetHostId(WebFrameImpl* webframe, int host_id); + static void SetHostId(WebKit::WebFrameImpl* webframe, int host_id); - static void OnWebViewClosed(WebViewImpl* webview); + static void OnWebViewClosed(WebKit::WebViewImpl* webview); static void OnNavigate(); @@ -86,7 +89,7 @@ class DebuggerAgentManager : public Noncopyable { static WebKit::WebDevToolsAgent::MessageLoopDispatchHandler message_loop_dispatch_handler_; static bool in_host_dispatch_handler_; - typedef HashMap<WebViewImpl*, WebCore::PageGroupLoadDeferrer*> + typedef HashMap<WebKit::WebViewImpl*, WebCore::PageGroupLoadDeferrer*> DeferrersMap; static DeferrersMap page_deferrers_; diff --git a/webkit/glue/dom_operations.cc b/webkit/glue/dom_operations.cc index ba1e2bc..2b523d6 100644 --- a/webkit/glue/dom_operations.cc +++ b/webkit/glue/dom_operations.cc @@ -33,16 +33,18 @@ MSVC_POP_WARNING(); #include "base/string_util.h" // TODO(yaar) Eventually should not depend on api/src. #include "webkit/api/src/DOMUtilitiesPrivate.h" +#include "webkit/api/src/WebFrameImpl.h" +#include "webkit/api/src/WebViewImpl.h" #include "webkit/glue/dom_operations.h" #include "webkit/glue/dom_operations_private.h" #include "webkit/glue/form_data.h" #include "webkit/glue/glue_util.h" #include "webkit/glue/password_autocomplete_listener_impl.h" -#include "webkit/glue/webframe_impl.h" -#include "webkit/glue/webview_impl.h" using WebCore::String; +using WebKit::FrameLoaderClientImpl; using WebKit::WebFrame; +using WebKit::WebFrameImpl; using WebKit::WebView; namespace { @@ -345,11 +347,11 @@ void FillPasswordForm(WebView* view, WebCore::HTMLInputElement* password_element = form_elements->input_elements[data.basic_data.elements[1]].get(); - WebFrameLoaderClient* frame_loader_client = - static_cast<WebFrameLoaderClient*>(username_element->document()-> - frame()->loader()->client()); - WebFrameImpl* webframe_impl = frame_loader_client->webframe(); - webframe_impl->RegisterPasswordListener( + FrameLoaderClientImpl* frame_loader_client = + static_cast<FrameLoaderClientImpl*>(username_element->document()-> + frame()->loader()->client()); + WebFrameImpl* webframe_impl = frame_loader_client->webFrame(); + webframe_impl->registerPasswordListener( username_element, new PasswordAutocompleteListenerImpl( new HTMLInputDelegate(username_element), @@ -369,7 +371,7 @@ WebFrameImpl* GetWebFrameImplFromElement(WebCore::Element* element, WebCore::HTMLFrameOwnerElement* frame_element = static_cast<WebCore::HTMLFrameOwnerElement*>(element); WebCore::Frame* content_frame = frame_element->contentFrame(); - return WebFrameImpl::FromFrame(content_frame); + return WebFrameImpl::fromFrame(content_frame); } } return NULL; diff --git a/webkit/glue/dom_operations.h b/webkit/glue/dom_operations.h index af61698..e0d7142 100644 --- a/webkit/glue/dom_operations.h +++ b/webkit/glue/dom_operations.h @@ -17,7 +17,6 @@ class WebView; } struct FormData; -class WebFrameImpl; // A collection of operations that access the underlying WebKit DOM directly. namespace webkit_glue { diff --git a/webkit/glue/dom_operations_private.h b/webkit/glue/dom_operations_private.h index 69676f4..403ca16 100644 --- a/webkit/glue/dom_operations_private.h +++ b/webkit/glue/dom_operations_private.h @@ -15,11 +15,11 @@ class String; } namespace WebKit { +class WebFrameImpl; class WebView; } class GURL; -class WebFrameImpl; namespace webkit_glue { @@ -27,8 +27,8 @@ namespace webkit_glue { // object corresponding to the content frame, otherwise return NULL. // The parameter is_frame_element indicates whether the input element // is frame/iframe element or not. -WebFrameImpl* GetWebFrameImplFromElement(WebCore::Element* element, - bool* is_frame_element); +WebKit::WebFrameImpl* GetWebFrameImplFromElement(WebCore::Element* element, + bool* is_frame_element); // If element is img, script or input type=image, then return its link refer // to the "src" attribute. If element is link, then return its link refer to @@ -50,8 +50,8 @@ bool ElementHasLegalLinkAttribute(const WebCore::Element* element, const WebCore::QualifiedName& attr_name); // Get pointer of WebFrameImpl from webview according to specific URL. -WebFrameImpl* GetWebFrameImplFromWebViewForSpecificURL(WebKit::WebView* view, - const GURL& page_url); +WebKit::WebFrameImpl* GetWebFrameImplFromWebViewForSpecificURL( + WebKit::WebView* view, const GURL& page_url); } // namespace webkit_glue diff --git a/webkit/glue/dom_serializer.cc b/webkit/glue/dom_serializer.cc index a4a0683..b3c7b28 100644 --- a/webkit/glue/dom_serializer.cc +++ b/webkit/glue/dom_serializer.cc @@ -73,14 +73,15 @@ MSVC_POP_WARNING(); #include "webkit/glue/dom_serializer.h" #include "base/string_util.h" +#include "webkit/api/src/WebFrameImpl.h" #include "webkit/glue/dom_operations.h" #include "webkit/glue/dom_operations_private.h" #include "webkit/glue/dom_serializer_delegate.h" #include "webkit/glue/entity_map.h" #include "webkit/glue/glue_util.h" -#include "webkit/glue/webframe_impl.h" using WebKit::WebFrame; +using WebKit::WebFrameImpl; namespace { diff --git a/webkit/glue/dom_serializer.h b/webkit/glue/dom_serializer.h index 3c59760..3c70431 100644 --- a/webkit/glue/dom_serializer.h +++ b/webkit/glue/dom_serializer.h @@ -11,8 +11,6 @@ #include "base/hash_tables.h" #include "googleurl/src/gurl.h" -class WebFrameImpl; - namespace WebCore { class Document; class Element; @@ -23,6 +21,7 @@ class TextEncoding; namespace WebKit { class WebFrame; +class WebFrameImpl; } namespace webkit_glue { @@ -71,7 +70,7 @@ class DomSerializer { private: // Specified frame which need to be serialized; - WebFrameImpl* specified_webframeimpl_; + WebKit::WebFrameImpl* specified_webframeimpl_; // This hash_map is used to map resource URL of original link to its local // file path. typedef base::hash_map<std::string, FilePath> LinkLocalPathMap; @@ -92,7 +91,7 @@ class DomSerializer { // Local directory name of all local resource files. const FilePath& local_directory_name_; // Vector for saving all frames which need to be serialized. - std::vector<WebFrameImpl*> frames_; + std::vector<WebKit::WebFrameImpl*> frames_; struct SerializeDomParam { // Frame URL of current processing document presented by GURL diff --git a/webkit/glue/dom_serializer_unittest.cc b/webkit/glue/dom_serializer_unittest.cc index 449227e..eeafc5e0 100644 --- a/webkit/glue/dom_serializer_unittest.cc +++ b/webkit/glue/dom_serializer_unittest.cc @@ -37,10 +37,12 @@ MSVC_POP_WARNING(); #include "webkit/glue/dom_serializer.h" #include "webkit/glue/dom_serializer_delegate.h" #include "webkit/glue/glue_util.h" -#include "webkit/glue/webframe_impl.h" +#include "webkit/api/src/WebFrameImpl.h" #include "webkit/tools/test_shell/simple_resource_loader_bridge.h" #include "webkit/tools/test_shell/test_shell_test.h" +using WebKit::WebFrameImpl; + namespace { class DomSerializerTests : public TestShellTest, diff --git a/webkit/glue/image_resource_fetcher.h b/webkit/glue/image_resource_fetcher.h index ef2f857..593b915 100644 --- a/webkit/glue/image_resource_fetcher.h +++ b/webkit/glue/image_resource_fetcher.h @@ -9,12 +9,11 @@ #include "webkit/glue/resource_fetcher.h" class SkBitmap; -class WebViewImpl; namespace webkit_glue { // ImageResourceFetcher handles downloading an image for a webview. Once -// downloading is done the hosting WebViewImpl is notified. ImageResourceFetcher +// downloading is done the supplied callback is notified. ImageResourceFetcher // is used to download the favicon and images for web apps. class ImageResourceFetcher { public: diff --git a/webkit/glue/password_autocomplete_listener_impl.cc b/webkit/glue/password_autocomplete_listener_impl.cc index 883e6bc..b955f53 100644 --- a/webkit/glue/password_autocomplete_listener_impl.cc +++ b/webkit/glue/password_autocomplete_listener_impl.cc @@ -13,10 +13,13 @@ #include "base/string_util.h" #include "webkit/api/public/WebNode.h" #include "webkit/api/public/WebVector.h" +#include "webkit/api/src/WebFrameImpl.h" +#include "webkit/api/src/WebViewImpl.h" #include "webkit/glue/glue_util.h" #include "webkit/glue/password_autocomplete_listener_impl.h" -#include "webkit/glue/webframe_impl.h" -#include "webkit/glue/webview_impl.h" + +using WebKit::WebFrameImpl; +using WebKit::WebViewImpl; namespace webkit_glue { @@ -47,8 +50,8 @@ void HTMLInputDelegate::RefreshAutofillPopup( const std::vector<string16>& suggestions, int default_suggestion_index) { WebFrameImpl* webframe = - WebFrameImpl::FromFrame(element_->document()->frame()); - WebViewImpl* webview = webframe->GetWebViewImpl(); + WebFrameImpl::fromFrame(element_->document()->frame()); + WebViewImpl* webview = webframe->viewImpl(); if (!webview) return; diff --git a/webkit/glue/webaccessibilitymanager_impl.cc b/webkit/glue/webaccessibilitymanager_impl.cc index fde40b3..f512a37 100644 --- a/webkit/glue/webaccessibilitymanager_impl.cc +++ b/webkit/glue/webaccessibilitymanager_impl.cc @@ -13,12 +13,13 @@ #include "webkit/glue/webaccessibilitymanager_impl.h" #include "webkit/api/public/WebAccessibilityObject.h" +#include "webkit/api/src/WebFrameImpl.h" +#include "webkit/api/src/WebViewImpl.h" #include "webkit/glue/glue_accessibility_object.h" #include "webkit/glue/glue_util.h" -#include "webkit/glue/webframe_impl.h" -#include "webkit/glue/webview_impl.h" using WebKit::WebAccessibilityObject; +using WebKit::WebFrameImpl; using WebKit::WebView; namespace webkit_glue { diff --git a/webkit/glue/webdevtoolsagent_impl.cc b/webkit/glue/webdevtoolsagent_impl.cc index e53fe46..ea84c14 100644 --- a/webkit/glue/webdevtoolsagent_impl.cc +++ b/webkit/glue/webdevtoolsagent_impl.cc @@ -26,14 +26,15 @@ #include "webkit/api/public/WebDataSource.h" #include "webkit/api/public/WebDevToolsAgentClient.h" +#include "webkit/api/public/WebFrame.h" #include "webkit/api/public/WebURL.h" #include "webkit/api/public/WebURLRequest.h" +#include "webkit/api/src/WebViewImpl.h" #include "webkit/glue/devtools/bound_object.h" #include "webkit/glue/devtools/debugger_agent_impl.h" #include "webkit/glue/devtools/debugger_agent_manager.h" #include "webkit/glue/glue_util.h" #include "webkit/glue/webdevtoolsagent_impl.h" -#include "webkit/glue/webview_impl.h" using WebCore::Document; using WebCore::InspectorBackend; @@ -53,10 +54,12 @@ using WebCore::V8Proxy; using WebKit::WebDataSource; using WebKit::WebDevToolsAgentClient; using WebKit::WebFrame; +using WebKit::WebFrameImpl; using WebKit::WebPoint; using WebKit::WebString; using WebKit::WebURL; using WebKit::WebURLRequest; +using WebKit::WebViewImpl; namespace { diff --git a/webkit/glue/webdevtoolsagent_impl.h b/webkit/glue/webdevtoolsagent_impl.h index 4bb19ff..7db9762 100644 --- a/webkit/glue/webdevtoolsagent_impl.h +++ b/webkit/glue/webdevtoolsagent_impl.h @@ -25,20 +25,20 @@ class String; namespace WebKit { class WebDevToolsAgentClient; class WebFrame; +class WebFrameImpl; +class WebViewImpl; } class BoundObject; class DebuggerAgentDelegateStub; class DebuggerAgentImpl; class Value; -class WebFrameImpl; -class WebViewImpl; class WebDevToolsAgentImpl : public WebKit::WebDevToolsAgent, public ToolsAgent, public DevToolsRpc::Delegate { public: - WebDevToolsAgentImpl(WebViewImpl* web_view_impl, + WebDevToolsAgentImpl(WebKit::WebViewImpl* web_view_impl, WebKit::WebDevToolsAgentClient* client); virtual ~WebDevToolsAgentImpl(); @@ -78,11 +78,11 @@ class WebDevToolsAgentImpl : public WebKit::WebDevToolsAgent, // Methods called by the glue. void SetMainFrameDocumentReady(bool ready); - void DidCommitLoadForFrame(WebViewImpl* webview, + void DidCommitLoadForFrame(WebKit::WebViewImpl* webview, WebKit::WebFrame* frame, bool is_new_navigation); - void WindowObjectCleared(WebFrameImpl* webframe); + void WindowObjectCleared(WebKit::WebFrameImpl* webframe); void ForceRepaint(); @@ -105,7 +105,7 @@ class WebDevToolsAgentImpl : public WebKit::WebDevToolsAgent, int host_id_; WebKit::WebDevToolsAgentClient* client_; - WebViewImpl* web_view_impl_; + WebKit::WebViewImpl* web_view_impl_; OwnPtr<DebuggerAgentDelegateStub> debugger_agent_delegate_stub_; OwnPtr<ToolsAgentDelegateStub> tools_agent_delegate_stub_; OwnPtr<ToolsAgentNativeDelegateStub> tools_agent_native_delegate_stub_; diff --git a/webkit/glue/webdevtoolsfrontend_impl.cc b/webkit/glue/webdevtoolsfrontend_impl.cc index db384fe..0cee5b5 100644 --- a/webkit/glue/webdevtoolsfrontend_impl.cc +++ b/webkit/glue/webdevtoolsfrontend_impl.cc @@ -27,21 +27,24 @@ #include "webkit/api/public/WebDevToolsFrontendClient.h" #include "webkit/api/public/WebFrame.h" #include "webkit/api/public/WebScriptSource.h" +#include "webkit/api/src/WebFrameImpl.h" +#include "webkit/api/src/WebViewImpl.h" #include "webkit/glue/devtools/bound_object.h" #include "webkit/glue/devtools/debugger_agent.h" #include "webkit/glue/devtools/devtools_rpc_js.h" #include "webkit/glue/devtools/tools_agent.h" #include "webkit/glue/glue_util.h" #include "webkit/glue/webdevtoolsfrontend_impl.h" -#include "webkit/glue/webview_impl.h" using namespace WebCore; using WebKit::WebDevToolsFrontend; using WebKit::WebDevToolsFrontendClient; using WebKit::WebFrame; +using WebKit::WebFrameImpl; using WebKit::WebScriptSource; using WebKit::WebString; using WebKit::WebView; +using WebKit::WebViewImpl; static v8::Local<v8::String> ToV8String(const String& s) { if (s.isNull()) @@ -124,7 +127,7 @@ WebDevToolsFrontendImpl::WebDevToolsFrontendImpl( client_(client), application_locale_(application_locale), loaded_(false) { - WebFrameImpl* frame = web_view_impl_->main_frame(); + WebFrameImpl* frame = web_view_impl_->mainFrameImpl(); v8::HandleScope scope; v8::Handle<v8::Context> frame_context = V8Proxy::context(frame->frame()); @@ -228,7 +231,7 @@ void WebDevToolsFrontendImpl::AddResourceSourceToFrame(int resource_id, } void WebDevToolsFrontendImpl::ExecuteScript(const Vector<String>& v) { - WebFrameImpl* frame = web_view_impl_->main_frame(); + WebFrameImpl* frame = web_view_impl_->mainFrameImpl(); v8::HandleScope scope; v8::Handle<v8::Context> frame_context = V8Proxy::context(frame->frame()); v8::Context::Scope context_scope(frame_context); @@ -264,7 +267,7 @@ v8::Handle<v8::Value> WebDevToolsFrontendImpl::JsReset( const v8::Arguments& args) { WebDevToolsFrontendImpl* frontend = static_cast<WebDevToolsFrontendImpl*>( v8::External::Cast(*args.Data())->Value()); - WebFrameImpl* frame = frontend->web_view_impl_->main_frame(); + WebFrameImpl* frame = frontend->web_view_impl_->mainFrameImpl(); frontend->tools_agent_native_delegate_impl_.set( new ToolsAgentNativeDelegateImpl(frame)); return v8::Undefined(); diff --git a/webkit/glue/webdevtoolsfrontend_impl.h b/webkit/glue/webdevtoolsfrontend_impl.h index 5f573a6..94e6bc0 100644 --- a/webkit/glue/webdevtoolsfrontend_impl.h +++ b/webkit/glue/webdevtoolsfrontend_impl.h @@ -22,20 +22,23 @@ class Page; class String; } +namespace WebKit { +class WebViewImpl; +} + class BoundObject; class JsDebuggerAgentBoundObj; class JsNetAgentBoundObj; class JsToolsAgentBoundObj; class ToolsAgentNativeDelegateImpl; class WebDevToolsClientDelegate; -class WebViewImpl; class WebDevToolsFrontendImpl : public WebKit::WebDevToolsFrontend, public DevToolsRpc::Delegate, public Noncopyable { public: WebDevToolsFrontendImpl( - WebViewImpl* web_view_impl, + WebKit::WebViewImpl* web_view_impl, WebKit::WebDevToolsFrontendClient* client, const String& application_locale); virtual ~WebDevToolsFrontendImpl(); @@ -80,7 +83,7 @@ class WebDevToolsFrontendImpl : public WebKit::WebDevToolsFrontend, static v8::Handle<v8::Value> JsDebuggerCommand( const v8::Arguments& args); - WebViewImpl* web_view_impl_; + WebKit::WebViewImpl* web_view_impl_; WebKit::WebDevToolsFrontendClient* client_; String application_locale_; OwnPtr<BoundObject> debugger_command_executor_obj_; diff --git a/webkit/glue/webframe_impl.cc b/webkit/glue/webframe_impl.cc deleted file mode 100644 index f3576ad..0000000 --- a/webkit/glue/webframe_impl.cc +++ /dev/null @@ -1,1921 +0,0 @@ -/* - * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// How ownership works -// ------------------- -// -// Big oh represents a refcounted relationship: owner O--- ownee -// -// WebView (for the toplevel frame only) -// O -// | -// Page O------- Frame (m_mainFrame) O-------O FrameView -// || -// || -// FrameLoader O-------- WebFrame (via FrameLoaderClient) -// -// FrameLoader and Frame are formerly one object that was split apart because -// it got too big. They basically have the same lifetime, hence the double line. -// -// WebFrame is refcounted and has one ref on behalf of the FrameLoader/Frame. -// This is not a normal reference counted pointer because that would require -// changing WebKit code that we don't control. Instead, it is created with this -// ref initially and it is removed when the FrameLoader is getting destroyed. -// -// WebFrames are created in two places, first in WebViewImpl when the root -// frame is created, and second in WebFrame::CreateChildFrame when sub-frames -// are created. WebKit will hook up this object to the FrameLoader/Frame -// and the refcount will be correct. -// -// How frames are destroyed -// ------------------------ -// -// The main frame is never destroyed and is re-used. The FrameLoader is re-used -// and a reference to the main frame is kept by the Page. -// -// When frame content is replaced, all subframes are destroyed. This happens -// in FrameLoader::detachFromParent for each subframe. -// -// Frame going away causes the FrameLoader to get deleted. In FrameLoader's -// destructor, it notifies its client with frameLoaderDestroyed. This calls -// WebFrame::Closing and then derefs the WebFrame and will cause it to be -// deleted (unless an external someone is also holding a reference). - -#include "config.h" - -#include <algorithm> -#include <string> - -#include "HTMLFormElement.h" // need this before Document.h -#include "Chrome.h" -#include "ChromiumBridge.h" -#include "ClipboardUtilitiesChromium.h" -#include "Console.h" -#include "Document.h" -#include "DocumentFragment.h" // Only needed for ReplaceSelectionCommand.h :( -#include "DocumentLoader.h" -#include "DocumentMarker.h" -#include "DOMWindow.h" -#include "Editor.h" -#include "EventHandler.h" -#include "FormState.h" -#include "FrameChromium.h" -#include "FrameLoader.h" -#include "FrameLoadRequest.h" -#include "FrameTree.h" -#include "FrameView.h" -#include "GraphicsContext.h" -#include "HTMLCollection.h" -#include "HTMLHeadElement.h" -#include "HTMLInputElement.h" -#include "HTMLFrameOwnerElement.h" -#include "HTMLLinkElement.h" -#include "HTMLNames.h" -#include "HistoryItem.h" -#include "InspectorController.h" -#if PLATFORM(DARWIN) -#include "LocalCurrentGraphicsContext.h" -#endif -#include "markup.h" -#include "Page.h" -#include "PlatformContextSkia.h" -#include "PrintContext.h" -#include "RenderFrame.h" -#if PLATFORM(WIN_OS) -#include "RenderThemeChromiumWin.h" -#endif -#include "RenderView.h" -#include "RenderWidget.h" -#include "ReplaceSelectionCommand.h" -#include "ResourceHandle.h" -#include "ResourceRequest.h" -#include "ScriptController.h" -#include "ScriptSourceCode.h" -#include "ScriptValue.h" -#include "ScrollbarTheme.h" -#include "ScrollTypes.h" -#include "SelectionController.h" -#include "Settings.h" -#include "SkiaUtils.h" -#include "SubstituteData.h" -#include "TextIterator.h" -#include "TextAffinity.h" -#include "XPathResult.h" -#include <wtf/CurrentTime.h> -#undef LOG - -#include "webkit/api/public/WebConsoleMessage.h" -#include "webkit/api/public/WebFindOptions.h" -#include "webkit/api/public/WebForm.h" -#include "webkit/api/public/WebFrameClient.h" -#include "webkit/api/public/WebHistoryItem.h" -#include "webkit/api/public/WebRange.h" -#include "webkit/api/public/WebRect.h" -#include "webkit/api/public/WebScriptSource.h" -#include "webkit/api/public/WebSecurityOrigin.h" -#include "webkit/api/public/WebSize.h" -#include "webkit/api/public/WebURLError.h" -#include "webkit/api/public/WebVector.h" -#include "webkit/api/src/DOMUtilitiesPrivate.h" -#include "webkit/api/src/PasswordAutocompleteListener.h" -#include "webkit/api/src/WebDataSourceImpl.h" -#include "webkit/glue/glue_util.h" -#include "webkit/glue/webframe_impl.h" -#include "webkit/glue/webview_impl.h" - -#if PLATFORM(LINUX) -#include <gdk/gdk.h> -#endif - -using WebCore::AtomicString; -using WebCore::ChromiumBridge; -using WebCore::Color; -using WebCore::Document; -using WebCore::DocumentFragment; -using WebCore::DocumentLoader; -using WebCore::ExceptionCode; -using WebCore::GraphicsContext; -using WebCore::HTMLFrameOwnerElement; -using WebCore::HTMLInputElement; -using WebCore::Frame; -using WebCore::FrameLoader; -using WebCore::FrameLoadRequest; -using WebCore::FrameLoadType; -using WebCore::FrameTree; -using WebCore::FrameView; -using WebCore::HistoryItem; -using WebCore::HTMLFormElement; -using WebCore::IntRect; -using WebCore::KURL; -using WebCore::Node; -using WebCore::Range; -using WebCore::ReloadIgnoringCacheData; -using WebCore::RenderObject; -using WebCore::ResourceError; -using WebCore::ResourceHandle; -using WebCore::ResourceRequest; -using WebCore::ResourceResponse; -using WebCore::VisibleSelection; -using WebCore::ScriptValue; -using WebCore::SecurityOrigin; -using WebCore::SharedBuffer; -using WebCore::String; -using WebCore::SubstituteData; -using WebCore::TextIterator; -using WebCore::Timer; -using WebCore::VisiblePosition; -using WebCore::XPathResult; - -using WebKit::PasswordAutocompleteListener; -using WebKit::WebCanvas; -using WebKit::WebConsoleMessage; -using WebKit::WebData; -using WebKit::WebDataSource; -using WebKit::WebDataSourceImpl; -using WebKit::WebFindOptions; -using WebKit::WebFrame; -using WebKit::WebFrameClient; -using WebKit::WebHistoryItem; -using WebKit::WebForm; -using WebKit::WebRange; -using WebKit::WebRect; -using WebKit::WebScriptSource; -using WebKit::WebSecurityOrigin; -using WebKit::WebSize; -using WebKit::WebString; -using WebKit::WebURL; -using WebKit::WebURLError; -using WebKit::WebURLRequest; -using WebKit::WebURLResponse; -using WebKit::WebVector; -using WebKit::WebView; - -// Key for a StatsCounter tracking how many WebFrames are active. -static const char* const kWebFrameActiveCount = "WebFrameActiveCount"; - -static const char* const kOSDType = "application/opensearchdescription+xml"; -static const char* const kOSDRel = "search"; - -// The separator between frames when the frames are converted to plain text. -static const wchar_t kFrameSeparator[] = L"\n\n"; -static const size_t kFrameSeparatorLen = arraysize(kFrameSeparator) - 1; - -// Backend for contentAsPlainText, this is a recursive function that gets -// the text for the current frame and all of its subframes. It will append -// the text of each frame in turn to the |output| up to |max_chars| length. -// -// The |frame| must be non-NULL. -static void FrameContentAsPlainText(size_t max_chars, Frame* frame, - Vector<UChar>* output) { - Document* doc = frame->document(); - if (!doc) - return; - - if (!frame->view()) - return; - - // TextIterator iterates over the visual representation of the DOM. As such, - // it requires you to do a layout before using it (otherwise it'll crash). - if (frame->view()->needsLayout()) - frame->view()->layout(); - - // Select the document body. - RefPtr<Range> range(doc->createRange()); - ExceptionCode exception = 0; - range->selectNodeContents(doc->body(), exception); - - if (exception == 0) { - // The text iterator will walk nodes giving us text. This is similar to - // the plainText() function in TextIterator.h, but we implement the maximum - // size and also copy the results directly into a wstring, avoiding the - // string conversion. - for (TextIterator it(range.get()); !it.atEnd(); it.advance()) { - const UChar* chars = it.characters(); - if (!chars) { - if (it.length() != 0) { - // It appears from crash reports that an iterator can get into a state - // where the character count is nonempty but the character pointer is - // NULL. advance()ing it will then just add that many to the NULL - // pointer which won't be caught in a NULL check but will crash. - // - // A NULL pointer and 0 length is common for some nodes. - // - // IF YOU CATCH THIS IN A DEBUGGER please let brettw know. We don't - // currently understand the conditions for this to occur. Ideally, the - // iterators would never get into the condition so we should fix them - // if we can. - ASSERT_NOT_REACHED(); - break; - } - - // Just got a NULL node, we can forge ahead! - continue; - } - size_t to_append = std::min(static_cast<size_t>(it.length()), - max_chars - output->size()); - output->append(chars, to_append); - if (output->size() >= max_chars) - return; // Filled up the buffer. - } - } - - // Recursively walk the children. - FrameTree* frame_tree = frame->tree(); - for (Frame* cur_child = frame_tree->firstChild(); cur_child; - cur_child = cur_child->tree()->nextSibling()) { - // Make sure the frame separator won't fill up the buffer, and give up if - // it will. The danger is if the separator will make the buffer longer than - // max_chars. This will cause the computation above: - // max_chars - output->size() - // to be a negative number which will crash when the subframe is added. - if (output->size() >= max_chars - kFrameSeparatorLen) - return; - - output->append(kFrameSeparator, kFrameSeparatorLen); - FrameContentAsPlainText(max_chars, cur_child, output); - if (output->size() >= max_chars) - return; // Filled up the buffer. - } -} - -// Simple class to override some of PrintContext behavior. -class ChromePrintContext : public WebCore::PrintContext { - public: - ChromePrintContext(Frame* frame) - : PrintContext(frame), - printed_page_width_(0) { - } - void begin(float width) { - ASSERT(!printed_page_width_); - printed_page_width_ = width; - WebCore::PrintContext::begin(printed_page_width_); - } - float getPageShrink(int pageNumber) const { - IntRect pageRect = m_pageRects[pageNumber]; - return printed_page_width_ / pageRect.width(); - } - // Spools the printed page, a subrect of m_frame. - // Skip the scale step. NativeTheme doesn't play well with scaling. Scaling - // is done browser side instead. - // Returns the scale to be applied. - float spoolPage(GraphicsContext& ctx, int pageNumber) { - IntRect pageRect = m_pageRects[pageNumber]; - float scale = printed_page_width_ / pageRect.width(); - - ctx.save(); - ctx.translate(static_cast<float>(-pageRect.x()), - static_cast<float>(-pageRect.y())); - ctx.clip(pageRect); - m_frame->view()->paintContents(&ctx, pageRect); - ctx.restore(); - return scale; - } - protected: - // Set when printing. - float printed_page_width_; - - private: - DISALLOW_COPY_AND_ASSIGN(ChromePrintContext); -}; - -static WebDataSource* DataSourceForDocLoader(DocumentLoader* loader) { - return loader ? WebDataSourceImpl::fromDocumentLoader(loader) : NULL; -} - - -// WebFrame ------------------------------------------------------------------- - -class WebFrameImpl::DeferredScopeStringMatches { - public: - DeferredScopeStringMatches(WebFrameImpl* webframe, - int identifier, - const WebString& search_text, - const WebFindOptions& options, - bool reset) - : ALLOW_THIS_IN_INITIALIZER_LIST( - timer_(this, &DeferredScopeStringMatches::DoTimeout)), - webframe_(webframe), - identifier_(identifier), - search_text_(search_text), - options_(options), - reset_(reset) { - timer_.startOneShot(0.0); - } - - private: - void DoTimeout(Timer<DeferredScopeStringMatches>*) { - webframe_->CallScopeStringMatches( - this, identifier_, search_text_, options_, reset_); - } - - Timer<DeferredScopeStringMatches> timer_; - RefPtr<WebFrameImpl> webframe_; - int identifier_; - WebString search_text_; - WebFindOptions options_; - bool reset_; -}; - - -// WebFrame ------------------------------------------------------------------- - -// static -WebFrame* WebFrame::frameForEnteredContext() { - Frame* frame = - WebCore::ScriptController::retrieveFrameForEnteredContext(); - return WebFrameImpl::FromFrame(frame); -} - -// static -WebFrame* WebFrame::frameForCurrentContext() { - Frame* frame = - WebCore::ScriptController::retrieveFrameForCurrentContext(); - return WebFrameImpl::FromFrame(frame); -} - -WebString WebFrameImpl::name() const { - return webkit_glue::StringToWebString(frame_->tree()->name()); -} - -WebURL WebFrameImpl::url() const { - const WebDataSource* ds = dataSource(); - if (!ds) - return WebURL(); - return ds->request().url(); -} - -WebURL WebFrameImpl::favIconURL() const { - WebCore::FrameLoader* frame_loader = frame_->loader(); - // The URL to the favicon may be in the header. As such, only - // ask the loader for the favicon if it's finished loading. - if (frame_loader->state() == WebCore::FrameStateComplete) { - const KURL& url = frame_loader->iconURL(); - if (!url.isEmpty()) { - return webkit_glue::KURLToWebURL(url); - } - } - return WebURL(); -} - -WebURL WebFrameImpl::openSearchDescriptionURL() const { - WebCore::FrameLoader* frame_loader = frame_->loader(); - if (frame_loader->state() == WebCore::FrameStateComplete && - frame_->document() && frame_->document()->head() && - !frame_->tree()->parent()) { - WebCore::HTMLHeadElement* head = frame_->document()->head(); - if (head) { - RefPtr<WebCore::HTMLCollection> children = head->children(); - for (Node* child = children->firstItem(); child != NULL; - child = children->nextItem()) { - WebCore::HTMLLinkElement* link_element = - WebKit::toHTMLLinkElement(child); - if (link_element && link_element->type() == kOSDType && - link_element->rel() == kOSDRel && !link_element->href().isEmpty()) { - return webkit_glue::KURLToWebURL(link_element->href()); - } - } - } - } - return WebURL(); -} - -WebSize WebFrameImpl::scrollOffset() const { - WebCore::FrameView* view = frameview(); - if (view) - return webkit_glue::IntSizeToWebSize(view->scrollOffset()); - - return WebSize(); -} - -WebSize WebFrameImpl::contentsSize() const { - return webkit_glue::IntSizeToWebSize(frame()->view()->contentsSize()); -} - -int WebFrameImpl::contentsPreferredWidth() const { - if ((frame_->document() != NULL) && - (frame_->document()->renderView() != NULL)) { - return frame_->document()->renderView()->minPrefWidth(); - } else { - return 0; - } -} - -bool WebFrameImpl::hasVisibleContent() const { - return frame()->view()->visibleWidth() > 0 && - frame()->view()->visibleHeight() > 0; -} - -WebView* WebFrameImpl::view() const { - return GetWebViewImpl(); -} - -WebFrame* WebFrameImpl::opener() const { - Frame* opener = NULL; - if (frame_) - opener = frame_->loader()->opener(); - return FromFrame(opener); -} - -WebFrame* WebFrameImpl::parent() const { - Frame *parent = NULL; - if (frame_) - parent = frame_->tree()->parent(); - return FromFrame(parent); -} - -WebFrame* WebFrameImpl::top() const { - if (frame_) - return FromFrame(frame_->tree()->top()); - - return NULL; -} - -WebFrame* WebFrameImpl::firstChild() const { - return FromFrame(frame()->tree()->firstChild()); -} - -WebFrame* WebFrameImpl::lastChild() const { - return FromFrame(frame()->tree()->lastChild()); -} - -WebFrame* WebFrameImpl::nextSibling() const { - return FromFrame(frame()->tree()->nextSibling()); -} - -WebFrame* WebFrameImpl::previousSibling() const { - return FromFrame(frame()->tree()->previousSibling()); -} - -WebFrame* WebFrameImpl::traverseNext(bool wrap) const { - return FromFrame(frame()->tree()->traverseNextWithWrap(wrap)); -} - -WebFrame* WebFrameImpl::traversePrevious(bool wrap) const { - return FromFrame(frame()->tree()->traversePreviousWithWrap(wrap)); -} - -WebFrame* WebFrameImpl::findChildByName(const WebKit::WebString& name) const { - return FromFrame(frame()->tree()->child( - webkit_glue::WebStringToString(name))); -} - -WebFrame* WebFrameImpl::findChildByExpression( - const WebKit::WebString& xpath) const { - if (xpath.isEmpty()) - return NULL; - - Document* document = frame_->document(); - - ExceptionCode ec = 0; - PassRefPtr<XPathResult> xpath_result = - document->evaluate(webkit_glue::WebStringToString(xpath), - document, - NULL, /* namespace */ - XPathResult::ORDERED_NODE_ITERATOR_TYPE, - NULL, /* XPathResult object */ - ec); - if (!xpath_result.get()) - return NULL; - - Node* node = xpath_result->iterateNext(ec); - - if (!node || !node->isFrameOwnerElement()) - return NULL; - HTMLFrameOwnerElement* frame_element = - static_cast<HTMLFrameOwnerElement*>(node); - return FromFrame(frame_element->contentFrame()); -} - -void WebFrameImpl::forms(WebVector<WebForm>& results) const { - if (!frame_) - return; - - RefPtr<WebCore::HTMLCollection> forms = frame_->document()->forms(); - size_t form_count = forms->length(); - - WebVector<WebForm> temp(form_count); - for (size_t i = 0; i < form_count; ++i) { - Node* node = forms->item(i); - // Strange but true, sometimes item can be NULL. - if (node) { - temp[i] = webkit_glue::HTMLFormElementToWebForm( - static_cast<HTMLFormElement*>(node)); - } - } - results.swap(temp); -} - -WebSecurityOrigin WebFrameImpl::securityOrigin() const { - if (!frame_ || !frame_->document()) - return WebSecurityOrigin(); - - return webkit_glue::SecurityOriginToWebSecurityOrigin( - frame_->document()->securityOrigin()); -} - -void WebFrameImpl::grantUniversalAccess() { - ASSERT(frame_ && frame_->document()); - if (frame_ && frame_->document()) { - frame_->document()->securityOrigin()->grantUniversalAccess(); - } -} - -NPObject* WebFrameImpl::windowObject() const { - if (!frame_) - return NULL; - - return frame_->script()->windowScriptNPObject(); -} - -void WebFrameImpl::bindToWindowObject(const WebString& name, - NPObject* object) { - ASSERT(frame_); - if (!frame_ || !frame_->script()->isEnabled()) - return; - - String key = webkit_glue::WebStringToString(name); -#if USE(V8) - frame_->script()->bindToWindowObject(frame_, key, object); -#else - notImplemented(); -#endif -} - -void WebFrameImpl::executeScript(const WebScriptSource& source) { - frame_->script()->executeScript( - WebCore::ScriptSourceCode( - webkit_glue::WebStringToString(source.code), - webkit_glue::WebURLToKURL(source.url), - source.startLine)); -} - -void WebFrameImpl::executeScriptInNewContext( - const WebScriptSource* sources_in, unsigned num_sources, - int extension_group) { - Vector<WebCore::ScriptSourceCode> sources; - - for (unsigned i = 0; i < num_sources; ++i) { - sources.append(WebCore::ScriptSourceCode( - webkit_glue::WebStringToString(sources_in[i].code), - webkit_glue::WebURLToKURL(sources_in[i].url), - sources_in[i].startLine)); - } - - frame_->script()->evaluateInNewContext(sources, extension_group); -} - -void WebFrameImpl::executeScriptInIsolatedWorld( - int world_id, const WebScriptSource* sources_in, unsigned num_sources, - int extension_group) { - Vector<WebCore::ScriptSourceCode> sources; - - for (unsigned i = 0; i < num_sources; ++i) { - sources.append(WebCore::ScriptSourceCode( - webkit_glue::WebStringToString(sources_in[i].code), - webkit_glue::WebURLToKURL(sources_in[i].url), - sources_in[i].startLine)); - } - - frame_->script()->evaluateInIsolatedWorld(world_id, sources, extension_group); -} - -void WebFrameImpl::addMessageToConsole(const WebConsoleMessage& message) { - ASSERT(frame()); - - WebCore::MessageLevel webcore_message_level; - switch (message.level) { - case WebConsoleMessage::LevelTip: - webcore_message_level = WebCore::TipMessageLevel; - break; - case WebConsoleMessage::LevelLog: - webcore_message_level = WebCore::LogMessageLevel; - break; - case WebConsoleMessage::LevelWarning: - webcore_message_level = WebCore::WarningMessageLevel; - break; - case WebConsoleMessage::LevelError: - webcore_message_level = WebCore::ErrorMessageLevel; - break; - default: - ASSERT_NOT_REACHED(); - return; - } - - frame()->domWindow()->console()->addMessage( - WebCore::OtherMessageSource, WebCore::LogMessageType, - webcore_message_level, webkit_glue::WebStringToString(message.text), - 1, String()); -} - -void WebFrameImpl::collectGarbage() { - if (!frame_) - return; - if (!frame_->settings()->isJavaScriptEnabled()) - return; - // TODO(mbelshe): Move this to the ScriptController and make it JS neutral. -#if USE(V8) - frame_->script()->collectGarbage(); -#else - notImplemented(); -#endif -} - -#if USE(V8) -// Returns the V8 context for this frame, or an empty handle if there is none. -v8::Local<v8::Context> WebFrameImpl::mainWorldScriptContext() const { - if (!frame_) - return v8::Local<v8::Context>(); - - return WebCore::V8Proxy::mainWorldContext(frame_); -} -#endif - -bool WebFrameImpl::insertStyleText( - const WebString& css, const WebString& id) { - Document* document = frame()->document(); - if (!document) - return false; - WebCore::Element* document_element = document->documentElement(); - if (!document_element) - return false; - - ExceptionCode err = 0; - - if (!id.isEmpty()) { - WebCore::Element* old_element = - document->getElementById(webkit_glue::WebStringToString(id)); - if (old_element) { - Node* parent = old_element->parent(); - if (!parent) - return false; - parent->removeChild(old_element, err); - } - } - - RefPtr<WebCore::Element> stylesheet = document->createElement( - WebCore::HTMLNames::styleTag, false); - if (!id.isEmpty()) - stylesheet->setAttribute(WebCore::HTMLNames::idAttr, - webkit_glue::WebStringToString(id)); - stylesheet->setTextContent(webkit_glue::WebStringToString(css), err); - ASSERT(!err); - WebCore::Node* first = document_element->firstChild(); - bool success = document_element->insertBefore(stylesheet, first, err); - ASSERT(success); - return success; -} - -void WebFrameImpl::reload() { - frame_->loader()->history()->saveDocumentAndScrollState(); - - stopLoading(); // Make sure existing activity stops. - frame_->loader()->reload(); -} - -void WebFrameImpl::loadRequest(const WebURLRequest& request) { - const ResourceRequest* resource_request = - webkit_glue::WebURLRequestToResourceRequest(&request); - ASSERT(resource_request); - - if (resource_request->url().protocolIs("javascript")) { - LoadJavaScriptURL(resource_request->url()); - return; - } - - stopLoading(); // Make sure existing activity stops. - frame_->loader()->load(*resource_request, false); -} - -void WebFrameImpl::loadHistoryItem(const WebHistoryItem& item) { - RefPtr<HistoryItem> history_item = - webkit_glue::WebHistoryItemToHistoryItem(item); - ASSERT(history_item.get()); - - stopLoading(); // Make sure existing activity stops. - - // If there is no current_item, which happens when we are navigating in - // session history after a crash, we need to manufacture one otherwise WebKit - // hoarks. This is probably the wrong thing to do, but it seems to work. - RefPtr<HistoryItem> current_item = frame_->loader()->history()->currentItem(); - if (!current_item) { - current_item = HistoryItem::create(); - current_item->setLastVisitWasFailure(true); - frame_->loader()->history()->setCurrentItem(current_item.get()); - GetWebViewImpl()->SetCurrentHistoryItem(current_item.get()); - } - - frame_->loader()->history()->goToItem(history_item.get(), - WebCore::FrameLoadTypeIndexedBackForward); -} - -void WebFrameImpl::loadData(const WebData& data, - const WebString& mime_type, - const WebString& text_encoding, - const WebURL& base_url, - const WebURL& unreachable_url, - bool replace) { - SubstituteData subst_data( - webkit_glue::WebDataToSharedBuffer(data), - webkit_glue::WebStringToString(mime_type), - webkit_glue::WebStringToString(text_encoding), - webkit_glue::WebURLToKURL(unreachable_url)); - ASSERT(subst_data.isValid()); - - stopLoading(); // Make sure existing activity stops. - frame_->loader()->load(ResourceRequest(webkit_glue::WebURLToKURL(base_url)), - subst_data, false); - if (replace) { - // Do this to force WebKit to treat the load as replacing the currently - // loaded page. - frame_->loader()->setReplacing(); - } -} - -void WebFrameImpl::loadHTMLString(const WebData& data, - const WebURL& base_url, - const WebURL& unreachable_url, - bool replace) { - loadData(data, - WebString::fromUTF8("text/html"), - WebString::fromUTF8("UTF-8"), - base_url, - unreachable_url, - replace); -} - -bool WebFrameImpl::isLoading() const { - if (!frame_) - return false; - return frame_->loader()->isLoading(); -} - -void WebFrameImpl::stopLoading() { - if (!frame_) - return; - - // TODO(darin): Figure out what we should really do here. It seems like a - // bug that FrameLoader::stopLoading doesn't call stopAllLoaders. - frame_->loader()->stopAllLoaders(); - frame_->loader()->stopLoading(WebCore::UnloadEventPolicyNone); -} - -WebDataSource* WebFrameImpl::provisionalDataSource() const { - FrameLoader* frame_loader = frame_->loader(); - - // We regard the policy document loader as still provisional. - DocumentLoader* doc_loader = frame_loader->provisionalDocumentLoader(); - if (!doc_loader) - doc_loader = frame_loader->policyDocumentLoader(); - - return DataSourceForDocLoader(doc_loader); -} - -WebDataSource* WebFrameImpl::dataSource() const { - return DataSourceForDocLoader(frame_->loader()->documentLoader()); -} - -WebHistoryItem WebFrameImpl::previousHistoryItem() const { - // We use the previous item here because documentState (filled-out forms) - // only get saved to history when it becomes the previous item. The caller - // is expected to query the history item after a navigation occurs, after - // the desired history item has become the previous entry. - return webkit_glue::HistoryItemToWebHistoryItem( - GetWebViewImpl()->GetPreviousHistoryItem()); -} - -WebHistoryItem WebFrameImpl::currentHistoryItem() const { - frame_->loader()->history()->saveDocumentAndScrollState(); - - return webkit_glue::HistoryItemToWebHistoryItem( - frame_->page()->backForwardList()->currentItem()); -} - -void WebFrameImpl::enableViewSourceMode(bool enable) { - if (frame_) - frame_->setInViewSourceMode(enable); -} - -bool WebFrameImpl::isViewSourceModeEnabled() const { - if (frame_) - return frame_->inViewSourceMode(); - - return false; -} - -void WebFrameImpl::setReferrerForRequest( - WebURLRequest& request, const WebURL& referrer_url) { - String referrer; - if (referrer_url.isEmpty()) { - referrer = frame_->loader()->outgoingReferrer(); - } else { - referrer = webkit_glue::WebStringToString(referrer_url.spec().utf16()); - } - if (SecurityOrigin::shouldHideReferrer( - webkit_glue::WebURLToKURL(request.url()), referrer)) - return; - request.setHTTPHeaderField(WebString::fromUTF8("Referer"), - webkit_glue::StringToWebString(referrer)); -} - -void WebFrameImpl::dispatchWillSendRequest(WebURLRequest& request) { - ResourceResponse response; - frame_->loader()->client()->dispatchWillSendRequest(NULL, 0, - *webkit_glue::WebURLRequestToMutableResourceRequest(&request), - response); -} - -void WebFrameImpl::commitDocumentData(const char* data, size_t data_len) { - DocumentLoader* document_loader = frame_->loader()->documentLoader(); - - // Set the text encoding. This calls begin() for us. It is safe to call - // this multiple times (Mac does: page/mac/WebCoreFrameBridge.mm). - bool user_chosen = true; - String encoding = document_loader->overrideEncoding(); - if (encoding.isNull()) { - user_chosen = false; - encoding = document_loader->response().textEncodingName(); - } - frame_->loader()->setEncoding(encoding, user_chosen); - - // NOTE: mac only does this if there is a document - frame_->loader()->addData(data, data_len); -} - -unsigned WebFrameImpl::unloadListenerCount() const { - return frame()->domWindow()->pendingUnloadEventListeners(); -} - -bool WebFrameImpl::isProcessingUserGesture() const { - return frame()->loader()->isProcessingUserGesture(); -} - -bool WebFrameImpl::willSuppressOpenerInNewFrame() const { - return frame()->loader()->suppressOpenerInNewFrame(); -} - -void WebFrameImpl::replaceSelection(const WebString& wtext) { - String text = webkit_glue::WebStringToString(wtext); - RefPtr<DocumentFragment> fragment = createFragmentFromText( - frame()->selection()->toNormalizedRange().get(), text); - WebCore::applyCommand(WebCore::ReplaceSelectionCommand::create( - frame()->document(), fragment.get(), false, true, true)); -} - -void WebFrameImpl::insertText(const WebString& text) { - frame()->editor()->insertText(webkit_glue::WebStringToString(text), NULL); -} - -void WebFrameImpl::setMarkedText( - const WebString& text, unsigned location, unsigned length) { - WebCore::Editor* editor = frame()->editor(); - WebCore::String str = webkit_glue::WebStringToString(text); - - editor->confirmComposition(str); - - WTF::Vector<WebCore::CompositionUnderline> decorations; - editor->setComposition(str, decorations, location, length); -} - -void WebFrameImpl::unmarkText() { - frame()->editor()->confirmCompositionWithoutDisturbingSelection(); -} - -bool WebFrameImpl::hasMarkedText() const { - return frame()->editor()->hasComposition(); -} - -WebRange WebFrameImpl::markedRange() const { - return webkit_glue::RangeToWebRange(frame()->editor()->compositionRange()); -} - -bool WebFrameImpl::executeCommand(const WebString& name) { - ASSERT(frame()); - - if (name.length() <= 2) - return false; - - // Since we don't have NSControl, we will convert the format of command - // string and call the function on Editor directly. - String command = webkit_glue::WebStringToString(name); - - // Make sure the first letter is upper case. - command.replace(0, 1, command.substring(0, 1).upper()); - - // Remove the trailing ':' if existing. - if (command[command.length() - 1] == UChar(':')) - command = command.substring(0, command.length() - 1); - - bool rv = true; - - // Specially handling commands that Editor::execCommand does not directly - // support. - if (command == "DeleteToEndOfParagraph") { - WebCore::Editor* editor = frame()->editor(); - if (!editor->deleteWithDirection(WebCore::SelectionController::FORWARD, - WebCore::ParagraphBoundary, - true, - false)) { - editor->deleteWithDirection(WebCore::SelectionController::FORWARD, - WebCore::CharacterGranularity, - true, - false); - } - } else if (command == "Indent") { - frame()->editor()->indent(); - } else if (command == "Outdent") { - frame()->editor()->outdent(); - } else if (command == "DeleteBackward") { - rv = frame()->editor()->command(AtomicString("BackwardDelete")).execute(); - } else if (command == "DeleteForward") { - rv = frame()->editor()->command(AtomicString("ForwardDelete")).execute(); - } else if (command == "AdvanceToNextMisspelling") { - // False must be passed here, or the currently selected word will never be - // skipped. - frame()->editor()->advanceToNextMisspelling(false); - } else if (command == "ToggleSpellPanel") { - frame()->editor()->showSpellingGuessPanel(); - } else { - rv = frame()->editor()->command(command).execute(); - } - return rv; -} - -bool WebFrameImpl::executeCommand(const WebString& name, - const WebString& value) { - ASSERT(frame()); - WebCore::String web_name = webkit_glue::WebStringToString(name); - - // moveToBeginningOfDocument and moveToEndfDocument are only handled by WebKit - // for editable nodes. - if (!frame()->editor()->canEdit() && - web_name == "moveToBeginningOfDocument") { - return GetWebViewImpl()->PropagateScroll(WebCore::ScrollUp, - WebCore::ScrollByDocument); - } else if (!frame()->editor()->canEdit() && - web_name == "moveToEndOfDocument") { - return GetWebViewImpl()->PropagateScroll(WebCore::ScrollDown, - WebCore::ScrollByDocument); - } else { - return frame()->editor()->command(web_name). - execute(webkit_glue::WebStringToString(value)); - } -} - -bool WebFrameImpl::isCommandEnabled(const WebString& name) const { - ASSERT(frame()); - return frame()->editor()->command(webkit_glue::WebStringToString(name)). - isEnabled(); -} - -void WebFrameImpl::enableContinuousSpellChecking(bool enable) { - if (enable == isContinuousSpellCheckingEnabled()) - return; - frame()->editor()->toggleContinuousSpellChecking(); -} - -bool WebFrameImpl::isContinuousSpellCheckingEnabled() const { - return frame()->editor()->isContinuousSpellCheckingEnabled(); -} - -bool WebFrameImpl::hasSelection() const { - // frame()->selection()->isNone() never returns true. - return (frame()->selection()->start() != frame()->selection()->end()); -} - -WebRange WebFrameImpl::selectionRange() const { - return webkit_glue::RangeToWebRange( - frame()->selection()->toNormalizedRange()); -} - -WebString WebFrameImpl::selectionAsText() const { - RefPtr<Range> range = frame()->selection()->toNormalizedRange(); - if (!range.get()) - return WebString(); - - String text = range->text(); -#if PLATFORM(WIN_OS) - WebCore::replaceNewlinesWithWindowsStyleNewlines(text); -#endif - WebCore::replaceNBSPWithSpace(text); - return webkit_glue::StringToWebString(text); -} - -WebString WebFrameImpl::selectionAsMarkup() const { - RefPtr<Range> range = frame()->selection()->toNormalizedRange(); - if (!range.get()) - return WebString(); - - String markup = WebCore::createMarkup(range.get(), 0); - return webkit_glue::StringToWebString(markup); -} - -int WebFrameImpl::printBegin(const WebSize& page_size) { - ASSERT(!frame()->document()->isFrameSet()); - - print_context_.set(new ChromePrintContext(frame())); - WebCore::FloatRect rect(0, 0, - static_cast<float>(page_size.width), - static_cast<float>(page_size.height)); - print_context_->begin(rect.width()); - float page_height; - // We ignore the overlays calculation for now since they are generated in the - // browser. page_height is actually an output parameter. - print_context_->computePageRects(rect, 0, 0, 1.0, page_height); - return print_context_->pageCount(); -} - -float WebFrameImpl::getPrintPageShrink(int page) { - // Ensure correct state. - if (!print_context_.get() || page < 0) { - ASSERT_NOT_REACHED(); - return 0; - } - - return print_context_->getPageShrink(page); -} - -float WebFrameImpl::printPage(int page, WebCanvas* canvas) { - // Ensure correct state. - if (!print_context_.get() || page < 0 || !frame() || !frame()->document()) { - ASSERT_NOT_REACHED(); - return 0; - } - -#if PLATFORM(WIN_OS) || PLATFORM(LINUX) || PLATFORM(FREEBSD) - PlatformContextSkia context(canvas); - GraphicsContext spool(&context); -#elif PLATFORM(DARWIN) - GraphicsContext spool(canvas); - WebCore::LocalCurrentGraphicsContext localContext(&spool); -#endif - - return print_context_->spoolPage(spool, page); -} - -void WebFrameImpl::printEnd() { - ASSERT(print_context_.get()); - if (print_context_.get()) - print_context_->end(); - print_context_.clear(); -} - -bool WebFrameImpl::find(int request_id, - const WebString& search_text, - const WebFindOptions& options, - bool wrap_within_frame, - WebRect* selection_rect) { - WebCore::String webcore_string = webkit_glue::WebStringToString(search_text); - - WebFrameImpl* const main_frame_impl = GetWebViewImpl()->main_frame(); - - if (!options.findNext) - frame()->page()->unmarkAllTextMatches(); - else - SetMarkerActive(active_match_.get(), false); // Active match is changing. - - // Starts the search from the current selection. - bool start_in_selection = true; - - // If the user has selected something since the last Find operation we want - // to start from there. Otherwise, we start searching from where the last Find - // operation left off (either a Find or a FindNext operation). - VisibleSelection selection(frame()->selection()->selection()); - if (selection.isNone() && active_match_) { - selection = VisibleSelection(active_match_.get()); - frame()->selection()->setSelection(selection); - } - - ASSERT(frame() && frame()->view()); - bool found = frame()->findString(webcore_string, options.forward, - options.matchCase, wrap_within_frame, - start_in_selection); - if (found) { - // Store which frame was active. This will come in handy later when we - // change the active match ordinal below. - WebFrameImpl* old_active_frame = main_frame_impl->active_match_frame_; - // Set this frame as the active frame (the one with the active highlight). - main_frame_impl->active_match_frame_ = this; - - // We found something, so we can now query the selection for its position. - VisibleSelection new_selection(frame()->selection()->selection()); - IntRect curr_selection_rect; - - // If we thought we found something, but it couldn't be selected (perhaps - // because it was marked -webkit-user-select: none), we can't set it to - // be active but we still continue searching. This matches Safari's - // behavior, including some oddities when selectable and un-selectable text - // are mixed on a page: see https://bugs.webkit.org/show_bug.cgi?id=19127. - if (new_selection.isNone() || - (new_selection.start() == new_selection.end())) { - active_match_ = NULL; - } else { - active_match_ = new_selection.toNormalizedRange(); - curr_selection_rect = active_match_->boundingBox(); - SetMarkerActive(active_match_.get(), true); // Active. - // WebKit draws the highlighting for all matches. - executeCommand(WebString::fromUTF8("Unselect")); - } - - if (!options.findNext) { - // This is a Find operation, so we set the flag to ask the scoping effort - // to find the active rect for us so we can update the ordinal (n of m). - locating_active_rect_ = true; - } else { - if (old_active_frame != this) { - // If the active frame has changed it means that we have a multi-frame - // page and we just switch to searching in a new frame. Then we just - // want to reset the index. - if (options.forward) - active_match_index_ = 0; - else - active_match_index_ = last_match_count_ - 1; - } else { - // We are still the active frame, so increment (or decrement) the - // |active_match_index|, wrapping if needed (on single frame pages). - options.forward ? ++active_match_index_ : --active_match_index_; - if (active_match_index_ + 1 > last_match_count_) - active_match_index_ = 0; - if (active_match_index_ + 1 == 0) - active_match_index_ = last_match_count_ - 1; - } - if (selection_rect) { - WebRect rect = webkit_glue::IntRectToWebRect( - frame()->view()->convertToContainingWindow(curr_selection_rect)); - rect.x -= frameview()->scrollOffset().width(); - rect.y -= frameview()->scrollOffset().height(); - *selection_rect = rect; - - ReportFindInPageSelection(rect, - active_match_index_ + 1, - request_id); - } - } - } else { - // Nothing was found in this frame. - active_match_ = NULL; - - // Erase all previous tickmarks and highlighting. - InvalidateArea(INVALIDATE_ALL); - } - - return found; -} - -void WebFrameImpl::stopFinding(bool clear_selection) { - if (!clear_selection) - SetFindEndstateFocusAndSelection(); - cancelPendingScopingEffort(); - - // Remove all markers for matches found and turn off the highlighting. - if (!parent()) - frame()->document()->removeMarkers(WebCore::DocumentMarker::TextMatch); - frame()->setMarkedTextMatchesAreHighlighted(false); - - // Let the frame know that we don't want tickmarks or highlighting anymore. - InvalidateArea(INVALIDATE_ALL); -} - -void WebFrameImpl::scopeStringMatches(int request_id, - const WebString& search_text, - const WebFindOptions& options, - bool reset) { - if (!ShouldScopeMatches(search_text)) - return; - - WebFrameImpl* main_frame_impl = GetWebViewImpl()->main_frame(); - - if (reset) { - // This is a brand new search, so we need to reset everything. - // Scoping is just about to begin. - scoping_complete_ = false; - // Clear highlighting for this frame. - if (frame()->markedTextMatchesAreHighlighted()) - frame()->page()->unmarkAllTextMatches(); - // Clear the counters from last operation. - last_match_count_ = 0; - next_invalidate_after_ = 0; - - resume_scoping_from_range_ = NULL; - - main_frame_impl->frames_scoping_count_++; - - // Now, defer scoping until later to allow find operation to finish quickly. - ScopeStringMatchesSoon( - request_id, - search_text, - options, - false); // false=we just reset, so don't do it again. - return; - } - - WebCore::String webcore_string = webkit_glue::String16ToString(search_text); - - RefPtr<Range> search_range(rangeOfContents(frame()->document())); - - ExceptionCode ec = 0, ec2 = 0; - if (resume_scoping_from_range_.get()) { - // This is a continuation of a scoping operation that timed out and didn't - // complete last time around, so we should start from where we left off. - search_range->setStart(resume_scoping_from_range_->startContainer(), - resume_scoping_from_range_->startOffset(ec2) + 1, - ec); - if (ec != 0 || ec2 != 0) { - if (ec2 != 0) // A non-zero |ec| happens when navigating during search. - ASSERT_NOT_REACHED(); - return; - } - } - - // This timeout controls how long we scope before releasing control. This - // value does not prevent us from running for longer than this, but it is - // periodically checked to see if we have exceeded our allocated time. - const double kTimeout = 0.1; // seconds - - int match_count = 0; - bool timeout = false; - double start_time = currentTime(); - do { - // Find next occurrence of the search string. - // TODO(finnur): (http://b/1088245) This WebKit operation may run - // for longer than the timeout value, and is not interruptible as it is - // currently written. We may need to rewrite it with interruptibility in - // mind, or find an alternative. - RefPtr<Range> result_range(findPlainText(search_range.get(), - webcore_string, - true, - options.matchCase)); - if (result_range->collapsed(ec)) { - if (!result_range->startContainer()->isInShadowTree()) - break; - - search_range = rangeOfContents(frame()->document()); - search_range->setStartAfter( - result_range->startContainer()->shadowAncestorNode(), ec); - 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. (This function is based on the implementation of - // Frame::markAllMatchesForText, which is where this safeguard comes from). - VisiblePosition new_start = endVisiblePosition(result_range.get(), - WebCore::DOWNSTREAM); - if (new_start == startVisiblePosition(search_range.get(), - WebCore::DOWNSTREAM)) - break; - - // Only treat the result as a match if it is visible - if (frame()->editor()->insideVisibleArea(result_range.get())) { - ++match_count; - - setStart(search_range.get(), new_start); - Node* shadow_tree_root = search_range->shadowTreeRootNode(); - if (search_range->collapsed(ec) && shadow_tree_root) - search_range->setEnd(shadow_tree_root, - shadow_tree_root->childNodeCount(), ec); - - // Catch a special case where Find found something but doesn't know what - // the bounding box for it is. In this case we set the first match we find - // as the active rect. - IntRect result_bounds = result_range->boundingBox(); - IntRect active_selection_rect; - if (locating_active_rect_) { - active_selection_rect = active_match_.get() ? - active_match_->boundingBox() : result_bounds; - } - - // If the Find function found a match it will have stored where the - // match was found in active_selection_rect_ on the current frame. If we - // find this rect during scoping it means we have found the active - // tickmark. - bool found_active_match = false; - if (locating_active_rect_ && (active_selection_rect == result_bounds)) { - // We have found the active tickmark frame. - main_frame_impl->active_match_frame_ = this; - found_active_match = true; - // We also know which tickmark is active now. - active_match_index_ = match_count - 1; - // To stop looking for the active tickmark, we set this flag. - locating_active_rect_ = false; - - // Notify browser of new location for the selected rectangle. - result_bounds.move(-frameview()->scrollOffset().width(), - -frameview()->scrollOffset().height()); - ReportFindInPageSelection( - webkit_glue::IntRectToWebRect( - frame()->view()->convertToContainingWindow(result_bounds)), - active_match_index_ + 1, - request_id); - } - - AddMarker(result_range.get(), found_active_match); - } - - resume_scoping_from_range_ = result_range; - timeout = (currentTime() - start_time) >= kTimeout; - } while (!timeout); - - // Remember what we search for last time, so we can skip searching if more - // letters are added to the search string (and last outcome was 0). - last_search_string_ = search_text; - - if (match_count > 0) { - frame()->setMarkedTextMatchesAreHighlighted(true); - - last_match_count_ += match_count; - - // Let the mainframe know how much we found during this pass. - main_frame_impl->increaseMatchCount(match_count, request_id); - } - - if (timeout) { - // If we found anything during this pass, we should redraw. However, we - // don't want to spam too much if the page is extremely long, so if we - // reach a certain point we start throttling the redraw requests. - if (match_count > 0) - InvalidateIfNecessary(); - - // Scoping effort ran out of time, lets ask for another time-slice. - ScopeStringMatchesSoon( - request_id, - search_text, - options, - false); // don't reset. - return; // Done for now, resume work later. - } - - // This frame has no further scoping left, so it is done. Other frames might, - // of course, continue to scope matches. - scoping_complete_ = true; - main_frame_impl->frames_scoping_count_--; - - // If this is the last frame to finish scoping we need to trigger the final - // update to be sent. - if (main_frame_impl->frames_scoping_count_ == 0) - main_frame_impl->increaseMatchCount(0, request_id); - - // This frame is done, so show any scrollbar tickmarks we haven't drawn yet. - InvalidateArea(INVALIDATE_SCROLLBAR); -} - -void WebFrameImpl::cancelPendingScopingEffort() { - deleteAllValues(deferred_scoping_work_); - deferred_scoping_work_.clear(); - - active_match_index_ = -1; -} - -void WebFrameImpl::increaseMatchCount(int count, int request_id) { - // This function should only be called on the mainframe. - ASSERT(!parent()); - - total_matchcount_ += count; - - // Update the UI with the latest findings. - if (client()) { - client()->reportFindInPageMatchCount( - request_id, total_matchcount_, frames_scoping_count_ == 0); - } -} - -void WebFrameImpl::ReportFindInPageSelection(const WebRect& selection_rect, - int active_match_ordinal, - int request_id) { - // Update the UI with the latest selection rect. - if (client()) { - client()->reportFindInPageSelection( - request_id, OrdinalOfFirstMatchForFrame(this) + active_match_ordinal, - selection_rect); - } -} - -void WebFrameImpl::resetMatchCount() { - total_matchcount_ = 0; - frames_scoping_count_ = 0; -} - -WebURL WebFrameImpl::completeURL(const WebString& url) const { - if (!frame_ || !frame_->document()) - return WebURL(); - - return webkit_glue::KURLToWebURL( - frame_->document()->completeURL(webkit_glue::WebStringToString(url))); -} - -WebString WebFrameImpl::contentAsText(size_t max_chars) const { - if (!frame_) - return WebString(); - - Vector<UChar> text; - FrameContentAsPlainText(max_chars, frame_, &text); - return webkit_glue::StringToWebString(String::adopt(text)); -} - -WebString WebFrameImpl::contentAsMarkup() const { - return webkit_glue::StringToWebString(createFullMarkup(frame_->document())); -} - -// WebFrameImpl public --------------------------------------------------------- - -int WebFrameImpl::live_object_count_ = 0; - -PassRefPtr<WebFrameImpl> WebFrameImpl::create(WebFrameClient* client) { - return adoptRef(new WebFrameImpl(ClientHandle::create(client))); -} - -WebFrameImpl::WebFrameImpl(PassRefPtr<ClientHandle> client_handle) - : ALLOW_THIS_IN_INITIALIZER_LIST(frame_loader_client_(this)), - client_handle_(client_handle), - active_match_frame_(NULL), - active_match_index_(-1), - locating_active_rect_(false), - resume_scoping_from_range_(NULL), - last_match_count_(-1), - total_matchcount_(-1), - frames_scoping_count_(-1), - scoping_complete_(false), - next_invalidate_after_(0) { - ChromiumBridge::incrementStatsCounter(kWebFrameActiveCount); - live_object_count_++; -} - -WebFrameImpl::~WebFrameImpl() { - ChromiumBridge::decrementStatsCounter(kWebFrameActiveCount); - live_object_count_--; - - cancelPendingScopingEffort(); - ClearPasswordListeners(); -} - -void WebFrameImpl::InitMainFrame(WebViewImpl* webview_impl) { - RefPtr<Frame> frame = - Frame::create(webview_impl->page(), 0, &frame_loader_client_); - frame_ = frame.get(); - - // Add reference on behalf of FrameLoader. See comments in - // WebFrameLoaderClient::frameLoaderDestroyed for more info. - ref(); - - // We must call init() after frame_ is assigned because it is referenced - // during init(). - frame_->init(); -} - -PassRefPtr<Frame> WebFrameImpl::CreateChildFrame( - const FrameLoadRequest& request, HTMLFrameOwnerElement* owner_element) { - // TODO(darin): share code with initWithName() - - RefPtr<WebFrameImpl> webframe(adoptRef(new WebFrameImpl(client_handle_))); - - // Add an extra ref on behalf of the Frame/FrameLoader, which references the - // WebFrame via the FrameLoaderClient interface. See the comment at the top - // of this file for more info. - webframe->ref(); - - RefPtr<Frame> child_frame = Frame::create( - frame_->page(), owner_element, &webframe->frame_loader_client_); - webframe->frame_ = child_frame.get(); - - child_frame->tree()->setName(request.frameName()); - - frame_->tree()->appendChild(child_frame); - - // Frame::init() can trigger onload event in the parent frame, - // which may detach this frame and trigger a null-pointer access - // in FrameTree::removeChild. Move init() after appendChild call - // so that webframe->frame_ is in the tree before triggering - // onload event handler. - // Because the event handler may set webframe->frame_ to null, - // it is necessary to check the value after calling init() and - // return without loading URL. - // (b:791612) - child_frame->init(); // create an empty document - if (!child_frame->tree()->parent()) - return NULL; - - frame_->loader()->loadURLIntoChildFrame( - request.resourceRequest().url(), - request.resourceRequest().httpReferrer(), - child_frame.get()); - - // A synchronous navigation (about:blank) would have already processed - // onload, so it is possible for the frame to have already been destroyed by - // script in the page. - if (!child_frame->tree()->parent()) - return NULL; - - return child_frame.release(); -} - -void WebFrameImpl::Layout() { - // layout this frame - FrameView* view = frame_->view(); - if (view) - view->layoutIfNeededRecursive(); -} - -void WebFrameImpl::Paint(WebCanvas* canvas, const WebRect& rect) { - if (rect.isEmpty()) - return; - IntRect dirty_rect(webkit_glue::WebRectToIntRect(rect)); -#if WEBKIT_USING_CG - GraphicsContext gc(canvas); - WebCore::LocalCurrentGraphicsContext localContext(&gc); -#elif WEBKIT_USING_SKIA - PlatformContextSkia context(canvas); - - // PlatformGraphicsContext is actually a pointer to PlatformContextSkia - GraphicsContext gc(reinterpret_cast<PlatformGraphicsContext*>(&context)); -#else - notImplemented(); -#endif - gc.save(); - if (frame_->document() && frameview()) { - gc.clip(dirty_rect); - frameview()->paint(&gc, dirty_rect); - frame_->page()->inspectorController()->drawNodeHighlight(gc); - } else { - gc.fillRect(dirty_rect, Color::white); - } - gc.restore(); -} - -void WebFrameImpl::CreateFrameView() { - ASSERT(frame_); // If frame_ doesn't exist, we probably didn't init properly. - - WebCore::Page* page = frame_->page(); - ASSERT(page); - - ASSERT(page->mainFrame() != NULL); - - bool is_main_frame = frame_ == page->mainFrame(); - if (is_main_frame && frame_->view()) - frame_->view()->setParentVisible(false); - - frame_->setView(0); - - WebViewImpl* web_view = GetWebViewImpl(); - - RefPtr<WebCore::FrameView> view; - if (is_main_frame) { - IntSize size = webkit_glue::WebSizeToIntSize(web_view->size()); - view = FrameView::create(frame_, size); - } else { - view = FrameView::create(frame_); - } - - frame_->setView(view); - - if (web_view->isTransparent()) - view->setTransparent(true); - - // TODO(darin): The Mac code has a comment about this possibly being - // unnecessary. See installInFrame in WebCoreFrameBridge.mm - if (frame_->ownerRenderer()) - frame_->ownerRenderer()->setWidget(view.get()); - - if (HTMLFrameOwnerElement* owner = frame_->ownerElement()) { - view->setCanHaveScrollbars( - owner->scrollingMode() != WebCore::ScrollbarAlwaysOff); - } - - if (is_main_frame) - view->setParentVisible(true); -} - -// static -WebFrameImpl* WebFrameImpl::FromFrame(WebCore::Frame* frame) { - if (!frame) - return NULL; - return static_cast<WebFrameLoaderClient*>( - frame->loader()->client())->webframe(); -} - -WebViewImpl* WebFrameImpl::GetWebViewImpl() const { - if (!frame_) - return NULL; - - return WebViewImpl::FromPage(frame_->page()); -} - -WebDataSourceImpl* WebFrameImpl::GetDataSourceImpl() const { - return static_cast<WebDataSourceImpl*>(dataSource()); -} - -WebDataSourceImpl* WebFrameImpl::GetProvisionalDataSourceImpl() const { - return static_cast<WebDataSourceImpl*>(provisionalDataSource()); -} - -void WebFrameImpl::SetFindEndstateFocusAndSelection() { - WebFrameImpl* main_frame_impl = GetWebViewImpl()->main_frame(); - - if (this == main_frame_impl->active_match_frame() && - active_match_.get()) { - // If the user has set the selection since the match was found, we - // don't focus anything. - VisibleSelection selection(frame()->selection()->selection()); - if (!selection.isNone()) - return; - - // Try to find the first focusable node up the chain, which will, for - // example, focus links if we have found text within the link. - Node* node = active_match_->firstNode(); - while (node && !node->isFocusable() && node != frame()->document()) - node = node->parent(); - - if (node && node != frame()->document()) { - // Found a focusable parent node. Set focus to it. - frame()->document()->setFocusedNode(node); - } else { - // Iterate over all the nodes in the range until we find a focusable node. - // This, for example, sets focus to the first link if you search for - // text and text that is within one or more links. - node = active_match_->firstNode(); - while (node && node != active_match_->pastLastNode()) { - if (node->isFocusable()) { - frame()->document()->setFocusedNode(node); - break; - } - node = node->traverseNextNode(); - } - } - } -} - -void WebFrameImpl::DidFail(const ResourceError& error, bool was_provisional) { - if (!client()) - return; - const WebURLError& web_error = - webkit_glue::ResourceErrorToWebURLError(error); - if (was_provisional) { - client()->didFailProvisionalLoad(this, web_error); - } else { - client()->didFailLoad(this, web_error); - } -} - -void WebFrameImpl::SetAllowsScrolling(bool flag) { - frame_->view()->setCanHaveScrollbars(flag); -} - -void WebFrameImpl::RegisterPasswordListener( - PassRefPtr<HTMLInputElement> input_element, - PasswordAutocompleteListener* listener) { - RefPtr<HTMLInputElement> element = input_element; - ASSERT(password_listeners_.find(element) == password_listeners_.end()); - password_listeners_.set(element, listener); -} - -PasswordAutocompleteListener* WebFrameImpl::GetPasswordListener( - HTMLInputElement* input_element) { - return password_listeners_.get(RefPtr<HTMLInputElement>(input_element)); -} - -// WebFrameImpl protected ------------------------------------------------------ - -void WebFrameImpl::Closing() { - frame_ = NULL; -} - -// WebFrameImpl private -------------------------------------------------------- - -void WebFrameImpl::InvalidateArea(AreaToInvalidate area) { - ASSERT(frame() && frame()->view()); - FrameView* view = frame()->view(); - - if ((area & INVALIDATE_ALL) == INVALIDATE_ALL) { - view->invalidateRect(view->frameRect()); - } else { - if ((area & INVALIDATE_CONTENT_AREA) == INVALIDATE_CONTENT_AREA) { - IntRect content_area( - view->x(), view->y(), view->visibleWidth(), view->visibleHeight()); - view->invalidateRect(content_area); - } - - if ((area & INVALIDATE_SCROLLBAR) == INVALIDATE_SCROLLBAR) { - // Invalidate the vertical scroll bar region for the view. - IntRect scroll_bar_vert( - view->x() + view->visibleWidth(), view->y(), - WebCore::ScrollbarTheme::nativeTheme()->scrollbarThickness(), - view->visibleHeight()); - view->invalidateRect(scroll_bar_vert); - } - } -} - -void WebFrameImpl::AddMarker(WebCore::Range* range, bool active_match) { - // Use a TextIterator to visit the potentially multiple nodes the range - // covers. - TextIterator markedText(range); - for (; !markedText.atEnd(); markedText.advance()) { - RefPtr<Range> textPiece = markedText.range(); - int exception = 0; - - WebCore::DocumentMarker marker = { - WebCore::DocumentMarker::TextMatch, - textPiece->startOffset(exception), - textPiece->endOffset(exception), - "", - active_match }; - - if (marker.endOffset > marker.startOffset) { - // Find the node to add a marker to and add it. - Node* node = textPiece->startContainer(exception); - frame()->document()->addMarker(node, marker); - - // Rendered rects for markers in WebKit are not populated until each time - // the markers are painted. However, we need it to happen sooner, because - // the whole purpose of tickmarks on the scrollbar is to show where - // matches off-screen are (that haven't been painted yet). - Vector<WebCore::DocumentMarker> markers = - frame()->document()->markersForNode(node); - frame()->document()->setRenderedRectForMarker( - textPiece->startContainer(exception), - markers[markers.size() - 1], - range->boundingBox()); - } - } -} - -void WebFrameImpl::SetMarkerActive(WebCore::Range* range, bool active) { - if (!range) - return; - - frame()->document()->setMarkersActive(range, active); -} - -int WebFrameImpl::OrdinalOfFirstMatchForFrame(WebFrameImpl* frame) const { - int ordinal = 0; - WebFrameImpl* main_frame_impl = GetWebViewImpl()->main_frame(); - // Iterate from the main frame up to (but not including) |frame| and - // add up the number of matches found so far. - for (WebFrameImpl* it = main_frame_impl; - it != frame; - it = static_cast<WebFrameImpl*>(it->traverseNext(true))) { - if (it->last_match_count_ > 0) - ordinal += it->last_match_count_; - } - - return ordinal; -} - -bool WebFrameImpl::ShouldScopeMatches(const string16& search_text) { - // Don't scope if we can't find a frame or if the frame is not visible. - // The user may have closed the tab/application, so abort. - if (!frame() || !hasVisibleContent()) - return false; - - ASSERT(frame()->document() && frame()->view()); - - // If the frame completed the scoping operation and found 0 matches the last - // time it was searched, then we don't have to search it again if the user is - // just adding to the search string or sending the same search string again. - if (scoping_complete_ && - !last_search_string_.empty() && last_match_count_ == 0) { - // Check to see if the search string prefixes match. - string16 previous_search_prefix = - search_text.substr(0, last_search_string_.length()); - - if (previous_search_prefix == last_search_string_) { - return false; // Don't search this frame, it will be fruitless. - } - } - - return true; -} - -void WebFrameImpl::ScopeStringMatchesSoon( - int identifier, const WebString& search_text, - const WebFindOptions& options, bool reset) { - deferred_scoping_work_.append(new DeferredScopeStringMatches( - this, identifier, search_text, options, reset)); -} - -void WebFrameImpl::CallScopeStringMatches( - DeferredScopeStringMatches* caller, int identifier, - const WebString& search_text, const WebFindOptions& options, bool reset) { - deferred_scoping_work_.remove(deferred_scoping_work_.find(caller)); - - scopeStringMatches(identifier, search_text, options, reset); - - // This needs to happen last since search_text is passed by reference. - delete caller; -} - -void WebFrameImpl::InvalidateIfNecessary() { - if (last_match_count_ > next_invalidate_after_) { - // TODO(finnur): (http://b/1088165) Optimize the drawing of the - // tickmarks and remove this. This calculation sets a milestone for when - // next to invalidate the scrollbar and the content area. We do this so that - // we don't spend too much time drawing the scrollbar over and over again. - // Basically, up until the first 500 matches there is no throttle. After the - // first 500 matches, we set set the milestone further and further out (750, - // 1125, 1688, 2K, 3K). - static const int start_slowing_down_after = 500; - static const int slowdown = 750; - int i = (last_match_count_ / start_slowing_down_after); - next_invalidate_after_ += i * slowdown; - - InvalidateArea(INVALIDATE_SCROLLBAR); - } -} - -void WebFrameImpl::ClearPasswordListeners() { - for (PasswordListenerMap::iterator iter = password_listeners_.begin(); - iter != password_listeners_.end(); ++iter) { - delete iter->second; - } - password_listeners_.clear(); -} - -void WebFrameImpl::LoadJavaScriptURL(const KURL& url) { - // This is copied from FrameLoader::executeIfJavaScriptURL. Unfortunately, - // we cannot just use that method since it is private, and it also doesn't - // quite behave as we require it to for bookmarklets. The key difference is - // that we need to suppress loading the string result from evaluating the JS - // URL if executing the JS URL resulted in a location change. We also allow - // a JS URL to be loaded even if scripts on the page are otherwise disabled. - - if (!frame_->document() || !frame_->page()) - return; - - String script = - decodeURLEscapeSequences(url.string().substring(strlen("javascript:"))); - ScriptValue result = frame_->script()->executeScript(script, true); - - String script_result; - if (!result.getString(script_result)) - return; - - SecurityOrigin* security_origin = frame_->document()->securityOrigin(); - - if (!frame_->redirectScheduler()->locationChangePending()) { - frame_->loader()->stopAllLoaders(); - frame_->loader()->begin(frame_->loader()->url(), true, security_origin); - frame_->loader()->write(script_result); - frame_->loader()->end(); - } -} diff --git a/webkit/glue/webframe_impl.h b/webkit/glue/webframe_impl.h deleted file mode 100644 index f1d0548..0000000 --- a/webkit/glue/webframe_impl.h +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBKIT_GLUE_WEBFRAME_IMPL_H_ -#define WEBKIT_GLUE_WEBFRAME_IMPL_H_ - -#include "Frame.h" -#include "PlatformString.h" -#include <wtf/OwnPtr.h> -#include <wtf/RefCounted.h> - -#include "webkit/api/public/WebFrame.h" -#include "webkit/glue/webframeloaderclient_impl.h" - -class ChromePrintContext; -class WebViewImpl; - -namespace gfx { -class BitmapPlatformDevice; -} - -namespace WebCore { -class HistoryItem; -class KURL; -class Node; -class Range; -class SubstituteData; -struct WindowFeatures; -} - -namespace WebKit { -class PasswordAutocompleteListener; -class WebDataSourceImpl; -class WebFrameClient; -class WebView; -} - -// Implementation of WebFrame, note that this is a reference counted object. -class WebFrameImpl : public WebKit::WebFrame, public RefCounted<WebFrameImpl> { - public: - // WebFrame methods: - virtual WebKit::WebString name() const; - virtual WebKit::WebURL url() const; - virtual WebKit::WebURL favIconURL() const; - virtual WebKit::WebURL openSearchDescriptionURL() const; - virtual WebKit::WebSize scrollOffset() const; - virtual WebKit::WebSize contentsSize() const; - virtual int contentsPreferredWidth() const; - virtual bool hasVisibleContent() const; - virtual WebKit::WebView* view() const; - virtual WebKit::WebFrame* opener() const; - virtual WebKit::WebFrame* parent() const; - virtual WebKit::WebFrame* top() const; - virtual WebKit::WebFrame* firstChild() const; - virtual WebKit::WebFrame* lastChild() const; - virtual WebKit::WebFrame* nextSibling() const; - virtual WebKit::WebFrame* previousSibling() const; - virtual WebKit::WebFrame* traverseNext(bool wrap) const; - virtual WebKit::WebFrame* traversePrevious(bool wrap) const; - virtual WebKit::WebFrame* findChildByName(const WebKit::WebString& name) const; - virtual WebKit::WebFrame* findChildByExpression( - const WebKit::WebString& xpath) const; - virtual void forms(WebKit::WebVector<WebKit::WebForm>&) const; - virtual WebKit::WebSecurityOrigin securityOrigin() const; - virtual void grantUniversalAccess(); - virtual NPObject* windowObject() const; - virtual void bindToWindowObject( - const WebKit::WebString& name, NPObject* object); - virtual void executeScript(const WebKit::WebScriptSource&); - virtual void executeScriptInNewContext( - const WebKit::WebScriptSource* sources, unsigned num_sources, - int extension_group); - virtual void executeScriptInIsolatedWorld( - int world_id, const WebKit::WebScriptSource* sources, - unsigned num_sources, int extension_group); - virtual void addMessageToConsole(const WebKit::WebConsoleMessage&); - virtual void collectGarbage(); -#if WEBKIT_USING_V8 - virtual v8::Local<v8::Context> mainWorldScriptContext() const; -#endif - virtual bool insertStyleText( - const WebKit::WebString& css, const WebKit::WebString& id); - virtual void reload(); - virtual void loadRequest(const WebKit::WebURLRequest& request); - virtual void loadHistoryItem(const WebKit::WebHistoryItem& history_item); - virtual void loadData( - const WebKit::WebData& data, const WebKit::WebString& mime_type, - const WebKit::WebString& text_encoding, const WebKit::WebURL& base_url, - const WebKit::WebURL& unreachable_url, bool replace); - virtual void loadHTMLString( - const WebKit::WebData& html, const WebKit::WebURL& base_url, - const WebKit::WebURL& unreachable_url, bool replace); - virtual bool isLoading() const; - virtual void stopLoading(); - virtual WebKit::WebDataSource* provisionalDataSource() const; - virtual WebKit::WebDataSource* dataSource() const; - virtual WebKit::WebHistoryItem previousHistoryItem() const; - virtual WebKit::WebHistoryItem currentHistoryItem() const; - virtual void enableViewSourceMode(bool enable); - virtual bool isViewSourceModeEnabled() const; - virtual void setReferrerForRequest( - WebKit::WebURLRequest& request, const WebKit::WebURL& referrer); - virtual void dispatchWillSendRequest(WebKit::WebURLRequest& request); - virtual void commitDocumentData(const char* data, size_t length); - virtual unsigned unloadListenerCount() const; - virtual bool isProcessingUserGesture() const; - virtual bool willSuppressOpenerInNewFrame() const; - virtual void replaceSelection(const WebKit::WebString& text); - virtual void insertText(const WebKit::WebString& text); - virtual void setMarkedText( - const WebKit::WebString& text, unsigned location, unsigned length); - virtual void unmarkText(); - virtual bool hasMarkedText() const; - virtual WebKit::WebRange markedRange() const; - virtual bool executeCommand(const WebKit::WebString& command); - virtual bool executeCommand( - const WebKit::WebString& command, const WebKit::WebString& value); - virtual bool isCommandEnabled(const WebKit::WebString& command) const; - virtual void enableContinuousSpellChecking(bool enable); - virtual bool isContinuousSpellCheckingEnabled() const; - virtual bool hasSelection() const; - virtual WebKit::WebRange selectionRange() const; - virtual WebKit::WebString selectionAsText() const; - virtual WebKit::WebString selectionAsMarkup() const; - virtual int printBegin(const WebKit::WebSize& page_size); - virtual float printPage(int page_to_print, WebKit::WebCanvas* canvas); - virtual float getPrintPageShrink(int page); - virtual void printEnd(); - virtual bool find( - int identifier, const WebKit::WebString& search_text, - const WebKit::WebFindOptions& options, bool wrap_within_frame, - WebKit::WebRect* selection_rect); - virtual void stopFinding(bool clear_selection); - virtual void scopeStringMatches( - int identifier, const WebKit::WebString& search_text, - const WebKit::WebFindOptions& options, bool reset); - virtual void cancelPendingScopingEffort(); - virtual void increaseMatchCount(int count, int identifier); - virtual void resetMatchCount(); - virtual WebKit::WebURL completeURL(const WebKit::WebString& url) const; - virtual WebKit::WebString contentAsText(size_t max_chars) const; - virtual WebKit::WebString contentAsMarkup() const; - - static PassRefPtr<WebFrameImpl> create(WebKit::WebFrameClient* client); - ~WebFrameImpl(); - - static int live_object_count() { - return live_object_count_; - } - - // Called by the WebViewImpl to initialize its main frame: - void InitMainFrame(WebViewImpl* webview_impl); - - PassRefPtr<WebCore::Frame> CreateChildFrame( - const WebCore::FrameLoadRequest&, - WebCore::HTMLFrameOwnerElement* owner_element); - - void Layout(); - void Paint(WebKit::WebCanvas* canvas, const WebKit::WebRect& rect); - - void CreateFrameView(); - - WebCore::Frame* frame() const { - return frame_; - } - - static WebFrameImpl* FromFrame(WebCore::Frame* frame); - - WebViewImpl* GetWebViewImpl() const; - - WebCore::FrameView* frameview() const { - return frame_ ? frame_->view() : NULL; - } - - // Getters for the impls corresponding to Get(Provisional)DataSource. They - // may return NULL if there is no corresponding data source. - WebKit::WebDataSourceImpl* GetDataSourceImpl() const; - WebKit::WebDataSourceImpl* GetProvisionalDataSourceImpl() const; - - // Returns which frame has an active match. This function should only be - // called on the main frame, as it is the only frame keeping track. Returned - // value can be NULL if no frame has an active match. - const WebFrameImpl* active_match_frame() const { - return active_match_frame_; - } - - // When a Find operation ends, we want to set the selection to what was active - // and set focus to the first focusable node we find (starting with the first - // node in the matched range and going up the inheritance chain). If we find - // nothing to focus we focus the first focusable node in the range. This - // allows us to set focus to a link (when we find text inside a link), which - // allows us to navigate by pressing Enter after closing the Find box. - void SetFindEndstateFocusAndSelection(); - - void DidFail(const WebCore::ResourceError& error, bool was_provisional); - - // Sets whether the WebFrameImpl allows its document to be scrolled. - // If the parameter is true, allow the document to be scrolled. - // Otherwise, disallow scrolling. - void SetAllowsScrolling(bool flag); - - // Registers a listener for the specified user name input element. The - // listener will receive notifications for blur and when autocomplete should - // be triggered. - // The WebFrameImpl becomes the owner of the passed listener. - void RegisterPasswordListener( - PassRefPtr<WebCore::HTMLInputElement> user_name_input_element, - WebKit::PasswordAutocompleteListener* listener); - - // Returns the password autocomplete listener associated with the passed - // user name input element, or NULL if none available. - // Note that the returned listener is owner by the WebFrameImpl and should not - // be kept around as it is deleted when the page goes away. - WebKit::PasswordAutocompleteListener* GetPasswordListener( - WebCore::HTMLInputElement* user_name_input_element); - - WebKit::WebFrameClient* client() const { return client_handle_->client(); } - void drop_client() { client_handle_->drop_client(); } - - protected: - friend class WebFrameLoaderClient; - - // A weak reference to the WebFrameClient. Each WebFrame in the hierarchy - // owns a reference to a ClientHandle. When the main frame is destroyed, it - // clears the WebFrameClient. - class ClientHandle : public RefCounted<ClientHandle> { - public: - static PassRefPtr<ClientHandle> create(WebKit::WebFrameClient* client) { - return adoptRef(new ClientHandle(client)); - } - WebKit::WebFrameClient* client() { return client_; } - void drop_client() { client_ = NULL; } - private: - ClientHandle(WebKit::WebFrameClient* client) : client_(client) {} - WebKit::WebFrameClient* client_; - }; - - WebFrameImpl(PassRefPtr<ClientHandle> client_handle); - - // Informs the WebFrame that the Frame is being closed, called by the - // WebFrameLoaderClient - void Closing(); - - // Used to check for leaks of this object. - static int live_object_count_; - - WebFrameLoaderClient frame_loader_client_; - - RefPtr<ClientHandle> client_handle_; - - // This is a weak pointer to our corresponding WebCore frame. A reference to - // ourselves is held while frame_ is valid. See our Closing method. - WebCore::Frame* frame_; - - // A way for the main frame to keep track of which frame has an active - // match. Should be NULL for all other frames. - WebFrameImpl* active_match_frame_; - - // The range of the active match for the current frame. - RefPtr<WebCore::Range> active_match_; - - // The index of the active match. - int active_match_index_; - - // This flag is used by the scoping effort to determine if we need to figure - // out which rectangle is the active match. Once we find the active - // rectangle we clear this flag. - bool locating_active_rect_; - - // The scoping effort can time out and we need to keep track of where we - // ended our last search so we can continue from where we left of. - RefPtr<WebCore::Range> resume_scoping_from_range_; - - // Keeps track of the last string this frame searched for. This is used for - // short-circuiting searches in the following scenarios: When a frame has - // been searched and returned 0 results, we don't need to search that frame - // again if the user is just adding to the search (making it more specific). - string16 last_search_string_; - - // Keeps track of how many matches this frame has found so far, so that we - // don't loose count between scoping efforts, and is also used (in conjunction - // with last_search_string_ and scoping_complete_) to figure out if we need to - // search the frame again. - int last_match_count_; - - // This variable keeps a cumulative total of matches found so far for ALL the - // frames on the page, and is only incremented by calling IncreaseMatchCount - // (on the main frame only). It should be -1 for all other frames. - size_t total_matchcount_; - - // This variable keeps a cumulative total of how many frames are currently - // scoping, and is incremented/decremented on the main frame only. - // It should be -1 for all other frames. - int frames_scoping_count_; - - // Keeps track of whether the scoping effort was completed (the user may - // interrupt it before it completes by submitting a new search). - bool scoping_complete_; - - // Keeps track of when the scoping effort should next invalidate the scrollbar - // and the frame area. - int next_invalidate_after_; - - private: - class DeferredScopeStringMatches; - friend class DeferredScopeStringMatches; - - // A bit mask specifying area of the frame to invalidate. - enum AreaToInvalidate { - INVALIDATE_NOTHING = 0, - INVALIDATE_CONTENT_AREA = 1, - INVALIDATE_SCROLLBAR = 2, // vertical scrollbar only. - INVALIDATE_ALL = 3 // both content area and the scrollbar. - }; - - // Notifies the delegate about a new selection rect. - void ReportFindInPageSelection( - const WebKit::WebRect& selection_rect, int active_match_ordinal, - int identifier); - - // Invalidates a certain area within the frame. - void InvalidateArea(AreaToInvalidate area); - - // Add a WebKit TextMatch-highlight marker to nodes in a range. - void AddMarker(WebCore::Range* range, bool active_match); - - // Sets the markers within a range as active or inactive. - void SetMarkerActive(WebCore::Range* range, bool active); - - // Returns the ordinal of the first match in the frame specified. This - // function enumerates the frames, starting with the main frame and up to (but - // not including) the frame passed in as a parameter and counts how many - // matches have been found. - int OrdinalOfFirstMatchForFrame(WebFrameImpl* frame) const; - - // Determines whether the scoping effort is required for a particular frame. - // It is not necessary if the frame is invisible, for example, or if this - // is a repeat search that already returned nothing last time the same prefix - // was searched. - bool ShouldScopeMatches(const string16& search_text); - - // Queue up a deferred call to scopeStringMatches. - void ScopeStringMatchesSoon( - int identifier, const WebKit::WebString& search_text, - const WebKit::WebFindOptions& options, bool reset); - - // Called by a DeferredScopeStringMatches instance. - void CallScopeStringMatches( - DeferredScopeStringMatches* deferred, - int identifier, const WebKit::WebString& search_text, - const WebKit::WebFindOptions& options, bool reset); - - // Determines whether to invalidate the content area and scrollbar. - void InvalidateIfNecessary(); - - // Clears the map of password listeners. - void ClearPasswordListeners(); - - void LoadJavaScriptURL(const WebCore::KURL& url); - - // A list of all of the pending calls to scopeStringMatches. - Vector<DeferredScopeStringMatches*> deferred_scoping_work_; - - // Valid between calls to BeginPrint() and EndPrint(). Containts the print - // information. Is used by PrintPage(). - OwnPtr<ChromePrintContext> print_context_; - - // The input fields that are interested in edit events and their associated - // listeners. - typedef HashMap<RefPtr<WebCore::HTMLInputElement>, - WebKit::PasswordAutocompleteListener*> PasswordListenerMap; - PasswordListenerMap password_listeners_; -}; - -#endif // WEBKIT_GLUE_WEBFRAME_IMPL_H_ diff --git a/webkit/glue/webframeloaderclient_impl.cc b/webkit/glue/webframeloaderclient_impl.cc deleted file mode 100644 index ab4dbb7..0000000 --- a/webkit/glue/webframeloaderclient_impl.cc +++ /dev/null @@ -1,1339 +0,0 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "config.h" - -#include "Chrome.h" -#include "CString.h" -#include "Document.h" -#include "DocumentLoader.h" -#include "HTMLAppletElement.h" -#include "HTMLFormElement.h" // needed by FormState.h -#include "HTMLNames.h" -#include "FormState.h" -#include "FrameLoader.h" -#include "FrameLoadRequest.h" -#include "HitTestResult.h" -#include "MIMETypeRegistry.h" -#include "MouseEvent.h" -#include "Page.h" -#include "PlatformString.h" -#include "PluginData.h" -#include "StringExtras.h" -#include "WindowFeatures.h" -#undef LOG - -#include "net/base/mime_util.h" -#include "webkit/api/public/WebForm.h" -#include "webkit/api/public/WebFrameClient.h" -#include "webkit/api/public/WebNode.h" -#include "webkit/api/public/WebPlugin.h" -#include "webkit/api/public/WebPluginParams.h" -#include "webkit/api/public/WebSecurityOrigin.h" -#include "webkit/api/public/WebURL.h" -#include "webkit/api/public/WebURLError.h" -#include "webkit/api/public/WebVector.h" -#include "webkit/api/public/WebViewClient.h" -#include "webkit/api/src/WebDataSourceImpl.h" -#include "webkit/api/src/WebPluginContainerImpl.h" -#include "webkit/api/src/WebPluginLoadObserver.h" -#include "webkit/api/src/WrappedResourceRequest.h" -#include "webkit/api/src/WrappedResourceResponse.h" -#include "webkit/glue/glue_util.h" -#include "webkit/glue/webdevtoolsagent_impl.h" -#include "webkit/glue/webframe_impl.h" -#include "webkit/glue/webframeloaderclient_impl.h" -#include "webkit/glue/webkit_glue.h" -#include "webkit/glue/webview_impl.h" - -using namespace WebCore; - -using WebKit::WebData; -using WebKit::WebDataSourceImpl; -using WebKit::WebNavigationType; -using WebKit::WebNavigationPolicy; -using WebKit::WebNode; -using WebKit::WebPlugin; -using WebKit::WebPluginContainerImpl; -using WebKit::WebPluginLoadObserver; -using WebKit::WebPluginParams; -using WebKit::WebString; -using WebKit::WebURL; -using WebKit::WebURLError; -using WebKit::WebURLRequest; -using WebKit::WebVector; -using WebKit::WrappedResourceRequest; -using WebKit::WrappedResourceResponse; - -// Domain for internal error codes. -static const char kInternalErrorDomain[] = "WebKit"; - -// An internal error code. Used to note a policy change error resulting from -// dispatchDecidePolicyForMIMEType not passing the PolicyUse option. -enum { - ERR_POLICY_CHANGE = -10000, -}; - -static void CopyStringVector( - const Vector<String>& input, WebVector<WebString>* output) { - WebVector<WebString> result(input.size()); - for (size_t i = 0; i < input.size(); ++i) - result[i] = webkit_glue::StringToWebString(input[i]); - output->swap(result); -} - -WebFrameLoaderClient::WebFrameLoaderClient(WebFrameImpl* frame) - : webframe_(frame), - has_representation_(false), - sent_initial_response_to_plugin_(false), - next_navigation_policy_(WebKit::WebNavigationPolicyIgnore) { -} - -WebFrameLoaderClient::~WebFrameLoaderClient() { -} - -void WebFrameLoaderClient::frameLoaderDestroyed() { - // When the WebFrame was created, it had an extra reference given to it on - // behalf of the Frame. Since the WebFrame owns us, this extra ref also - // serves to keep us alive until the FrameLoader is done with us. The - // FrameLoader calls this method when it's going away. Therefore, we balance - // out that extra reference, which may cause 'this' to be deleted. - webframe_->Closing(); - webframe_->deref(); -} - -void WebFrameLoaderClient::windowObjectCleared() { - if (webframe_->client()) - webframe_->client()->didClearWindowObject(webframe_); - - WebViewImpl* webview = webframe_->GetWebViewImpl(); - if (webview) { - WebDevToolsAgentImpl* tools_agent = webview->GetWebDevToolsAgentImpl(); - if (tools_agent) - tools_agent->WindowObjectCleared(webframe_); - } -} - -void WebFrameLoaderClient::documentElementAvailable() { - if (webframe_->client()) - webframe_->client()->didCreateDocumentElement(webframe_); -} - -void WebFrameLoaderClient::didCreateScriptContextForFrame() { - if (webframe_->client()) - webframe_->client()->didCreateScriptContext(webframe_); -} - -void WebFrameLoaderClient::didDestroyScriptContextForFrame() { - if (webframe_->client()) - webframe_->client()->didDestroyScriptContext(webframe_); -} - -void WebFrameLoaderClient::didCreateIsolatedScriptContext() { - if (webframe_->client()) - webframe_->client()->didCreateIsolatedScriptContext(webframe_); -} - -void WebFrameLoaderClient::didPerformFirstNavigation() const { -} - -void WebFrameLoaderClient::registerForIconNotification(bool listen){ -} - -bool WebFrameLoaderClient::hasWebView() const { - return webframe_->GetWebViewImpl() != NULL; -} - -bool WebFrameLoaderClient::hasFrameView() const { - // The Mac port has this notion of a WebFrameView, which seems to be - // some wrapper around an NSView. Since our equivalent is HWND, I guess - // we have a "frameview" whenever we have the toplevel HWND. - return webframe_->GetWebViewImpl() != NULL; -} - -void WebFrameLoaderClient::makeDocumentView() { - webframe_->CreateFrameView(); -} - -void WebFrameLoaderClient::makeRepresentation(DocumentLoader*) { - has_representation_ = true; -} - -void WebFrameLoaderClient::forceLayout() { - // FIXME -} -void WebFrameLoaderClient::forceLayoutForNonHTML() { - // FIXME -} - -void WebFrameLoaderClient::setCopiesOnScroll() { - // FIXME -} - -void WebFrameLoaderClient::detachedFromParent2() { - // Nothing to do here. -} - -void WebFrameLoaderClient::detachedFromParent3() { - // Close down the proxy. The purpose of this change is to make the - // call to ScriptController::clearWindowShell a no-op when called from - // Frame::pageDestroyed. Without this change, this call to clearWindowShell - // will cause a crash. If you remove/modify this, just ensure that you can - // go to a page and then navigate to a new page without getting any asserts - // or crashes. - webframe_->frame()->script()->proxy()->clearForClose(); -} - -// This function is responsible for associating the |identifier| with a given -// subresource load. The following functions that accept an |identifier| are -// called for each subresource, so they should not be dispatched to the -// WebFrame. -void WebFrameLoaderClient::assignIdentifierToInitialRequest( - unsigned long identifier, DocumentLoader* loader, - const ResourceRequest& request) { - if (webframe_->client()) { - WrappedResourceRequest webreq(request); - webframe_->client()->assignIdentifierToRequest( - webframe_, identifier, webreq); - } -} - -// Determines whether the request being loaded by |loader| is a frame or a -// subresource. A subresource in this context is anything other than a frame -- -// this includes images and xmlhttp requests. It is important to note that a -// subresource is NOT limited to stuff loaded through the frame's subresource -// loader. Synchronous xmlhttp requests for example, do not go through the -// subresource loader, but we still label them as TargetIsSubResource. -// -// The important edge cases to consider when modifying this function are -// how synchronous resource loads are treated during load/unload threshold. -static ResourceRequest::TargetType DetermineTargetTypeFromLoader( - DocumentLoader* loader) { - if (loader == loader->frameLoader()->provisionalDocumentLoader()) { - if (loader->frameLoader()->isLoadingMainFrame()) { - return ResourceRequest::TargetIsMainFrame; - } else { - return ResourceRequest::TargetIsSubFrame; - } - } - return ResourceRequest::TargetIsSubResource; -} - -void WebFrameLoaderClient::dispatchWillSendRequest( - DocumentLoader* loader, unsigned long identifier, ResourceRequest& request, - const ResourceResponse& redirect_response) { - - if (loader) { - // We want to distinguish between a request for a document to be loaded into - // the main frame, a sub-frame, or the sub-objects in that document. - request.setTargetType(DetermineTargetTypeFromLoader(loader)); - } - - // FrameLoader::loadEmptyDocumentSynchronously() creates an empty document - // with no URL. We don't like that, so we'll rename it to about:blank. - if (request.url().isEmpty()) - request.setURL(KURL(ParsedURLString, "about:blank")); - if (request.firstPartyForCookies().isEmpty()) - request.setFirstPartyForCookies(KURL(ParsedURLString, "about:blank")); - - // Give the WebFrameClient a crack at the request. - if (webframe_->client()) { - WrappedResourceRequest webreq(request); - WrappedResourceResponse webresp(redirect_response); - webframe_->client()->willSendRequest( - webframe_, identifier, webreq, webresp); - } -} - -bool WebFrameLoaderClient::shouldUseCredentialStorage(DocumentLoader*, - unsigned long identifier) { - // FIXME - // Intended to pass through to a method on the resource load delegate. - // If implemented, that method controls whether the browser should ask the - // networking layer for a stored default credential for the page (say from - // the Mac OS keychain). If the method returns false, the user should be - // presented with an authentication challenge whether or not the networking - // layer has a credential stored. - // This returns true for backward compatibility: the ability to override the - // system credential store is new. (Actually, not yet fully implemented in - // WebKit, as of this writing.) - return true; -} - -void WebFrameLoaderClient::dispatchDidReceiveAuthenticationChallenge( - DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) { - // FIXME -} - -void WebFrameLoaderClient::dispatchDidCancelAuthenticationChallenge( - DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) { - // FIXME -} - -void WebFrameLoaderClient::dispatchDidReceiveResponse(DocumentLoader* loader, - unsigned long identifier, - const ResourceResponse& response) { - if (webframe_->client()) { - WrappedResourceResponse webresp(response); - webframe_->client()->didReceiveResponse(webframe_, identifier, webresp); - } -} - -void WebFrameLoaderClient::dispatchDidReceiveContentLength( - DocumentLoader* loader, - unsigned long identifier, - int length_received) { -} - -// Called when a particular resource load completes -void WebFrameLoaderClient::dispatchDidFinishLoading(DocumentLoader* loader, - unsigned long identifier) { - if (webframe_->client()) - webframe_->client()->didFinishResourceLoad(webframe_, identifier); -} - -void WebFrameLoaderClient::dispatchDidFailLoading(DocumentLoader* loader, - unsigned long identifier, - const ResourceError& error) { - if (webframe_->client()) { - webframe_->client()->didFailResourceLoad( - webframe_, identifier, webkit_glue::ResourceErrorToWebURLError(error)); - } -} - -void WebFrameLoaderClient::dispatchDidFinishDocumentLoad() { - // A frame may be reused. This call ensures we don't hold on to our password - // listeners and their associated HTMLInputElements. - webframe_->ClearPasswordListeners(); - - if (webframe_->client()) - webframe_->client()->didFinishDocumentLoad(webframe_); -} - -bool WebFrameLoaderClient::dispatchDidLoadResourceFromMemoryCache( - DocumentLoader* loader, - const ResourceRequest& request, - const ResourceResponse& response, - int length) { - if (webframe_->client()) { - WrappedResourceRequest webreq(request); - WrappedResourceResponse webresp(response); - webframe_->client()->didLoadResourceFromMemoryCache( - webframe_, webreq, webresp); - } - return false; // Do not suppress remaining notifications -} - -void WebFrameLoaderClient::dispatchDidLoadResourceByXMLHttpRequest( - unsigned long identifier, - const ScriptString& source) { -} - -void WebFrameLoaderClient::dispatchDidHandleOnloadEvents() { - if (webframe_->client()) - webframe_->client()->didHandleOnloadEvents(webframe_); -} - -// Redirect Tracking -// ================= -// We want to keep track of the chain of redirects that occur during page -// loading. There are two types of redirects, server redirects which are HTTP -// response codes, and client redirects which are document.location= and meta -// refreshes. -// -// This outlines the callbacks that we get in different redirect situations, -// and how each call modifies the redirect chain. -// -// Normal page load -// ---------------- -// dispatchDidStartProvisionalLoad() -> adds URL to the redirect list -// dispatchDidCommitLoad() -> DISPATCHES & clears list -// -// Server redirect (success) -// ------------------------- -// dispatchDidStartProvisionalLoad() -> adds source URL -// dispatchDidReceiveServerRedirectForProvisionalLoad() -> adds dest URL -// dispatchDidCommitLoad() -> DISPATCHES -// -// Client redirect (success) -// ------------------------- -// (on page) -// dispatchWillPerformClientRedirect() -> saves expected redirect -// dispatchDidStartProvisionalLoad() -> appends redirect source (since -// it matches the expected redirect) -// and the current page as the dest) -// dispatchDidCancelClientRedirect() -> clears expected redirect -// dispatchDidCommitLoad() -> DISPATCHES -// -// Client redirect (cancelled) -// (e.g meta-refresh trumped by manual doc.location change, or just cancelled -// because a link was clicked that requires the meta refresh to be rescheduled -// (the SOURCE URL may have changed). -// --------------------------- -// dispatchDidCancelClientRedirect() -> clears expected redirect -// dispatchDidStartProvisionalLoad() -> adds only URL to redirect list -// dispatchDidCommitLoad() -> DISPATCHES & clears list -// rescheduled ? dispatchWillPerformClientRedirect() -> saves expected redirect -// : nothing - -// Client redirect (failure) -// ------------------------- -// (on page) -// dispatchWillPerformClientRedirect() -> saves expected redirect -// dispatchDidStartProvisionalLoad() -> appends redirect source (since -// it matches the expected redirect) -// and the current page as the dest) -// dispatchDidCancelClientRedirect() -// dispatchDidFailProvisionalLoad() -// -// Load 1 -> Server redirect to 2 -> client redirect to 3 -> server redirect to 4 -// ------------------------------------------------------------------------------ -// dispatchDidStartProvisionalLoad() -> adds source URL 1 -// dispatchDidReceiveServerRedirectForProvisionalLoad() -> adds dest URL 2 -// dispatchDidCommitLoad() -> DISPATCHES 1+2 -// -- begin client redirect and NEW DATA SOURCE -// dispatchWillPerformClientRedirect() -> saves expected redirect -// dispatchDidStartProvisionalLoad() -> appends URL 2 and URL 3 -// dispatchDidReceiveServerRedirectForProvisionalLoad() -> appends destination URL 4 -// dispatchDidCancelClientRedirect() -> clears expected redirect -// dispatchDidCommitLoad() -> DISPATCHES -// -// Interesting case with multiple location changes involving anchors. -// Load page 1 containing future client-redirect (back to 1, e.g meta refresh) > Click -// on a link back to the same page (i.e an anchor href) > -// client-redirect finally fires (with new source, set to 1#anchor) -// ----------------------------------------------------------------------------- -// dispatchWillPerformClientRedirect(non-zero 'interval' param) -> saves expected redirect -// -- click on anchor href -// dispatchDidCancelClientRedirect() -> clears expected redirect -// dispatchDidStartProvisionalLoad() -> adds 1#anchor source -// dispatchDidCommitLoad() -> DISPATCHES 1#anchor -// dispatchWillPerformClientRedirect() -> saves exp. source (1#anchor) -// -- redirect timer fires -// dispatchDidStartProvisionalLoad() -> appends 1#anchor (src) and 1 (dest) -// dispatchDidCancelClientRedirect() -> clears expected redirect -// dispatchDidCommitLoad() -> DISPATCHES 1#anchor + 1 -// -void WebFrameLoaderClient::dispatchDidReceiveServerRedirectForProvisionalLoad() { - WebDataSourceImpl* ds = webframe_->GetProvisionalDataSourceImpl(); - if (!ds) { - // Got a server redirect when there is no provisional DS! - ASSERT_NOT_REACHED(); - return; - } - - // The server redirect may have been blocked. - if (ds->request().isNull()) - return; - - // A provisional load should have started already, which should have put an - // entry in our redirect chain. - ASSERT(ds->hasRedirectChain()); - - // The URL of the destination is on the provisional data source. We also need - // to update the redirect chain to account for this addition (we do this - // before the callback so the callback can look at the redirect chain to see - // what happened). - ds->appendRedirect(webkit_glue::WebURLToKURL(ds->request().url())); - - if (webframe_->client()) - webframe_->client()->didReceiveServerRedirectForProvisionalLoad(webframe_); -} - -// Called on both success and failure of a client redirect. -void WebFrameLoaderClient::dispatchDidCancelClientRedirect() { - // No longer expecting a client redirect. - if (webframe_->client()) { - expected_client_redirect_src_ = KURL(); - expected_client_redirect_dest_ = KURL(); - webframe_->client()->didCancelClientRedirect(webframe_); - } - - // No need to clear the redirect chain, since that data source has already - // been deleted by the time this function is called. -} - -void WebFrameLoaderClient::dispatchWillPerformClientRedirect( - const KURL& url, - double interval, - double fire_date) { - // Tells dispatchDidStartProvisionalLoad that if it sees this item it is a - // redirect and the source item should be added as the start of the chain. - expected_client_redirect_src_ = webkit_glue::WebURLToKURL(webframe_->url()); - expected_client_redirect_dest_ = url; - - // TODO(timsteele): bug 1135512. Webkit does not properly notify us of - // cancelling http > file client redirects. Since the FrameLoader's policy - // is to never carry out such a navigation anyway, the best thing we can do - // for now to not get confused is ignore this notification. - if (expected_client_redirect_dest_.isLocalFile() && - expected_client_redirect_src_.protocolInHTTPFamily()) { - expected_client_redirect_src_ = KURL(); - expected_client_redirect_dest_ = KURL(); - return; - } - - if (webframe_->client()) { - webframe_->client()->willPerformClientRedirect( - webframe_, - webkit_glue::KURLToWebURL(expected_client_redirect_src_), - webkit_glue::KURLToWebURL(expected_client_redirect_dest_), - static_cast<unsigned int>(interval), - static_cast<unsigned int>(fire_date)); - } -} - -void WebFrameLoaderClient::dispatchDidChangeLocationWithinPage() { - // Anchor fragment navigations are not normal loads, so we need to synthesize - // some events for our delegate. - WebViewImpl* webview = webframe_->GetWebViewImpl(); - if (webview->client()) - webview->client()->didStartLoading(); - - WebDataSourceImpl* ds = webframe_->GetDataSourceImpl(); - ASSERT(ds); // Should not be null when navigating to a reference fragment! - if (ds) { - KURL url = webkit_glue::WebURLToKURL(ds->request().url()); - KURL chain_end; - if (ds->hasRedirectChain()) { - chain_end = ds->endOfRedirectChain(); - ds->clearRedirectChain(); - } - - // Figure out if this location change is because of a JS-initiated client - // redirect (e.g onload/setTimeout document.location.href=). - // TODO(timsteele): (bugs 1085325, 1046841) We don't get proper redirect - // performed/cancelled notifications across anchor navigations, so the - // other redirect-tracking code in this class (see dispatch*ClientRedirect() - // and dispatchDidStartProvisionalLoad) is insufficient to catch and - // properly flag these transitions. Once a proper fix for this bug is - // identified and applied the following block may no longer be required. - bool was_client_redirect = - (url == expected_client_redirect_dest_ && - chain_end == expected_client_redirect_src_) || - !webframe_->isProcessingUserGesture(); - - if (was_client_redirect) { - if (webframe_->client()) { - webframe_->client()->didCompleteClientRedirect( - webframe_, webkit_glue::KURLToWebURL(chain_end)); - } - ds->appendRedirect(chain_end); - // Make sure we clear the expected redirect since we just effectively - // completed it. - expected_client_redirect_src_ = KURL(); - expected_client_redirect_dest_ = KURL(); - } - - // Regardless of how we got here, we are navigating to a URL so we need to - // add it to the redirect chain. - ds->appendRedirect(url); - } - - bool is_new_navigation; - webview->DidCommitLoad(&is_new_navigation); - if (webframe_->client()) { - webframe_->client()->didChangeLocationWithinPage( - webframe_, is_new_navigation); - } - - if (webview->client()) - webview->client()->didStopLoading(); -} - -void WebFrameLoaderClient::dispatchWillClose() { - if (webframe_->client()) - webframe_->client()->willClose(webframe_); -} - -void WebFrameLoaderClient::dispatchDidReceiveIcon() { - // The icon database is disabled, so this should never be called. - ASSERT_NOT_REACHED(); -} - -void WebFrameLoaderClient::dispatchDidStartProvisionalLoad() { - // In case a redirect occurs, we need this to be set so that the redirect - // handling code can tell where the redirect came from. Server redirects - // will occur on the provisional load, so we need to keep track of the most - // recent provisional load URL. - // See dispatchDidReceiveServerRedirectForProvisionalLoad. - WebDataSourceImpl* ds = webframe_->GetProvisionalDataSourceImpl(); - if (!ds) { - ASSERT_NOT_REACHED(); - return; - } - KURL url = webkit_glue::WebURLToKURL(ds->request().url()); - - // Since the provisional load just started, we should have not gotten - // any redirects yet. - ASSERT(!ds->hasRedirectChain()); - - // If this load is what we expected from a client redirect, treat it as a - // redirect from that original page. The expected redirect urls will be - // cleared by DidCancelClientRedirect. - bool completing_client_redirect = false; - if (expected_client_redirect_src_.isValid()) { - // expected_client_redirect_dest_ could be something like - // "javascript:history.go(-1)" thus we need to exclude url starts with - // "javascript:". See bug: 1080873 - ASSERT(expected_client_redirect_dest_.protocolIs("javascript") || - expected_client_redirect_dest_ == url); - ds->appendRedirect(expected_client_redirect_src_); - completing_client_redirect = true; - } - ds->appendRedirect(url); - - if (webframe_->client()) { - // As the comment for DidCompleteClientRedirect in webview_delegate.h - // points out, whatever information its invocation contains should only - // be considered relevant until the next provisional load has started. - // So we first tell the delegate that the load started, and then tell it - // about the client redirect the load is responsible for completing. - webframe_->client()->didStartProvisionalLoad(webframe_); - if (completing_client_redirect) - webframe_->client()->didCompleteClientRedirect( - webframe_, webkit_glue::KURLToWebURL(expected_client_redirect_src_)); - } -} - -void WebFrameLoaderClient::dispatchDidReceiveTitle(const String& title) { - if (webframe_->client()) { - webframe_->client()->didReceiveTitle( - webframe_, webkit_glue::StringToWebString(title)); - } -} - -void WebFrameLoaderClient::dispatchDidCommitLoad() { - WebViewImpl* webview = webframe_->GetWebViewImpl(); - bool is_new_navigation; - webview->DidCommitLoad(&is_new_navigation); - - if (webframe_->client()) { - webframe_->client()->didCommitProvisionalLoad( - webframe_, is_new_navigation); - } - - WebDevToolsAgentImpl* tools_agent = webview->GetWebDevToolsAgentImpl(); - if (tools_agent) { - tools_agent->DidCommitLoadForFrame(webview, webframe_, is_new_navigation); - } -} - -void WebFrameLoaderClient::dispatchDidFailProvisionalLoad( - const ResourceError& error) { - // If a policy change occured, then we do not want to inform the plugin - // delegate. See bug 907789 for details. - // TODO(darin): This means the plugin won't receive NPP_URLNotify, which - // seems like it could result in a memory leak in the plugin!! - if (error.domain() == kInternalErrorDomain && - error.errorCode() == ERR_POLICY_CHANGE) { - webframe_->DidFail(cancelledError(error.failingURL()), true); - return; - } - - OwnPtr<WebPluginLoadObserver> plugin_load_observer = GetPluginLoadObserver(); - webframe_->DidFail(error, true); - if (plugin_load_observer) - plugin_load_observer->didFailLoading(error); -} - -void WebFrameLoaderClient::dispatchDidFailLoad(const ResourceError& error) { - OwnPtr<WebPluginLoadObserver> plugin_load_observer = GetPluginLoadObserver(); - webframe_->DidFail(error, false); - if (plugin_load_observer) - plugin_load_observer->didFailLoading(error); - - // Don't clear the redirect chain, this will happen in the middle of client - // redirects, and we need the context. The chain will be cleared when the - // provisional load succeeds or fails, not the "real" one. -} - -void WebFrameLoaderClient::dispatchDidFinishLoad() { - OwnPtr<WebPluginLoadObserver> plugin_load_observer = GetPluginLoadObserver(); - - if (webframe_->client()) - webframe_->client()->didFinishLoad(webframe_); - - if (plugin_load_observer) - plugin_load_observer->didFinishLoading(); - - // Don't clear the redirect chain, this will happen in the middle of client - // redirects, and we need the context. The chain will be cleared when the - // provisional load succeeds or fails, not the "real" one. -} - -void WebFrameLoaderClient::dispatchDidFirstLayout() { -} - -void WebFrameLoaderClient::dispatchDidFirstVisuallyNonEmptyLayout() { - // FIXME: called when webkit finished layout of a page that was visually - // non-empty. - // All resources have not necessarily finished loading. -} - -Frame* WebFrameLoaderClient::dispatchCreatePage() { - struct WebCore::WindowFeatures features; - Page* new_page = webframe_->frame()->page()->chrome()->createWindow( - webframe_->frame(), FrameLoadRequest(), features); - - // Make sure that we have a valid disposition. This should have been set in - // the preceeding call to dispatchDecidePolicyForNewWindowAction. - ASSERT(next_navigation_policy_ != WebKit::WebNavigationPolicyIgnore); - WebNavigationPolicy policy = next_navigation_policy_; - next_navigation_policy_ = WebKit::WebNavigationPolicyIgnore; - - // createWindow can return NULL (e.g., popup blocker denies the window). - if (!new_page) - return NULL; - - WebViewImpl::FromPage(new_page)->set_initial_navigation_policy(policy); - return new_page->mainFrame(); -} - -void WebFrameLoaderClient::dispatchShow() { - WebViewImpl* webview = webframe_->GetWebViewImpl(); - if (webview && webview->client()) - webview->client()->show(webview->initial_navigation_policy()); -} - -static bool TreatAsAttachment(const ResourceResponse& response) { - const String& content_disposition = - response.httpHeaderField("Content-Disposition"); - if (content_disposition.isEmpty()) - return false; - - // Some broken sites just send - // Content-Disposition: ; filename="file" - // screen those out here. - if (content_disposition.startsWith(";")) - return false; - - if (content_disposition.startsWith("inline", false)) - return false; - - // Some broken sites just send - // Content-Disposition: filename="file" - // without a disposition token... screen those out. - if (content_disposition.startsWith("filename", false)) - return false; - - // Also in use is Content-Disposition: name="file" - if (content_disposition.startsWith("name", false)) - return false; - - // We have a content-disposition of "attachment" or unknown. - // RFC 2183, section 2.8 says that an unknown disposition - // value should be treated as "attachment" - return true; -} - -void WebFrameLoaderClient::dispatchDecidePolicyForMIMEType( - FramePolicyFunction function, - const String& mime_type, - const ResourceRequest&) { - const ResourceResponse& response = - webframe_->frame()->loader()->activeDocumentLoader()->response(); - - PolicyAction action; - - int status_code = response.httpStatusCode(); - if (status_code == 204 || status_code == 205) { - // The server does not want us to replace the page contents. - action = PolicyIgnore; - } else if (TreatAsAttachment(response)) { - // The server wants us to download instead of replacing the page contents. - // Downloading is handled by the embedder, but we still get the initial - // response so that we can ignore it and clean up properly. - action = PolicyIgnore; - } else if (!canShowMIMEType(mime_type)) { - // Make sure that we can actually handle this type internally. - action = PolicyIgnore; - } else { - // OK, we will render this page. - action = PolicyUse; - } - - // NOTE: ERR_POLICY_CHANGE will be generated when action is not PolicyUse. - (webframe_->frame()->loader()->policyChecker()->*function)(action); -} - -void WebFrameLoaderClient::dispatchDecidePolicyForNewWindowAction( - WebCore::FramePolicyFunction function, - const WebCore::NavigationAction& action, - const WebCore::ResourceRequest& request, - PassRefPtr<WebCore::FormState> form_state, - const WebCore::String& frame_name) { - WebNavigationPolicy navigation_policy; - if (!ActionSpecifiesNavigationPolicy(action, &navigation_policy)) - navigation_policy = WebKit::WebNavigationPolicyNewForegroundTab; - - PolicyAction policy_action; - if (navigation_policy == WebKit::WebNavigationPolicyDownload) { - policy_action = PolicyDownload; - } else { - policy_action = PolicyUse; - - // Remember the disposition for when dispatchCreatePage is called. It is - // unfortunate that WebCore does not provide us with any context when - // creating or showing the new window that would allow us to avoid having - // to keep this state. - next_navigation_policy_ = navigation_policy; - } - (webframe_->frame()->loader()->policyChecker()->*function)(policy_action); -} - -void WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction( - WebCore::FramePolicyFunction function, - const WebCore::NavigationAction& action, - const WebCore::ResourceRequest& request, - PassRefPtr<WebCore::FormState> form_state) { - PolicyAction policy_action = PolicyIgnore; - - // It is valid for this function to be invoked in code paths where the - // the webview is closed. - // The NULL check here is to fix a crash that seems strange - // (see - https://bugs.webkit.org/show_bug.cgi?id=23554). - if (webframe_->client() && !request.url().isNull()) { - WebNavigationPolicy navigation_policy = - WebKit::WebNavigationPolicyCurrentTab; - ActionSpecifiesNavigationPolicy(action, &navigation_policy); - - // Give the delegate a chance to change the navigation policy. - const WebDataSourceImpl* ds = webframe_->GetProvisionalDataSourceImpl(); - if (ds) { - KURL url = webkit_glue::WebURLToKURL(ds->request().url()); - if (url.protocolIs(WebKit::backForwardNavigationScheme)) { - HandleBackForwardNavigation(url); - navigation_policy = WebKit::WebNavigationPolicyIgnore; - } else { - bool is_redirect = ds->hasRedirectChain(); - - WebNavigationType webnav_type = - WebDataSourceImpl::toWebNavigationType(action.type()); - - RefPtr<WebCore::Node> node; - for (const Event* event = action.event(); event; - event = event->underlyingEvent()) { - if (event->isMouseEvent()) { - const MouseEvent* mouse_event = - static_cast<const MouseEvent*>(event); - node = webframe_->frame()->eventHandler()->hitTestResultAtPoint( - mouse_event->absoluteLocation(), false).innerNonSharedNode(); - break; - } - } - WebNode originating_node = webkit_glue::NodeToWebNode(node); - - navigation_policy = webframe_->client()->decidePolicyForNavigation( - webframe_, ds->request(), webnav_type, originating_node, - navigation_policy, is_redirect); - } - } - - if (navigation_policy == WebKit::WebNavigationPolicyCurrentTab) { - policy_action = PolicyUse; - } else if (navigation_policy == WebKit::WebNavigationPolicyDownload) { - policy_action = PolicyDownload; - } else { - if (navigation_policy != WebKit::WebNavigationPolicyIgnore) { - WrappedResourceRequest webreq(request); - webframe_->client()->loadURLExternally( - webframe_, webreq, navigation_policy); - } - policy_action = PolicyIgnore; - } - } - - (webframe_->frame()->loader()->policyChecker()->*function)(policy_action); -} - -void WebFrameLoaderClient::cancelPolicyCheck() { - // FIXME -} - -void WebFrameLoaderClient::dispatchUnableToImplementPolicy( - const ResourceError& error) { - WebKit::WebURLError url_error = - webkit_glue::ResourceErrorToWebURLError(error); - webframe_->client()->unableToImplementPolicyWithError(webframe_, url_error); -} - -void WebFrameLoaderClient::dispatchWillSubmitForm(FramePolicyFunction function, - PassRefPtr<FormState> form_ref) { - if (webframe_->client()) { - webframe_->client()->willSubmitForm( - webframe_, webkit_glue::HTMLFormElementToWebForm(form_ref->form())); - } - (webframe_->frame()->loader()->policyChecker()->*function)(PolicyUse); -} - -void WebFrameLoaderClient::dispatchDidLoadMainResource(DocumentLoader*) { - // FIXME -} - -void WebFrameLoaderClient::revertToProvisionalState(DocumentLoader*) { - has_representation_ = true; -} - -void WebFrameLoaderClient::setMainDocumentError(DocumentLoader*, - const ResourceError& error) { - if (plugin_widget_.get()) { - if (sent_initial_response_to_plugin_) { - plugin_widget_->didFailLoading(error); - sent_initial_response_to_plugin_ = false; - } - plugin_widget_ = NULL; - } -} - -void WebFrameLoaderClient::postProgressStartedNotification() { - WebViewImpl* webview = webframe_->GetWebViewImpl(); - if (webview && webview->client()) - webview->client()->didStartLoading(); -} - -void WebFrameLoaderClient::postProgressEstimateChangedNotification() { - // FIXME -} - -void WebFrameLoaderClient::postProgressFinishedNotification() { - // TODO(ericroman): why might the webview be null? - // http://b/1234461 - WebViewImpl* webview = webframe_->GetWebViewImpl(); - if (webview && webview->client()) - webview->client()->didStopLoading(); -} - -void WebFrameLoaderClient::setMainFrameDocumentReady(bool ready) { - // FIXME -} - -// Creates a new connection and begins downloading from that (contrast this -// with |download|). -void WebFrameLoaderClient::startDownload(const ResourceRequest& request) { - if (webframe_->client()) { - WrappedResourceRequest webreq(request); - webframe_->client()->loadURLExternally( - webframe_, webreq, WebKit::WebNavigationPolicyDownload); - } -} - -void WebFrameLoaderClient::willChangeTitle(DocumentLoader*) { - // FIXME -} - -void WebFrameLoaderClient::didChangeTitle(DocumentLoader*) { - // FIXME -} - -// Called whenever data is received. -void WebFrameLoaderClient::committedLoad(DocumentLoader* loader, const char* data, int length) { - if (!plugin_widget_.get()) { - if (webframe_->client()) { - bool preventDefault = false; - webframe_->client()->didReceiveDocumentData(webframe_, data, length, preventDefault); - if (!preventDefault) - webframe_->commitDocumentData(data, length); - } - } - - // If we are sending data to WebCore::MediaDocument, we should stop here - // and cancel the request. - if (webframe_->frame()->document() && - webframe_->frame()->document()->isMediaDocument()) { - loader->cancelMainResourceLoad( - pluginWillHandleLoadError(loader->response())); - } - - // The plugin widget could have been created in the webframe_->DidReceiveData - // function. - if (plugin_widget_.get()) { - if (!sent_initial_response_to_plugin_) { - sent_initial_response_to_plugin_ = true; - plugin_widget_->didReceiveResponse( - webframe_->frame()->loader()->activeDocumentLoader()->response()); - } - plugin_widget_->didReceiveData(data, length); - } -} - -void WebFrameLoaderClient::finishedLoading(DocumentLoader* dl) { - if (plugin_widget_.get()) { - plugin_widget_->didFinishLoading(); - plugin_widget_ = NULL; - sent_initial_response_to_plugin_ = false; - } else { - // This is necessary to create an empty document. See bug 634004. - // However, we only want to do this if makeRepresentation has been called, to - // match the behavior on the Mac. - if (has_representation_) - dl->frameLoader()->setEncoding("", false); - } -} - -void WebFrameLoaderClient::updateGlobalHistory() { -} - -void WebFrameLoaderClient::updateGlobalHistoryRedirectLinks() { -} - -bool WebFrameLoaderClient::shouldGoToHistoryItem(HistoryItem*) const { - // FIXME - return true; -} - -void WebFrameLoaderClient::didDisplayInsecureContent() { - if (webframe_->client()) - webframe_->client()->didDisplayInsecureContent(webframe_); -} - -void WebFrameLoaderClient::didRunInsecureContent(SecurityOrigin* origin) { - if (webframe_->client()) { - webframe_->client()->didRunInsecureContent(webframe_, - webkit_glue::SecurityOriginToWebSecurityOrigin(origin)); - } -} - -ResourceError WebFrameLoaderClient::blockedError(const WebCore::ResourceRequest&) { - // FIXME - return ResourceError(); -} - -ResourceError WebFrameLoaderClient::cancelledError( - const ResourceRequest& request) { - if (!webframe_->client()) - return ResourceError(); - - return webkit_glue::WebURLErrorToResourceError( - webframe_->client()->cancelledError( - webframe_, WrappedResourceRequest(request))); -} - -ResourceError WebFrameLoaderClient::cannotShowURLError( - const ResourceRequest& request) { - if (!webframe_->client()) - return ResourceError(); - - return webkit_glue::WebURLErrorToResourceError( - webframe_->client()->cannotHandleRequestError( - webframe_, WrappedResourceRequest(request))); -} - -ResourceError WebFrameLoaderClient::interruptForPolicyChangeError( - const ResourceRequest& request) { - return ResourceError(kInternalErrorDomain, ERR_POLICY_CHANGE, - request.url().string(), String()); -} - -ResourceError WebFrameLoaderClient::cannotShowMIMETypeError(const ResourceResponse&) { - // FIXME - return ResourceError(); -} - -ResourceError WebFrameLoaderClient::fileDoesNotExistError(const ResourceResponse&) { - // FIXME - return ResourceError(); -} - -ResourceError WebFrameLoaderClient::pluginWillHandleLoadError(const WebCore::ResourceResponse&) { - // FIXME - return ResourceError(); -} - -bool WebFrameLoaderClient::shouldFallBack(const ResourceError& error) { - // This method is called when we fail to load the URL for an <object> tag - // that has fallback content (child elements) and is being loaded as a frame. - // The error parameter indicates the reason for the load failure. - // We should let the fallback content load only if this wasn't a cancelled - // request. - // Note: The mac version also has a case for "WebKitErrorPluginWillHandleLoad" - ResourceError cancelled_error = cancelledError(ResourceRequest()); - return error.errorCode() != cancelled_error.errorCode() || - error.domain() != cancelled_error.domain(); -} - -bool WebFrameLoaderClient::canHandleRequest( - const ResourceRequest& request) const { - return webframe_->client()->canHandleRequest( - webframe_, WrappedResourceRequest(request)); -} - -bool WebFrameLoaderClient::canShowMIMEType(const String& mime_type) const { - // This method is called to determine if the media type can be shown - // "internally" (i.e. inside the browser) regardless of whether or not the - // browser or a plugin is doing the rendering. - - // mime_type strings are supposed to be ASCII, but if they are not for some - // reason, then it just means that the mime type will fail all of these "is - // supported" checks and go down the path of an unhandled mime type. - if (net::IsSupportedMimeType( - webkit_glue::CStringToStdString(mime_type.latin1()))) - return true; - - // If Chrome is started with the --disable-plugins switch, pluginData is null. - WebCore::PluginData* plugin_data = webframe_->frame()->page()->pluginData(); - - // See if the type is handled by an installed plugin, if so, we can show it. - // TODO(beng): (http://b/1085524) This is the place to stick a preference to - // disable full page plugins (optionally for certain types!) - return !mime_type.isEmpty() && plugin_data && plugin_data->supportsMimeType(mime_type); -} - -bool WebFrameLoaderClient::representationExistsForURLScheme(const String& URLScheme) const { - // FIXME - return false; -} - -String WebFrameLoaderClient::generatedMIMETypeForURLScheme(const String& URLScheme) const { - // This appears to generate MIME types for protocol handlers that are handled - // internally. The only place I can find in the WebKit code that uses this - // function is WebView::registerViewClass, where it is used as part of the - // process by which custom view classes for certain document representations - // are registered. - String mimetype("x-apple-web-kit/"); - mimetype.append(URLScheme.lower()); - return mimetype; -} - -void WebFrameLoaderClient::frameLoadCompleted() { - // FIXME: the mac port also conditionally calls setDrawsBackground:YES on - // it's ScrollView here. - - // This comment from the Mac port: - // Note: Can be called multiple times. - // Even if already complete, we might have set a previous item on a frame that - // didn't do any data loading on the past transaction. Make sure to clear these out. - - // FIXME: setPreviousHistoryItem() no longer exists. http://crbug.com/8566 - // webframe_->frame()->loader()->setPreviousHistoryItem(0); -} - -void WebFrameLoaderClient::saveViewStateToItem(HistoryItem*) { - // FIXME -} - - -void WebFrameLoaderClient::restoreViewState() { - // FIXME: probably scrolls to last position when you go back or forward -} - -void WebFrameLoaderClient::provisionalLoadStarted() { - // FIXME: On mac, this does various caching stuff -} - -void WebFrameLoaderClient::didFinishLoad() { - OwnPtr<WebPluginLoadObserver> plugin_load_observer = GetPluginLoadObserver(); - if (plugin_load_observer) - plugin_load_observer->didFinishLoading(); -} - -void WebFrameLoaderClient::prepareForDataSourceReplacement() { - // FIXME -} - -PassRefPtr<DocumentLoader> WebFrameLoaderClient::createDocumentLoader( - const ResourceRequest& request, - const SubstituteData& data) { - RefPtr<WebDataSourceImpl> ds = WebDataSourceImpl::create(request, data); - if (webframe_->client()) - webframe_->client()->didCreateDataSource(webframe_, ds.get()); - return ds.release(); -} - -void WebFrameLoaderClient::setTitle(const String& title, const KURL& url) { - // FIXME: monitor for changes in WebFrameLoaderClient.mm - // FIXME: Set the title of the current history item. HistoryItemImpl's setter - // will notify its clients (e.g. the history database) that the title - // has changed. - // - // e.g.: - // WebHistoryItem* item = - // webframe_->GetWebViewImpl()->GetBackForwardList()->GetCurrentItem(); - // WebHistoryItemImpl* item_impl = static_cast<WebHistoryItemImpl*>(item); - // - // item_impl->SetTitle(webkit_glue::StringToStdWString(title)); -} - -String WebFrameLoaderClient::userAgent(const KURL& url) { - return webkit_glue::StdStringToString( - webkit_glue::GetUserAgent(webkit_glue::KURLToGURL(url))); -} - -void WebFrameLoaderClient::savePlatformDataToCachedFrame(WebCore::CachedFrame*) { - // The page cache should be disabled. - ASSERT_NOT_REACHED(); -} - -void WebFrameLoaderClient::transitionToCommittedFromCachedFrame(WebCore::CachedFrame*) { - ASSERT_NOT_REACHED(); -} - -// Called when the FrameLoader goes into a state in which a new page load -// will occur. -void WebFrameLoaderClient::transitionToCommittedForNewPage() { - makeDocumentView(); -} - -bool WebFrameLoaderClient::canCachePage() const { - // Since we manage the cache, always report this page as non-cacheable to - // FrameLoader. - return false; -} - -// Downloading is handled in the browser process, not WebKit. If we get to this -// point, our download detection code in the ResourceDispatcherHost is broken! -void WebFrameLoaderClient::download(ResourceHandle* handle, - const ResourceRequest& request, - const ResourceRequest& initialRequest, - const ResourceResponse& response) { - ASSERT_NOT_REACHED(); -} - -PassRefPtr<Frame> WebFrameLoaderClient::createFrame( - const KURL& url, - const String& name, - HTMLFrameOwnerElement* owner_element, - const String& referrer, - bool allows_scrolling, - int margin_width, - int margin_height) { - FrameLoadRequest frame_request(ResourceRequest(url, referrer), name); - return webframe_->CreateChildFrame(frame_request, owner_element); -} - -PassRefPtr<Widget> WebFrameLoaderClient::createPlugin( - const IntSize& size, // TODO(erikkay): how do we use this? - HTMLPlugInElement* element, - const KURL& url, - const Vector<String>& param_names, - const Vector<String>& param_values, - const String& mime_type, - bool load_manually) { -#if !PLATFORM(WIN_OS) - // WebCore asks us to make a plugin even if we don't have a - // registered handler, with a comment saying it's so we can display - // the broken plugin icon. In Chromium, we normally register a - // fallback plugin handler that allows you to install a missing - // plugin. Since we don't yet have a default plugin handler, we - // need to return NULL here rather than going through all the - // plugin-creation IPCs only to discover we don't have a plugin - // registered, which causes a crash. - // TODO(evanm): remove me once we have a default plugin. - if (objectContentType(url, mime_type) != ObjectContentNetscapePlugin) - return NULL; -#endif - - if (!webframe_->client()) - return NULL; - - WebPluginParams params; - params.url = webkit_glue::KURLToWebURL(url); - params.mimeType = webkit_glue::StringToWebString(mime_type); - CopyStringVector(param_names, ¶ms.attributeNames); - CopyStringVector(param_values, ¶ms.attributeValues); - params.loadManually = load_manually; - - WebPlugin* webplugin = webframe_->client()->createPlugin(webframe_, params); - if (!webplugin) - return NULL; - - // The container takes ownership of the WebPlugin. - RefPtr<WebPluginContainerImpl> container = - WebPluginContainerImpl::create(element, webplugin); - - if (!webplugin->initialize(container.get())) - return NULL; - - // The element might have been removed during plugin initialization! - if (!element->renderer()) - return NULL; - - return container; -} - -// This method gets called when a plugin is put in place of html content -// (e.g., acrobat reader). -void WebFrameLoaderClient::redirectDataToPlugin(Widget* pluginWidget) { - plugin_widget_ = static_cast<WebPluginContainerImpl*>(pluginWidget); - ASSERT(plugin_widget_.get()); -} - -PassRefPtr<Widget> WebFrameLoaderClient::createJavaAppletWidget( - const IntSize& size, - HTMLAppletElement* element, - const KURL& /* base_url */, - const Vector<String>& param_names, - const Vector<String>& param_values) { - return createPlugin(size, element, KURL(), param_names, param_values, - "application/x-java-applet", false); -} - -ObjectContentType WebFrameLoaderClient::objectContentType( - const KURL& url, - const String& explicit_mime_type) { - // This code is based on Apple's implementation from - // WebCoreSupport/WebFrameBridge.mm. - - String mime_type = explicit_mime_type; - if (mime_type.isEmpty()) { - // Try to guess the MIME type based off the extension. - String filename = url.lastPathComponent(); - int extension_pos = filename.reverseFind('.'); - if (extension_pos >= 0) - mime_type = MIMETypeRegistry::getMIMETypeForPath(url.path()); - - if (mime_type.isEmpty()) - return ObjectContentFrame; - } - - if (MIMETypeRegistry::isSupportedImageMIMEType(mime_type)) - return ObjectContentImage; - - // If Chrome is started with the --disable-plugins switch, pluginData is null. - PluginData* plugin_data = webframe_->frame()->page()->pluginData(); - if (plugin_data && plugin_data->supportsMimeType(mime_type)) - return ObjectContentNetscapePlugin; - - if (MIMETypeRegistry::isSupportedNonImageMIMEType(mime_type)) - return ObjectContentFrame; - - return ObjectContentNone; -} - -String WebFrameLoaderClient::overrideMediaType() const { - // FIXME - return String(); -} - -bool WebFrameLoaderClient::ActionSpecifiesNavigationPolicy( - const WebCore::NavigationAction& action, - WebNavigationPolicy* policy) { - if ((action.type() != NavigationTypeLinkClicked) || - !action.event()->isMouseEvent()) - return false; - - const MouseEvent* event = static_cast<const MouseEvent*>(action.event()); - return WebViewImpl::NavigationPolicyFromMouseEvent(event->button(), - event->ctrlKey(), event->shiftKey(), event->altKey(), event->metaKey(), - policy); -} - -void WebFrameLoaderClient::HandleBackForwardNavigation(const KURL& url) { - ASSERT(url.protocolIs(WebKit::backForwardNavigationScheme)); - - bool ok; - int offset = url.lastPathComponent().toIntStrict(&ok); - if (!ok) - return; - - WebViewImpl* webview = webframe_->GetWebViewImpl(); - if (webview->client()) - webview->client()->navigateBackForwardSoon(offset); -} - -PassOwnPtr<WebPluginLoadObserver> WebFrameLoaderClient::GetPluginLoadObserver() { - WebDataSourceImpl* ds = WebDataSourceImpl::fromDocumentLoader( - webframe_->frame()->loader()->activeDocumentLoader()); - return ds->releasePluginLoadObserver(); -} diff --git a/webkit/glue/webframeloaderclient_impl.h b/webkit/glue/webframeloaderclient_impl.h deleted file mode 100644 index fdf5de7..0000000 --- a/webkit/glue/webframeloaderclient_impl.h +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef WEBKIT_GLUE_WEBFRAMELOADERCLIENT_IMPL_H_ -#define WEBKIT_GLUE_WEBFRAMELOADERCLIENT_IMPL_H_ - -#include "FrameLoaderClient.h" -#include "KURL.h" -#include <wtf/PassOwnPtr.h> -#include <wtf/RefPtr.h> - -#include "webkit/api/public/WebNavigationPolicy.h" - -class WebFrameImpl; - -namespace WebKit { -class WebPluginContainerImpl; -class WebPluginLoadObserver; -} - -class WebFrameLoaderClient : public WebCore::FrameLoaderClient { - public: - WebFrameLoaderClient(WebFrameImpl* webframe); - virtual ~WebFrameLoaderClient(); - - WebFrameImpl* webframe() const { return webframe_; } - - // WebCore::FrameLoaderClient ---------------------------------------------- - - virtual void frameLoaderDestroyed(); - - // Notifies the WebView delegate that the JS window object has been cleared, - // giving it a chance to bind native objects to the window before script - // parsing begins. - virtual void windowObjectCleared(); - virtual void documentElementAvailable(); - - // A frame's V8 context was created or destroyed. - virtual void didCreateScriptContextForFrame(); - virtual void didDestroyScriptContextForFrame(); - - // A context untied to a frame was created (through evaluateInNewContext). - // This context is not tied to the lifetime of its frame, and is destroyed - // in garbage collection. - virtual void didCreateIsolatedScriptContext(); - - virtual bool hasWebView() const; // mainly for assertions - virtual bool hasFrameView() const; // ditto - - virtual void makeRepresentation(WebCore::DocumentLoader*); - virtual void forceLayout(); - virtual void forceLayoutForNonHTML(); - - virtual void setCopiesOnScroll(); - - virtual void detachedFromParent2(); - virtual void detachedFromParent3(); - - virtual void assignIdentifierToInitialRequest(unsigned long identifier, WebCore::DocumentLoader*, const WebCore::ResourceRequest&); - - virtual void dispatchWillSendRequest(WebCore::DocumentLoader*, unsigned long identifier, WebCore::ResourceRequest&, const WebCore::ResourceResponse& redirectResponse); - virtual bool shouldUseCredentialStorage(WebCore::DocumentLoader*, unsigned long identifier); - virtual void dispatchDidReceiveAuthenticationChallenge(WebCore::DocumentLoader*, unsigned long identifier, const WebCore::AuthenticationChallenge&); - virtual void dispatchDidCancelAuthenticationChallenge(WebCore::DocumentLoader*, unsigned long identifier, const WebCore::AuthenticationChallenge&); - virtual void dispatchDidReceiveResponse(WebCore::DocumentLoader*, unsigned long identifier, const WebCore::ResourceResponse&); - virtual void dispatchDidReceiveContentLength(WebCore::DocumentLoader*, unsigned long identifier, int lengthReceived); - virtual void dispatchDidFinishLoading(WebCore::DocumentLoader*, unsigned long identifier); - virtual void dispatchDidFailLoading(WebCore::DocumentLoader*, unsigned long identifier, const WebCore::ResourceError&); - virtual bool dispatchDidLoadResourceFromMemoryCache(WebCore::DocumentLoader*, const WebCore::ResourceRequest&, const WebCore::ResourceResponse&, int length); - virtual void dispatchDidLoadResourceByXMLHttpRequest(unsigned long identifier, const WebCore::ScriptString&); - - virtual void dispatchDidHandleOnloadEvents(); - virtual void dispatchDidReceiveServerRedirectForProvisionalLoad(); - virtual void dispatchDidCancelClientRedirect(); - virtual void dispatchWillPerformClientRedirect(const WebCore::KURL&, double interval, double fireDate); - virtual void dispatchDidChangeLocationWithinPage(); - virtual void dispatchWillClose(); - virtual void dispatchDidReceiveIcon(); - virtual void dispatchDidStartProvisionalLoad(); - virtual void dispatchDidReceiveTitle(const WebCore::String& title); - virtual void dispatchDidCommitLoad(); - virtual void dispatchDidFailProvisionalLoad(const WebCore::ResourceError&); - virtual void dispatchDidFailLoad(const WebCore::ResourceError&); - virtual void dispatchDidFinishDocumentLoad(); - virtual void dispatchDidFinishLoad(); - virtual void dispatchDidFirstLayout(); - virtual void dispatchDidFirstVisuallyNonEmptyLayout(); - - virtual WebCore::Frame* dispatchCreatePage(); - virtual void dispatchShow(); - - virtual void dispatchDecidePolicyForMIMEType(WebCore::FramePolicyFunction function, const WebCore::String& mime_type, const WebCore::ResourceRequest&); - virtual void dispatchDecidePolicyForNewWindowAction(WebCore::FramePolicyFunction function, const WebCore::NavigationAction& action, const WebCore::ResourceRequest& request, PassRefPtr<WebCore::FormState> form_state, const WebCore::String& frame_name); - virtual void dispatchDecidePolicyForNavigationAction(WebCore::FramePolicyFunction function, const WebCore::NavigationAction& action, const WebCore::ResourceRequest& request, PassRefPtr<WebCore::FormState> form_state); - virtual void cancelPolicyCheck(); - - virtual void dispatchUnableToImplementPolicy(const WebCore::ResourceError&); - - virtual void dispatchWillSubmitForm(WebCore::FramePolicyFunction, PassRefPtr<WebCore::FormState>); - - virtual void dispatchDidLoadMainResource(WebCore::DocumentLoader*); - virtual void revertToProvisionalState(WebCore::DocumentLoader*); - virtual void setMainDocumentError(WebCore::DocumentLoader*, const WebCore::ResourceError&); - - // Maybe these should go into a ProgressTrackerClient some day - virtual void willChangeEstimatedProgress() { } - virtual void didChangeEstimatedProgress() { } - virtual void postProgressStartedNotification(); - virtual void postProgressEstimateChangedNotification(); - virtual void postProgressFinishedNotification(); - - virtual void setMainFrameDocumentReady(bool); - - virtual void startDownload(const WebCore::ResourceRequest&); - - virtual void willChangeTitle(WebCore::DocumentLoader*); - virtual void didChangeTitle(WebCore::DocumentLoader*); - - virtual void committedLoad(WebCore::DocumentLoader*, const char*, int); - virtual void finishedLoading(WebCore::DocumentLoader*); - - virtual void updateGlobalHistory(); - virtual void updateGlobalHistoryRedirectLinks(); - - virtual bool shouldGoToHistoryItem(WebCore::HistoryItem*) const; - - virtual void didDisplayInsecureContent(); - virtual void didRunInsecureContent(WebCore::SecurityOrigin*); - - virtual WebCore::ResourceError blockedError(const WebCore::ResourceRequest&); - virtual WebCore::ResourceError cancelledError(const WebCore::ResourceRequest&); - virtual WebCore::ResourceError cannotShowURLError(const WebCore::ResourceRequest&); - virtual WebCore::ResourceError interruptForPolicyChangeError(const WebCore::ResourceRequest&); - - virtual WebCore::ResourceError cannotShowMIMETypeError(const WebCore::ResourceResponse&); - virtual WebCore::ResourceError fileDoesNotExistError(const WebCore::ResourceResponse&); - virtual WebCore::ResourceError pluginWillHandleLoadError(const WebCore::ResourceResponse&); - - virtual bool shouldFallBack(const WebCore::ResourceError&); - - virtual bool canHandleRequest(const WebCore::ResourceRequest&) const; - virtual bool canShowMIMEType(const WebCore::String& MIMEType) const; - virtual bool representationExistsForURLScheme(const WebCore::String& URLScheme) const; - virtual WebCore::String generatedMIMETypeForURLScheme(const WebCore::String& URLScheme) const; - - virtual void frameLoadCompleted(); - virtual void saveViewStateToItem(WebCore::HistoryItem*); - virtual void restoreViewState(); - virtual void provisionalLoadStarted(); - virtual void didFinishLoad(); - virtual void prepareForDataSourceReplacement(); - - virtual PassRefPtr<WebCore::DocumentLoader> createDocumentLoader( - const WebCore::ResourceRequest&, - const WebCore::SubstituteData&); - virtual void setTitle(const WebCore::String& title, const WebCore::KURL&); - - virtual WebCore::String userAgent(const WebCore::KURL&); - - virtual void savePlatformDataToCachedFrame(WebCore::CachedFrame*); - virtual void transitionToCommittedFromCachedFrame(WebCore::CachedFrame*); - virtual void transitionToCommittedForNewPage(); - - virtual bool canCachePage() const; - virtual void download(WebCore::ResourceHandle* handle, - const WebCore::ResourceRequest& request, - const WebCore::ResourceRequest& initialRequest, - const WebCore::ResourceResponse& response); - virtual PassRefPtr<WebCore::Frame> createFrame( - const WebCore::KURL& url, - const WebCore::String& name, - WebCore::HTMLFrameOwnerElement* ownerElement, - const WebCore::String& referrer, - bool allowsScrolling, int marginWidth, - int marginHeight); - virtual PassRefPtr<WebCore::Widget> createPlugin(const WebCore::IntSize&, - WebCore::HTMLPlugInElement*, - const WebCore::KURL&, - const WTF::Vector<WebCore::String>&, - const WTF::Vector<WebCore::String>&, - const WebCore::String&, - bool loadManually); - virtual void redirectDataToPlugin(WebCore::Widget* pluginWidget); - - virtual PassRefPtr<WebCore::Widget> createJavaAppletWidget( - const WebCore::IntSize&, - WebCore::HTMLAppletElement*, - const WebCore::KURL& /* base_url */, - const WTF::Vector<WebCore::String>& paramNames, - const WTF::Vector<WebCore::String>& paramValues); - - virtual WebCore::ObjectContentType objectContentType( - const WebCore::KURL& url, const WebCore::String& mimeType); - virtual WebCore::String overrideMediaType() const; - - virtual void didPerformFirstNavigation() const; - - virtual void registerForIconNotification(bool listen = true); - - private: - void makeDocumentView(); - - // Given a NavigationAction, determine the associated WebNavigationPolicy. - // For example, a middle click means "open in background tab". - static bool ActionSpecifiesNavigationPolicy( - const WebCore::NavigationAction& action, - WebKit::WebNavigationPolicy* policy); - - // Called when a dummy back-forward navigation is intercepted. - void HandleBackForwardNavigation(const WebCore::KURL&); - - PassOwnPtr<WebKit::WebPluginLoadObserver> GetPluginLoadObserver(); - - // The WebFrame that owns this object and manages its lifetime. Therefore, - // the web frame object is guaranteed to exist. - WebFrameImpl* webframe_; - - // True if makeRepresentation was called. We don't actually have a concept - // of a "representation", but we need to know when we're expected to have one. - // See finishedLoading(). - bool has_representation_; - - // Used to help track client redirects. When a provisional load starts, it - // has no redirects in its chain. But in the case of client redirects, we want - // to add that initial load as a redirect. When we get a new provisional load - // and the dest URL matches that load, we know that it was the result of a - // previous client redirect and the source should be added as a redirect. - // Both should be empty if unused. - WebCore::KURL expected_client_redirect_src_; - WebCore::KURL expected_client_redirect_dest_; - - // Contains a pointer to the plugin widget. - WTF::RefPtr<WebKit::WebPluginContainerImpl> plugin_widget_; - - // Indicates if we need to send over the initial notification to the plugin - // which specifies that the plugin should be ready to accept data. - bool sent_initial_response_to_plugin_; - - // The navigation policy to use for the next call to dispatchCreatePage. - WebKit::WebNavigationPolicy next_navigation_policy_; -}; - -#endif // #ifndef WEBKIT_GLUE_WEBFRAMELOADERCLIENT_IMPL_H_ diff --git a/webkit/glue/webkit_glue.cc b/webkit/glue/webkit_glue.cc index 233170c..d3e5b72 100644 --- a/webkit/glue/webkit_glue.cc +++ b/webkit/glue/webkit_glue.cc @@ -44,19 +44,21 @@ #if defined(OS_WIN) #include "webkit/api/public/win/WebInputEventFactory.h" #endif +#include "webkit/api/src/WebFrameImpl.h" +#include "webkit/api/src/WebViewImpl.h" #include "webkit/glue/glue_serialize.h" #include "webkit/glue/glue_util.h" -#include "webkit/glue/webframe_impl.h" -#include "webkit/glue/webview_impl.h" #include "webkit_version.h" // Generated using WebKit::WebCanvas; using WebKit::WebFrame; +using WebKit::WebFrameImpl; using WebKit::WebHistoryItem; using WebKit::WebString; using WebKit::WebVector; using WebKit::WebView; +using WebKit::WebViewImpl; namespace { @@ -123,7 +125,7 @@ std::wstring DumpFramesAsText(WebFrame* web_frame, bool recursive) { WebCore::Frame* child = webFrameImpl->frame()->tree()->firstChild(); for (; child; child = child->tree()->nextSibling()) { result.append( - DumpFramesAsText(WebFrameImpl::FromFrame(child), recursive)); + DumpFramesAsText(WebFrameImpl::fromFrame(child), recursive)); } } @@ -155,7 +157,7 @@ bool CounterValueForElementById(WebFrame* web_frame, const std::string& id, std::wstring DumpFrameScrollPosition(WebFrame* web_frame, bool recursive) { WebFrameImpl* webFrameImpl = static_cast<WebFrameImpl*>(web_frame); - WebCore::IntSize offset = webFrameImpl->frameview()->scrollOffset(); + WebCore::IntSize offset = webFrameImpl->frameView()->scrollOffset(); std::wstring result; if (offset.width() > 0 || offset.height() > 0) { @@ -170,7 +172,7 @@ std::wstring DumpFrameScrollPosition(WebFrame* web_frame, bool recursive) { if (recursive) { WebCore::Frame* child = webFrameImpl->frame()->tree()->firstChild(); for (; child; child = child->tree()->nextSibling()) { - result.append(DumpFrameScrollPosition(WebFrameImpl::FromFrame(child), + result.append(DumpFrameScrollPosition(WebFrameImpl::fromFrame(child), recursive)); } } @@ -274,7 +276,7 @@ void DumpLeakedObject(const char* file, int line, const char* object, int count) void CheckForLeaks() { #ifndef NDEBUG - int count = WebFrameImpl::live_object_count(); + int count = WebFrameImpl::liveObjectCount(); if (count) DumpLeakedObject(__FILE__, __LINE__, "WebFrame", count); #endif diff --git a/webkit/glue/webkitclient_impl.cc b/webkit/glue/webkitclient_impl.cc index 7560c70..d29f73d 100644 --- a/webkit/glue/webkitclient_impl.cc +++ b/webkit/glue/webkitclient_impl.cc @@ -33,6 +33,8 @@ #include "webkit/api/public/WebURL.h" #include "webkit/api/public/WebViewClient.h" #include "webkit/api/src/ChromeClientImpl.h" +#include "webkit/api/src/WebFrameImpl.h" +#include "webkit/api/src/WebViewImpl.h" #include "webkit/api/src/WebWorkerClientImpl.h" #include "webkit/glue/glue_util.h" #include "webkit/glue/plugins/plugin_instance.h" @@ -40,7 +42,6 @@ #include "webkit/glue/webplugininfo.h" #include "webkit/glue/websocketstreamhandle_impl.h" #include "webkit/glue/weburlloader_impl.h" -#include "webkit/glue/webview_impl.h" using WebKit::ChromeClientImpl; using WebKit::WebApplicationCacheHost; @@ -48,6 +49,7 @@ using WebKit::WebApplicationCacheHostClient; using WebKit::WebCookie; using WebKit::WebCursorInfo; using WebKit::WebData; +using WebKit::WebFrameImpl; using WebKit::WebLocalizedString; using WebKit::WebPluginListBuilder; using WebKit::WebStorageNamespace; @@ -57,6 +59,7 @@ using WebKit::WebThemeEngine; using WebKit::WebURL; using WebKit::WebURLLoader; using WebKit::WebVector; +using WebKit::WebViewImpl; using WebKit::WebWidgetClient; using WebKit::WebWorkerClientImpl; @@ -417,7 +420,7 @@ bool WebKitClientImpl::makeAllDirectories( WebKit::WebMediaPlayer* WebKitClientImpl::createWebMediaPlayer( WebKit::WebMediaPlayerClient* client, WebCore::Frame* frame) { - WebFrameImpl* webframe = WebFrameImpl::FromFrame(frame); + WebFrameImpl* webframe = WebFrameImpl::fromFrame(frame); if (!webframe->client()) return NULL; @@ -443,7 +446,7 @@ void WebKitClientImpl::notifyJSOutOfMemory(WebCore::Frame* frame) { if (!frame) return; - WebFrameImpl* webframe = WebFrameImpl::FromFrame(frame); + WebFrameImpl* webframe = WebFrameImpl::fromFrame(frame); if (!webframe->client()) return; webframe->client()->didExhaustMemoryAvailableForScript(webframe); diff --git a/webkit/glue/webview_impl.cc b/webkit/glue/webview_impl.cc deleted file mode 100644 index 97dce63..0000000 --- a/webkit/glue/webview_impl.cc +++ /dev/null @@ -1,1925 +0,0 @@ -// Copyright (c) 2007-2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "config.h" - -#include "AXObjectCache.h" -#include "CSSStyleSelector.h" -#include "CSSValueKeywords.h" -#include "Cursor.h" -#include "Document.h" -#include "DocumentLoader.h" -#include "DragController.h" -#include "DragData.h" -#include "Editor.h" -#include "EventHandler.h" -#include "FocusController.h" -#include "FontDescription.h" -#include "FrameLoader.h" -#include "FrameTree.h" -#include "FrameView.h" -#include "GraphicsContext.h" -#include "HTMLNames.h" -#include "HTMLInputElement.h" -#include "HTMLMediaElement.h" -#include "HitTestResult.h" -#include "Image.h" -#include "InspectorController.h" -#include "IntRect.h" -#include "KeyboardCodes.h" -#include "KeyboardEvent.h" -#include "MIMETypeRegistry.h" -#include "NodeRenderStyle.h" -#include "Page.h" -#include "PageGroup.h" -#include "Pasteboard.h" -#include "PlatformContextSkia.h" -#include "PlatformKeyboardEvent.h" -#include "PlatformMouseEvent.h" -#include "PlatformWheelEvent.h" -#include "PluginInfoStore.h" -#include "PopupMenuChromium.h" -#include "PopupMenuClient.h" -#include "RenderView.h" -#include "ResourceHandle.h" -#include "SecurityOrigin.h" -#include "SelectionController.h" -#include "Settings.h" -#include "TypingCommand.h" -#if PLATFORM(WIN_OS) -#include "KeyboardCodesWin.h" -#include "RenderThemeChromiumWin.h" -#else -#include "KeyboardCodesPosix.h" -#include "RenderTheme.h" -#endif -#undef LOG - -#include "webkit/api/public/WebAccessibilityObject.h" -#include "webkit/api/public/WebDragData.h" -#include "webkit/api/public/WebInputEvent.h" -#include "webkit/api/public/WebMediaPlayerAction.h" -#include "webkit/api/public/WebPoint.h" -#include "webkit/api/public/WebRect.h" -#include "webkit/api/public/WebString.h" -#include "webkit/api/public/WebVector.h" -#include "webkit/api/public/WebViewClient.h" -#include "webkit/api/src/DOMUtilitiesPrivate.h" -#include "webkit/api/src/WebInputEventConversion.h" -#include "webkit/api/src/WebPopupMenuImpl.h" -#include "webkit/api/src/WebSettingsImpl.h" -#include "webkit/glue/glue_util.h" -#include "webkit/glue/webdevtoolsagent_impl.h" -#include "webkit/glue/webkit_glue.h" -#include "webkit/glue/webview_impl.h" - -// Get rid of WTF's pow define so we can use std::pow. -#undef pow -#include <cmath> // for std::pow - -using namespace WebCore; - -using WebKit::ChromeClientImpl; -using WebKit::EditorClientImpl; -using WebKit::PlatformKeyboardEventBuilder; -using WebKit::PlatformMouseEventBuilder; -using WebKit::PlatformWheelEventBuilder; -using WebKit::WebAccessibilityObject; -using WebKit::WebCanvas; -using WebKit::WebCompositionCommand; -using WebKit::WebCompositionCommandConfirm; -using WebKit::WebCompositionCommandDiscard; -using WebKit::WebDevToolsAgent; -using WebKit::WebDevToolsAgentClient; -using WebKit::WebDragData; -using WebKit::WebDragOperation; -using WebKit::WebDragOperationCopy; -using WebKit::WebDragOperationNone; -using WebKit::WebDragOperationsMask; -using WebKit::WebFrame; -using WebKit::WebFrameClient; -using WebKit::WebInputEvent; -using WebKit::WebKeyboardEvent; -using WebKit::WebMediaPlayerAction; -using WebKit::WebMouseEvent; -using WebKit::WebMouseWheelEvent; -using WebKit::WebNavigationPolicy; -using WebKit::WebNode; -using WebKit::WebPoint; -using WebKit::WebPopupMenuImpl; -using WebKit::WebRect; -using WebKit::WebSettings; -using WebKit::WebSettingsImpl; -using WebKit::WebSize; -using WebKit::WebString; -using WebKit::WebTextDirection; -using WebKit::WebTextDirectionDefault; -using WebKit::WebTextDirectionLeftToRight; -using WebKit::WebTextDirectionRightToLeft; -using WebKit::WebURL; -using WebKit::WebVector; -using WebKit::WebViewClient; - -using webkit_glue::AccessibilityObjectToWebAccessibilityObject; - -// Change the text zoom level by kTextSizeMultiplierRatio each time the user -// zooms text in or out (ie., change by 20%). The min and max values limit -// text zoom to half and 3x the original text size. These three values match -// those in Apple's port in WebKit/WebKit/WebView/WebView.mm -static const double kTextSizeMultiplierRatio = 1.2; -static const double kMinTextSizeMultiplier = 0.5; -static const double kMaxTextSizeMultiplier = 3.0; - -// The group name identifies a namespace of pages. Page group is used on OSX -// for some programs that use HTML views to display things that don't seem like -// web pages to the user (so shouldn't have visited link coloring). We only use -// one page group. -// FIXME: This needs to go into the WebKit API implementation and be hidden -// from the API's users. -const char* pageGroupName = "default"; - -// Ensure that the WebKit::WebDragOperation enum values stay in sync with -// the original WebCore::DragOperation constants. -#define COMPILE_ASSERT_MATCHING_ENUM(webcore_name) \ - COMPILE_ASSERT(int(WebCore::webcore_name) == int(WebKit::Web##webcore_name),\ - dummy##webcore_name) -COMPILE_ASSERT_MATCHING_ENUM(DragOperationNone); -COMPILE_ASSERT_MATCHING_ENUM(DragOperationCopy); -COMPILE_ASSERT_MATCHING_ENUM(DragOperationLink); -COMPILE_ASSERT_MATCHING_ENUM(DragOperationGeneric); -COMPILE_ASSERT_MATCHING_ENUM(DragOperationPrivate); -COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove); -COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete); -COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery); - -// AutocompletePopupMenuClient -class AutocompletePopupMenuClient : public WebCore::PopupMenuClient { - public: - AutocompletePopupMenuClient(WebViewImpl* webview) : text_field_(NULL), - selected_index_(0), - webview_(webview) { - } - - void Init(WebCore::HTMLInputElement* text_field, - const WebVector<WebString>& suggestions, - int default_suggestion_index) { - ASSERT(default_suggestion_index < static_cast<int>(suggestions.size())); - text_field_ = text_field; - selected_index_ = default_suggestion_index; - SetSuggestions(suggestions); - - FontDescription font_description; - webview_->theme()->systemFont(CSSValueWebkitControl, font_description); - // Use a smaller font size to match IE/Firefox. - // TODO(jcampan): http://crbug.com/7376 use the system size instead of a - // fixed font size value. - font_description.setComputedSize(12.0); - Font font(font_description, 0, 0); - font.update(text_field->document()->styleSelector()->fontSelector()); - // The direction of text in popup menu is set the same as the direction of - // the input element: text_field. - style_.set(new PopupMenuStyle(Color::black, Color::white, font, true, - Length(WebCore::Fixed), text_field->renderer()->style()->direction())); - } - - virtual ~AutocompletePopupMenuClient() { - } - - // WebCore::PopupMenuClient implementation. - virtual void valueChanged(unsigned listIndex, bool fireEvents = true) { - text_field_->setValue(suggestions_[listIndex]); - EditorClientImpl* editor = - static_cast<EditorClientImpl*>(webview_->page()->editorClient()); - ASSERT(editor); - editor->onAutofillSuggestionAccepted( - static_cast<WebCore::HTMLInputElement*>(text_field_.get())); - } - - virtual WebCore::String itemText(unsigned list_index) const { - return suggestions_[list_index]; - } - - virtual WebCore::String itemToolTip(unsigned last_index) const { - notImplemented(); - return WebCore::String(); - } - - virtual bool itemIsEnabled(unsigned listIndex) const { - return true; - } - - virtual PopupMenuStyle itemStyle(unsigned listIndex) const { - return *style_; - } - - virtual PopupMenuStyle menuStyle() const { - return *style_; - } - - virtual int clientInsetLeft() const { - return 0; - } - virtual int clientInsetRight() const { - return 0; - } - virtual int clientPaddingLeft() const { - // Bug http://crbug.com/7708 seems to indicate the style can be NULL. - WebCore::RenderStyle* style = GetTextFieldStyle(); - return style ? webview_->theme()->popupInternalPaddingLeft(style) : 0; - } - virtual int clientPaddingRight() const { - // Bug http://crbug.com/7708 seems to indicate the style can be NULL. - WebCore::RenderStyle* style = GetTextFieldStyle(); - return style ? webview_->theme()->popupInternalPaddingRight(style) : 0; - } - virtual int listSize() const { - return suggestions_.size(); - } - virtual int selectedIndex() const { - return selected_index_; - } - virtual void popupDidHide() { - webview_->AutoCompletePopupDidHide(); - } - virtual bool itemIsSeparator(unsigned listIndex) const { - return false; - } - virtual bool itemIsLabel(unsigned listIndex) const { - return false; - } - virtual bool itemIsSelected(unsigned listIndex) const { - return false; - } - virtual bool shouldPopOver() const { - return false; - } - virtual bool valueShouldChangeOnHotTrack() const { - return false; - } - - virtual void setTextFromItem(unsigned listIndex) { - text_field_->setValue(suggestions_[listIndex]); - } - - virtual FontSelector* fontSelector() const { - return text_field_->document()->styleSelector()->fontSelector(); - } - - virtual HostWindow* hostWindow() const { - return text_field_->document()->view()->hostWindow(); - } - - virtual PassRefPtr<Scrollbar> createScrollbar( - ScrollbarClient* client, - ScrollbarOrientation orientation, - ScrollbarControlSize size) { - RefPtr<Scrollbar> widget = Scrollbar::createNativeScrollbar(client, - orientation, - size); - return widget.release(); - } - - // AutocompletePopupMenuClient specific methods: - void SetSuggestions(const WebVector<WebString>& suggestions) { - suggestions_.clear(); - for (size_t i = 0; i < suggestions.size(); ++i) - suggestions_.append(webkit_glue::WebStringToString(suggestions[i])); - // Try to preserve selection if possible. - if (selected_index_ >= static_cast<int>(suggestions.size())) - selected_index_ = -1; - } - - void RemoveItemAtIndex(int index) { - ASSERT(index >= 0 && index < static_cast<int>(suggestions_.size())); - suggestions_.remove(index); - } - - WebCore::HTMLInputElement* text_field() const { - return text_field_.get(); - } - - WebCore::RenderStyle* GetTextFieldStyle() const { - WebCore::RenderStyle* style = text_field_->computedStyle(); - if (!style) { - // It seems we can only have an NULL style in a TextField if the node is - // dettached, in which case we the popup shoud not be showing. Please - // report this in http://crbug.com/7708 and include the page you were - // visiting. - ASSERT_NOT_REACHED(); - } - return style; - } - - private: - RefPtr<WebCore::HTMLInputElement> text_field_; - Vector<WebCore::String> suggestions_; - int selected_index_; - WebViewImpl* webview_; - OwnPtr<PopupMenuStyle> style_; -}; - -// Note that focusOnShow is false so that the autocomplete popup is shown not -// activated. We need the page to still have focus so the user can keep typing -// while the popup is showing. -static const WebCore::PopupContainerSettings kAutocompletePopupSettings = { - false, // focusOnShow - false, // setTextOnIndexChange - false, // acceptOnAbandon - true, // loopSelectionNavigation - true, // restrictWidthOfListBox. Same as other browser (Fx, IE, and safari) - // For autocomplete, we use the direction of the input field as the direction - // of the popup items. The main reason is to keep the display of items in - // drop-down the same as the items in the input field. - WebCore::PopupContainerSettings::DOMElementDirection, -}; - -// WebView ---------------------------------------------------------------- - -namespace WebKit { - -// static -WebView* WebView::create(WebViewClient* client) { - return new WebViewImpl(client); -} - -// static -void WebView::updateVisitedLinkState(unsigned long long link_hash) { - WebCore::Page::visitedStateChanged( - WebCore::PageGroup::pageGroup(pageGroupName), link_hash); -} - -// static -void WebView::resetVisitedLinkState() { - WebCore::Page::allVisitedStateChanged( - WebCore::PageGroup::pageGroup(pageGroupName)); -} - -} // namespace WebKit - -void WebViewImpl::initializeMainFrame(WebFrameClient* frame_client) { - // NOTE: The WebFrameImpl takes a reference to itself within InitMainFrame - // and releases that reference once the corresponding Frame is destroyed. - RefPtr<WebFrameImpl> main_frame = WebFrameImpl::create(frame_client); - - main_frame->InitMainFrame(this); - - if (client_) { - WebDevToolsAgentClient* tools_client = client_->devToolsAgentClient(); - if (tools_client) - devtools_agent_.set(new WebDevToolsAgentImpl(this, tools_client)); - } - - // Restrict the access to the local file system - // (see WebView.mm WebView::_commonInitializationWithFrameName). - SecurityOrigin::setLocalLoadPolicy( - SecurityOrigin::AllowLocalLoadsForLocalOnly); -} - -WebViewImpl::WebViewImpl(WebViewClient* client) - : client_(client), - ALLOW_THIS_IN_INITIALIZER_LIST(back_forward_list_client_impl_(this)), - ALLOW_THIS_IN_INITIALIZER_LIST(chrome_client_impl_(this)), - ALLOW_THIS_IN_INITIALIZER_LIST(context_menu_client_impl_(this)), - ALLOW_THIS_IN_INITIALIZER_LIST(drag_client_impl_(this)), - ALLOW_THIS_IN_INITIALIZER_LIST(editor_client_impl_(this)), - ALLOW_THIS_IN_INITIALIZER_LIST(inspector_client_impl_(this)), - observed_new_navigation_(false), -#ifndef NDEBUG - new_navigation_loader_(NULL), -#endif - zoom_level_(0), - context_menu_allowed_(false), - doing_drag_and_drop_(false), - ignore_input_events_(false), - suppress_next_keypress_event_(false), - initial_navigation_policy_(WebKit::WebNavigationPolicyIgnore), - ime_accept_events_(true), - drag_target_dispatch_(false), - drag_identity_(0), - drop_effect_(DROP_EFFECT_DEFAULT), - operations_allowed_(WebKit::WebDragOperationNone), - drag_operation_(WebKit::WebDragOperationNone), - autocomplete_popup_showing_(false), - is_transparent_(false), - tabs_to_links_(false) { - // WebKit/win/WebView.cpp does the same thing, except they call the - // KJS specific wrapper around this method. We need to have threading - // initialized because CollatorICU requires it. - WTF::initializeThreading(); - - // set to impossible point so we always get the first mouse pos - last_mouse_position_ = WebPoint(-1, -1); - - // the page will take ownership of the various clients - page_.set(new Page(&chrome_client_impl_, - &context_menu_client_impl_, - &editor_client_impl_, - &drag_client_impl_, - &inspector_client_impl_, - NULL)); - - page_->backForwardList()->setClient(&back_forward_list_client_impl_); - page_->setGroupName(pageGroupName); -} - -WebViewImpl::~WebViewImpl() { - ASSERT(page_ == NULL); -} - -RenderTheme* WebViewImpl::theme() const { - return page_.get() ? page_->theme() : RenderTheme::defaultTheme().get(); -} - -bool WebViewImpl::tabKeyCyclesThroughElements() const { - ASSERT(page_.get()); - return page_->tabKeyCyclesThroughElements(); -} - -void WebViewImpl::setTabKeyCyclesThroughElements(bool value) { - if (page_ != NULL) { - page_->setTabKeyCyclesThroughElements(value); - } -} - -void WebViewImpl::MouseMove(const WebMouseEvent& event) { - if (!main_frame() || !main_frame()->frameview()) - return; - - last_mouse_position_ = WebPoint(event.x, event.y); - - // We call mouseMoved here instead of handleMouseMovedEvent because we need - // our ChromeClientImpl to receive changes to the mouse position and - // tooltip text, and mouseMoved handles all of that. - main_frame()->frame()->eventHandler()->mouseMoved( - PlatformMouseEventBuilder(main_frame()->frameview(), event)); -} - -void WebViewImpl::MouseLeave(const WebMouseEvent& event) { - // This event gets sent as the main frame is closing. In that case, just - // ignore it. - if (!main_frame() || !main_frame()->frameview()) - return; - - client_->setMouseOverURL(WebURL()); - - main_frame()->frame()->eventHandler()->handleMouseMoveEvent( - PlatformMouseEventBuilder(main_frame()->frameview(), event)); -} - -void WebViewImpl::MouseDown(const WebMouseEvent& event) { - if (!main_frame() || !main_frame()->frameview()) - return; - - last_mouse_down_point_ = WebPoint(event.x, event.y); - - // If a text field that has focus is clicked again, we should display the - // autocomplete popup. - RefPtr<Node> clicked_node; - if (event.button == WebMouseEvent::ButtonLeft) { - RefPtr<Node> focused_node = GetFocusedNode(); - if (focused_node.get() && - WebKit::toHTMLInputElement(focused_node.get())) { - IntPoint point(event.x, event.y); - point = page_->mainFrame()->view()->windowToContents(point); - HitTestResult result(point); - result = page_->mainFrame()->eventHandler()->hitTestResultAtPoint(point, - false); - if (result.innerNonSharedNode() == focused_node) { - // Already focused text field was clicked, let's remember this. If - // focus has not changed after the mouse event is processed, we'll - // trigger the autocomplete. - clicked_node = focused_node; - } - } - } - - main_frame()->frame()->eventHandler()->handleMousePressEvent( - PlatformMouseEventBuilder(main_frame()->frameview(), event)); - - if (clicked_node.get() && clicked_node == GetFocusedNode()) { - // Focus has not changed, show the autocomplete popup. - static_cast<EditorClientImpl*>(page_->editorClient())-> - showFormAutofillForNode(clicked_node.get()); - } - - // Dispatch the contextmenu event regardless of if the click was swallowed. - // On Windows, we handle it on mouse up, not down. -#if PLATFORM(DARWIN) - if (event.button == WebMouseEvent::ButtonRight || - (event.button == WebMouseEvent::ButtonLeft && - event.modifiers & WebMouseEvent::ControlKey)) { - MouseContextMenu(event); - } -#elif PLATFORM(LINUX) - if (event.button == WebMouseEvent::ButtonRight) - MouseContextMenu(event); -#endif -} - -void WebViewImpl::MouseContextMenu(const WebMouseEvent& event) { - if (!main_frame() || !main_frame()->frameview()) - return; - - page_->contextMenuController()->clearContextMenu(); - - PlatformMouseEventBuilder pme(main_frame()->frameview(), event); - - // Find the right target frame. See issue 1186900. - HitTestResult result = HitTestResultForWindowPos(pme.pos()); - Frame* target_frame; - if (result.innerNonSharedNode()) - target_frame = result.innerNonSharedNode()->document()->frame(); - else - target_frame = page_->focusController()->focusedOrMainFrame(); - -#if PLATFORM(WIN_OS) - target_frame->view()->setCursor(pointerCursor()); -#endif - - context_menu_allowed_ = true; - target_frame->eventHandler()->sendContextMenuEvent(pme); - context_menu_allowed_ = false; - // Actually showing the context menu is handled by the ContextMenuClient - // implementation... -} - -void WebViewImpl::MouseUp(const WebMouseEvent& event) { - if (!main_frame() || !main_frame()->frameview()) - return; - -#if PLATFORM(LINUX) - // If the event was a middle click, attempt to copy text into the focused - // frame. We execute this before we let the page have a go at the event - // because the page may change what is focused during in its event handler. - // - // This code is in the mouse up handler. There is some debate about putting - // this here, as opposed to the mouse down handler. - // xterm: pastes on up. - // GTK: pastes on down. - // Firefox: pastes on up. - // Midori: couldn't paste at all with 0.1.2 - // - // There is something of a webcompat angle to this well, as highlighted by - // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on - // down then the text is pasted just before the onclick handler runs and - // clears the text box. So it's important this happens after the - // handleMouseReleaseEvent() earlier in this function - if (event.button == WebMouseEvent::ButtonMiddle) { - Frame* focused = GetFocusedWebCoreFrame(); - IntPoint click_point(last_mouse_down_point_.x, last_mouse_down_point_.y); - click_point = page_->mainFrame()->view()->windowToContents(click_point); - HitTestResult hit_test_result = - focused->eventHandler()->hitTestResultAtPoint(click_point, false, false, - ShouldHitTestScrollbars); - // We don't want to send a paste when middle clicking a scroll bar or a - // link (which will navigate later in the code). - if (!hit_test_result.scrollbar() && !hit_test_result.isLiveLink() && - focused) { - Editor* editor = focused->editor(); - Pasteboard* pasteboard = Pasteboard::generalPasteboard(); - bool oldSelectionMode = pasteboard->isSelectionMode(); - pasteboard->setSelectionMode(true); - editor->command(AtomicString("Paste")).execute(); - pasteboard->setSelectionMode(oldSelectionMode); - } - } -#endif - - mouseCaptureLost(); - main_frame()->frame()->eventHandler()->handleMouseReleaseEvent( - PlatformMouseEventBuilder(main_frame()->frameview(), event)); - -#if PLATFORM(WIN_OS) - // Dispatch the contextmenu event regardless of if the click was swallowed. - // On Mac/Linux, we handle it on mouse down, not up. - if (event.button == WebMouseEvent::ButtonRight) - MouseContextMenu(event); -#endif -} - -void WebViewImpl::MouseWheel(const WebMouseWheelEvent& event) { - PlatformWheelEventBuilder platform_event(main_frame()->frameview(), event); - main_frame()->frame()->eventHandler()->handleWheelEvent(platform_event); -} - -bool WebViewImpl::KeyEvent(const WebKeyboardEvent& event) { - ASSERT((event.type == WebInputEvent::RawKeyDown) || - (event.type == WebInputEvent::KeyDown) || - (event.type == WebInputEvent::KeyUp)); - - // Please refer to the comments explaining the suppress_next_keypress_event_ - // member. - // The suppress_next_keypress_event_ is set if the KeyDown is handled by - // Webkit. A keyDown event is typically associated with a keyPress(char) - // event and a keyUp event. We reset this flag here as this is a new keyDown - // event. - suppress_next_keypress_event_ = false; - - // Give autocomplete a chance to consume the key events it is interested in. - if (AutocompleteHandleKeyEvent(event)) - return true; - - Frame* frame = GetFocusedWebCoreFrame(); - if (!frame) - return false; - - EventHandler* handler = frame->eventHandler(); - if (!handler) - return KeyEventDefault(event); - -#if PLATFORM(WIN_OS) || PLATFORM(LINUX) - if (((event.modifiers == 0) && (event.windowsKeyCode == VKEY_APPS)) || - ((event.modifiers == WebInputEvent::ShiftKey) && - (event.windowsKeyCode == VKEY_F10))) { - SendContextMenuEvent(event); - return true; - } -#endif - - // It's not clear if we should continue after detecting a capslock keypress. - // I'll err on the side of continuing, which is the pre-existing behaviour. - if (event.windowsKeyCode == VKEY_CAPITAL) - handler->capsLockStateMayHaveChanged(); - - PlatformKeyboardEventBuilder evt(event); - - if (handler->keyEvent(evt)) { - if (WebInputEvent::RawKeyDown == event.type && !evt.isSystemKey()) - suppress_next_keypress_event_ = true; - return true; - } - - return KeyEventDefault(event); -} - -bool WebViewImpl::AutocompleteHandleKeyEvent(const WebKeyboardEvent& event) { - if (!autocomplete_popup_showing_ || - // Home and End should be left to the text field to process. - event.windowsKeyCode == VKEY_HOME || - event.windowsKeyCode == VKEY_END) { - return false; - } - - // Pressing delete triggers the removal of the selected suggestion from the - // DB. - if (event.windowsKeyCode == VKEY_DELETE && - autocomplete_popup_->selectedIndex() != -1) { - Node* node = GetFocusedNode(); - if (!node || (node->nodeType() != WebCore::Node::ELEMENT_NODE)) { - ASSERT_NOT_REACHED(); - return false; - } - WebCore::Element* element = static_cast<WebCore::Element*>(node); - if (!element->hasLocalName(WebCore::HTMLNames::inputTag)) { - ASSERT_NOT_REACHED(); - return false; - } - - int selected_index = autocomplete_popup_->selectedIndex(); - WebCore::HTMLInputElement* input_element = - static_cast<WebCore::HTMLInputElement*>(element); - const WebString& name = webkit_glue::StringToWebString( - input_element->name()); - const WebString& value = webkit_glue::StringToWebString( - autocomplete_popup_client_->itemText(selected_index)); - client_->removeAutofillSuggestions(name, value); - // Update the entries in the currently showing popup to reflect the - // deletion. - autocomplete_popup_client_->RemoveItemAtIndex(selected_index); - RefreshAutofillPopup(); - return false; - } - - if (!autocomplete_popup_->isInterestedInEventForKey(event.windowsKeyCode)) - return false; - - if (autocomplete_popup_->handleKeyEvent( - PlatformKeyboardEventBuilder(event))) { - // We need to ignore the next Char event after this otherwise pressing - // enter when selecting an item in the menu will go to the page. - if (WebInputEvent::RawKeyDown == event.type) - suppress_next_keypress_event_ = true; - return true; - } - - return false; -} - -bool WebViewImpl::CharEvent(const WebKeyboardEvent& event) { - ASSERT(event.type == WebInputEvent::Char); - - // Please refer to the comments explaining the suppress_next_keypress_event_ - // member. - // The suppress_next_keypress_event_ is set if the KeyDown is handled by - // Webkit. A keyDown event is typically associated with a keyPress(char) - // event and a keyUp event. We reset this flag here as it only applies - // to the current keyPress event. - if (suppress_next_keypress_event_) { - suppress_next_keypress_event_ = false; - return true; - } - - Frame* frame = GetFocusedWebCoreFrame(); - if (!frame) - return false; - - EventHandler* handler = frame->eventHandler(); - if (!handler) - return KeyEventDefault(event); - - PlatformKeyboardEventBuilder evt(event); - if (!evt.isCharacterKey()) - return true; - - // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to - // the eventHandler::keyEvent. We mimic this behavior on all platforms since - // for now we are converting other platform's key events to windows key - // events. - if (evt.isSystemKey()) - return handler->handleAccessKey(evt); - - if (!handler->keyEvent(evt)) - return KeyEventDefault(event); - - return true; -} - -/* -* The WebViewImpl::SendContextMenuEvent function is based on the Webkit -* function -* bool WebView::handleContextMenuEvent(WPARAM wParam, LPARAM lParam) in -* webkit\webkit\win\WebView.cpp. The only significant change in this -* function is the code to convert from a Keyboard event to the Right -* Mouse button up event. -* -* This function is an ugly copy/paste and should be cleaned up when the -* WebKitWin version is cleaned: https://bugs.webkit.org/show_bug.cgi?id=20438 -*/ -#if PLATFORM(WIN_OS) || PLATFORM(LINUX) -// TODO(pinkerton): implement on non-windows -bool WebViewImpl::SendContextMenuEvent(const WebKeyboardEvent& event) { - static const int kContextMenuMargin = 1; - Frame* main_frame = page()->mainFrame(); - FrameView* view = main_frame->view(); - if (!view) - return false; - - IntPoint coords(-1, -1); -#if PLATFORM(WIN_OS) - int right_aligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT); -#else - int right_aligned = 0; -#endif - IntPoint location; - - // The context menu event was generated from the keyboard, so show the - // context menu by the current selection. - Position start = main_frame->selection()->selection().start(); - Position end = main_frame->selection()->selection().end(); - - if (!start.node() || !end.node()) { - location = - IntPoint(right_aligned ? view->contentsWidth() - kContextMenuMargin - : kContextMenuMargin, kContextMenuMargin); - } else { - RenderObject* renderer = start.node()->renderer(); - if (!renderer) - return false; - - RefPtr<Range> selection = main_frame->selection()->toNormalizedRange(); - IntRect first_rect = main_frame->firstRectForRange(selection.get()); - - int x = right_aligned ? first_rect.right() : first_rect.x(); - location = IntPoint(x, first_rect.bottom()); - } - - location = view->contentsToWindow(location); - // FIXME: The IntSize(0, -1) is a hack to get the hit-testing to result in - // the selected element. Ideally we'd have the position of a context menu - // event be separate from its target node. - coords = location + IntSize(0, -1); - - // The contextMenuController() holds onto the last context menu that was - // popped up on the page until a new one is created. We need to clear - // this menu before propagating the event through the DOM so that we can - // detect if we create a new menu for this event, since we won't create - // a new menu if the DOM swallows the event and the defaultEventHandler does - // not run. - page()->contextMenuController()->clearContextMenu(); - - Frame* focused_frame = page()->focusController()->focusedOrMainFrame(); - focused_frame->view()->setCursor(pointerCursor()); - WebMouseEvent mouse_event; - mouse_event.button = WebMouseEvent::ButtonRight; - mouse_event.x = coords.x(); - mouse_event.y = coords.y(); - mouse_event.type = WebInputEvent::MouseUp; - - PlatformMouseEventBuilder platform_event(view, mouse_event); - - context_menu_allowed_ = true; - bool handled = - focused_frame->eventHandler()->sendContextMenuEvent(platform_event); - context_menu_allowed_ = false; - return handled; -} -#endif - -bool WebViewImpl::KeyEventDefault(const WebKeyboardEvent& event) { - Frame* frame = GetFocusedWebCoreFrame(); - if (!frame) - return false; - - switch (event.type) { - case WebInputEvent::Char: { - if (event.windowsKeyCode == VKEY_SPACE) { - int key_code = ((event.modifiers & WebInputEvent::ShiftKey) ? - VKEY_PRIOR : VKEY_NEXT); - return ScrollViewWithKeyboard(key_code, event.modifiers); - } - break; - } - - case WebInputEvent::RawKeyDown: { - if (event.modifiers == WebInputEvent::ControlKey) { - switch (event.windowsKeyCode) { - case 'A': - focusedFrame()->executeCommand(WebString::fromUTF8("SelectAll")); - return true; - case VKEY_INSERT: - case 'C': - focusedFrame()->executeCommand(WebString::fromUTF8("Copy")); - return true; - // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl - // key combinations which affect scrolling. Safari is buggy in the - // sense that it scrolls the page for all Ctrl+scrolling key - // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc. - case VKEY_HOME: - case VKEY_END: - break; - default: - return false; - } - } - if (!event.isSystemKey && !(event.modifiers & WebInputEvent::ShiftKey)) { - return ScrollViewWithKeyboard(event.windowsKeyCode, event.modifiers); - } - break; - } - - default: - break; - } - return false; -} - -bool WebViewImpl::ScrollViewWithKeyboard(int key_code, int modifiers) { - ScrollDirection scroll_direction; - ScrollGranularity scroll_granularity; - - switch (key_code) { - case VKEY_LEFT: - scroll_direction = ScrollLeft; - scroll_granularity = ScrollByLine; - break; - case VKEY_RIGHT: - scroll_direction = ScrollRight; - scroll_granularity = ScrollByLine; - break; - case VKEY_UP: - scroll_direction = ScrollUp; - scroll_granularity = ScrollByLine; - break; - case VKEY_DOWN: - scroll_direction = ScrollDown; - scroll_granularity = ScrollByLine; - break; - case VKEY_HOME: - scroll_direction = ScrollUp; - scroll_granularity = ScrollByDocument; - break; - case VKEY_END: - scroll_direction = ScrollDown; - scroll_granularity = ScrollByDocument; - break; - case VKEY_PRIOR: // page up - scroll_direction = ScrollUp; - scroll_granularity = ScrollByPage; - break; - case VKEY_NEXT: // page down - scroll_direction = ScrollDown; - scroll_granularity = ScrollByPage; - break; - default: - return false; - } - - return PropagateScroll(scroll_direction, scroll_granularity); -} - -bool WebViewImpl::PropagateScroll( - WebCore::ScrollDirection scroll_direction, - WebCore::ScrollGranularity scroll_granularity) { - - Frame* frame = GetFocusedWebCoreFrame(); - if (!frame) - return false; - - bool scroll_handled = - frame->eventHandler()->scrollOverflow(scroll_direction, - scroll_granularity); - Frame* current_frame = frame; - while (!scroll_handled && current_frame) { - scroll_handled = current_frame->view()->scroll(scroll_direction, - scroll_granularity); - current_frame = current_frame->tree()->parent(); - } - return scroll_handled; -} - -Frame* WebViewImpl::GetFocusedWebCoreFrame() { - return page_.get() ? page_->focusController()->focusedOrMainFrame() : NULL; -} - -// static -WebViewImpl* WebViewImpl::FromPage(WebCore::Page* page) { - if (!page) - return NULL; - - return static_cast<ChromeClientImpl*>(page->chrome()->client())->webview(); -} - -// WebWidget ------------------------------------------------------------------ - -void WebViewImpl::close() { - RefPtr<WebFrameImpl> main_frame; - - if (page_.get()) { - // Initiate shutdown for the entire frameset. This will cause a lot of - // notifications to be sent. - if (page_->mainFrame()) { - main_frame = WebFrameImpl::FromFrame(page_->mainFrame()); - page_->mainFrame()->loader()->frameDetached(); - } - page_.clear(); - } - - // Should happen after page_.reset(). - if (devtools_agent_.get()) - devtools_agent_.clear(); - - // We drop the client after the page has been destroyed to support the - // WebFrameClient::didDestroyScriptContext method. - if (main_frame) - main_frame->drop_client(); - - // Reset the delegate to prevent notifications being sent as we're being - // deleted. - client_ = NULL; - - deref(); // Balances ref() acquired in WebView::create -} - -void WebViewImpl::resize(const WebSize& new_size) { - if (size_ == new_size) - return; - size_ = new_size; - - if (main_frame()->frameview()) { - main_frame()->frameview()->resize(size_.width, size_.height); - main_frame()->frame()->eventHandler()->sendResizeEvent(); - } - - if (client_) { - WebRect damaged_rect(0, 0, size_.width, size_.height); - client_->didInvalidateRect(damaged_rect); - } -} - -void WebViewImpl::layout() { - WebFrameImpl* webframe = main_frame(); - if (webframe) { - // In order for our child HWNDs (NativeWindowWidgets) to update properly, - // they need to be told that we are updating the screen. The problem is - // that the native widgets need to recalculate their clip region and not - // overlap any of our non-native widgets. To force the resizing, call - // setFrameRect(). This will be a quick operation for most frames, but - // the NativeWindowWidgets will update a proper clipping region. - FrameView* view = webframe->frameview(); - if (view) - view->setFrameRect(view->frameRect()); - - // setFrameRect may have the side-effect of causing existing page - // layout to be invalidated, so layout needs to be called last. - - webframe->Layout(); - } -} - -void WebViewImpl::paint(WebCanvas* canvas, const WebRect& rect) { - WebFrameImpl* webframe = main_frame(); - if (webframe) - webframe->Paint(canvas, rect); -} - -// TODO(eseidel): g_current_input_event should be removed once -// ChromeClient:show() can get the current-event information from WebCore. -/* static */ -const WebInputEvent* WebViewImpl::g_current_input_event = NULL; - -bool WebViewImpl::handleInputEvent(const WebInputEvent& input_event) { - // If we've started a drag and drop operation, ignore input events until - // we're done. - if (doing_drag_and_drop_) - return true; - - if (ignore_input_events_) - return true; - - // TODO(eseidel): Remove g_current_input_event. - // This only exists to allow ChromeClient::show() to know which mouse button - // triggered a window.open event. - // Safari must perform a similar hack, ours is in our WebKit glue layer - // theirs is in the application. This should go when WebCore can be fixed - // to pass more event information to ChromeClient::show() - g_current_input_event = &input_event; - - bool handled = true; - - // TODO(jcampan): WebKit seems to always return false on mouse events - // processing methods. For now we'll assume it has processed them (as we are - // only interested in whether keyboard events are processed). - switch (input_event.type) { - case WebInputEvent::MouseMove: - MouseMove(*static_cast<const WebMouseEvent*>(&input_event)); - break; - - case WebInputEvent::MouseLeave: - MouseLeave(*static_cast<const WebMouseEvent*>(&input_event)); - break; - - case WebInputEvent::MouseWheel: - MouseWheel(*static_cast<const WebMouseWheelEvent*>(&input_event)); - break; - - case WebInputEvent::MouseDown: - MouseDown(*static_cast<const WebMouseEvent*>(&input_event)); - break; - - case WebInputEvent::MouseUp: - MouseUp(*static_cast<const WebMouseEvent*>(&input_event)); - break; - - case WebInputEvent::RawKeyDown: - case WebInputEvent::KeyDown: - case WebInputEvent::KeyUp: - handled = KeyEvent(*static_cast<const WebKeyboardEvent*>(&input_event)); - break; - - case WebInputEvent::Char: - handled = CharEvent(*static_cast<const WebKeyboardEvent*>(&input_event)); - break; - default: - handled = false; - } - - g_current_input_event = NULL; - - return handled; -} - -void WebViewImpl::mouseCaptureLost() { -} - -void WebViewImpl::setFocus(bool enable) { - page_->focusController()->setFocused(enable); - if (enable) { - // Note that we don't call setActive() when disabled as this cause extra - // focus/blur events to be dispatched. - page_->focusController()->setActive(true); - ime_accept_events_ = true; - } else { - HideAutoCompletePopup(); - - // Clear focus on the currently focused frame if any. - if (!page_.get()) - return; - - Frame* frame = page_->mainFrame(); - if (!frame) - return; - - RefPtr<Frame> focused_frame = page_->focusController()->focusedFrame(); - if (focused_frame.get()) { - // Finish an ongoing composition to delete the composition node. - Editor* editor = focused_frame->editor(); - if (editor && editor->hasComposition()) - editor->confirmComposition(); - ime_accept_events_ = false; - } - } -} - -bool WebViewImpl::handleCompositionEvent(WebCompositionCommand command, - int cursor_position, - int target_start, - int target_end, - const WebString& ime_string) { - Frame* focused = GetFocusedWebCoreFrame(); - if (!focused || !ime_accept_events_) { - return false; - } - Editor* editor = focused->editor(); - if (!editor) - return false; - if (!editor->canEdit()) { - // The input focus has been moved to another WebWidget object. - // We should use this |editor| object only to complete the ongoing - // composition. - if (!editor->hasComposition()) - return false; - } - - // We should verify the parent node of this IME composition node are - // editable because JavaScript may delete a parent node of the composition - // node. In this case, WebKit crashes while deleting texts from the parent - // node, which doesn't exist any longer. - PassRefPtr<Range> range = editor->compositionRange(); - if (range) { - const Node* node = range->startPosition().node(); - if (!node || !node->isContentEditable()) - return false; - } - - if (command == WebCompositionCommandDiscard) { - // A browser process sent an IPC message which does not contain a valid - // string, which means an ongoing composition has been canceled. - // If the ongoing composition has been canceled, replace the ongoing - // composition string with an empty string and complete it. - WebCore::String empty_string; - WTF::Vector<WebCore::CompositionUnderline> empty_underlines; - editor->setComposition(empty_string, empty_underlines, 0, 0); - } else { - // A browser process sent an IPC message which contains a string to be - // displayed in this Editor object. - // To display the given string, set the given string to the - // m_compositionNode member of this Editor object and display it. - if (target_start < 0) - target_start = 0; - if (target_end < 0) - target_end = static_cast<int>(ime_string.length()); - WebCore::String composition_string( - webkit_glue::WebStringToString(ime_string)); - // Create custom underlines. - // To emphasize the selection, the selected region uses a solid black - // for its underline while other regions uses a pale gray for theirs. - WTF::Vector<WebCore::CompositionUnderline> underlines(3); - underlines[0].startOffset = 0; - underlines[0].endOffset = target_start; - underlines[0].thick = true; - underlines[0].color.setRGB(0xd3, 0xd3, 0xd3); - underlines[1].startOffset = target_start; - underlines[1].endOffset = target_end; - underlines[1].thick = true; - underlines[1].color.setRGB(0x00, 0x00, 0x00); - underlines[2].startOffset = target_end; - underlines[2].endOffset = static_cast<int>(ime_string.length()); - underlines[2].thick = true; - underlines[2].color.setRGB(0xd3, 0xd3, 0xd3); - // When we use custom underlines, WebKit ("InlineTextBox.cpp" Line 282) - // prevents from writing a text in between 'selectionStart' and - // 'selectionEnd' somehow. - // Therefore, we use the 'cursor_position' for these arguments so that - // there are not any characters in the above region. - editor->setComposition(composition_string, underlines, - cursor_position, cursor_position); - // The given string is a result string, which means the ongoing - // composition has been completed. I have to call the - // Editor::confirmCompletion() and complete this composition. - if (command == WebCompositionCommandConfirm) - editor->confirmComposition(); - } - - return editor->hasComposition(); -} - -bool WebViewImpl::queryCompositionStatus(bool* enable_ime, - WebRect* caret_rect) { - // Store whether the selected node needs IME and the caret rectangle. - // This process consists of the following four steps: - // 1. Retrieve the selection controller of the focused frame; - // 2. Retrieve the caret rectangle from the controller; - // 3. Convert the rectangle, which is relative to the parent view, to the - // one relative to the client window, and; - // 4. Store the converted rectangle. - const Frame* focused = GetFocusedWebCoreFrame(); - if (!focused) - return false; - - const Editor* editor = focused->editor(); - if (!editor || !editor->canEdit()) - return false; - - SelectionController* controller = focused->selection(); - if (!controller) - return false; - - const Node* node = controller->start().node(); - if (!node) - return false; - - *enable_ime = node->shouldUseInputMethod() && - !controller->isInPasswordField(); - const FrameView* view = node->document()->view(); - if (!view) - return false; - - *caret_rect = webkit_glue::IntRectToWebRect( - view->contentsToWindow(controller->absoluteCaretBounds())); - return true; -} - -void WebViewImpl::setTextDirection(WebTextDirection direction) { - // The Editor::setBaseWritingDirection() function checks if we can change - // the text direction of the selected node and updates its DOM "dir" - // attribute and its CSS "direction" property. - // So, we just call the function as Safari does. - const Frame* focused = GetFocusedWebCoreFrame(); - if (!focused) - return; - - Editor* editor = focused->editor(); - if (!editor || !editor->canEdit()) - return; - - switch (direction) { - case WebTextDirectionDefault: - editor->setBaseWritingDirection(WebCore::NaturalWritingDirection); - break; - - case WebTextDirectionLeftToRight: - editor->setBaseWritingDirection(WebCore::LeftToRightWritingDirection); - break; - - case WebTextDirectionRightToLeft: - editor->setBaseWritingDirection(WebCore::RightToLeftWritingDirection); - break; - - default: - notImplemented(); - break; - } -} - -// WebView -------------------------------------------------------------------- - -WebSettings* WebViewImpl::settings() { - if (!web_settings_.get()) - web_settings_.set(new WebSettingsImpl(page_->settings())); - ASSERT(web_settings_.get()); - return web_settings_.get(); -} - -WebString WebViewImpl::pageEncoding() const { - if (!page_.get()) - return WebString(); - - String encoding_name = page_->mainFrame()->loader()->encoding(); - return webkit_glue::StringToWebString(encoding_name); -} - -void WebViewImpl::setPageEncoding(const WebString& encoding_name) { - if (!page_.get()) - return; - - // Only change override encoding, don't change default encoding. - // Note that the new encoding must be NULL if it isn't supposed to be set. - String new_encoding_name; - if (!encoding_name.isEmpty()) - new_encoding_name = webkit_glue::WebStringToString(encoding_name); - page_->mainFrame()->loader()->reloadWithOverrideEncoding(new_encoding_name); -} - -bool WebViewImpl::dispatchBeforeUnloadEvent() { - // TODO(creis): This should really cause a recursive depth-first walk of all - // frames in the tree, calling each frame's onbeforeunload. At the moment, - // we're consistent with Safari 3.1, not IE/FF. - Frame* frame = page_->focusController()->focusedOrMainFrame(); - if (!frame) - return true; - - return frame->shouldClose(); -} - -void WebViewImpl::dispatchUnloadEvent() { - // Run unload handlers. - page_->mainFrame()->loader()->closeURL(); -} - -WebFrame* WebViewImpl::mainFrame() { - return main_frame(); -} - -WebFrame* WebViewImpl::findFrameByName( - const WebString& name, WebFrame* relative_to_frame) { - String name_str = webkit_glue::WebStringToString(name); - if (!relative_to_frame) - relative_to_frame = mainFrame(); - Frame* frame = static_cast<WebFrameImpl*>(relative_to_frame)->frame(); - frame = frame->tree()->find(name_str); - return WebFrameImpl::FromFrame(frame); -} - -WebFrame* WebViewImpl::focusedFrame() { - return WebFrameImpl::FromFrame(GetFocusedWebCoreFrame()); -} - -void WebViewImpl::setFocusedFrame(WebFrame* frame) { - if (!frame) { - // Clears the focused frame if any. - Frame* frame = GetFocusedWebCoreFrame(); - if (frame) - frame->selection()->setFocused(false); - return; - } - WebFrameImpl* frame_impl = static_cast<WebFrameImpl*>(frame); - WebCore::Frame* webcore_frame = frame_impl->frame(); - webcore_frame->page()->focusController()->setFocusedFrame(webcore_frame); -} - -void WebViewImpl::setInitialFocus(bool reverse) { - if (!page_.get()) - return; - - // Since we don't have a keyboard event, we'll create one. - WebKeyboardEvent keyboard_event; - keyboard_event.type = WebInputEvent::RawKeyDown; - if (reverse) - keyboard_event.modifiers = WebInputEvent::ShiftKey; - - // VK_TAB which is only defined on Windows. - keyboard_event.windowsKeyCode = 0x09; - PlatformKeyboardEventBuilder platform_event(keyboard_event); - RefPtr<KeyboardEvent> webkit_event = - KeyboardEvent::create(platform_event, NULL); - page()->focusController()->setInitialFocus( - reverse ? WebCore::FocusDirectionBackward : - WebCore::FocusDirectionForward, - webkit_event.get()); -} - -void WebViewImpl::clearFocusedNode() { - if (!page_.get()) - return; - - RefPtr<Frame> frame = page_->mainFrame(); - if (!frame.get()) - return; - - RefPtr<Document> document = frame->document(); - if (!document.get()) - return; - - RefPtr<Node> old_focused_node = document->focusedNode(); - - // Clear the focused node. - document->setFocusedNode(NULL); - - if (!old_focused_node.get()) - return; - - // If a text field has focus, we need to make sure the selection controller - // knows to remove selection from it. Otherwise, the text field is still - // processing keyboard events even though focus has been moved to the page and - // keystrokes get eaten as a result. - if (old_focused_node->hasTagName(HTMLNames::textareaTag) || - (old_focused_node->hasTagName(HTMLNames::inputTag) && - static_cast<HTMLInputElement*>(old_focused_node.get())->isTextField())) { - // Clear the selection. - SelectionController* selection = frame->selection(); - selection->clear(); - } -} - -void WebViewImpl::zoomIn(bool text_only) { - Frame* frame = main_frame()->frame(); - double multiplier = std::min(std::pow(kTextSizeMultiplierRatio, - zoom_level_ + 1), - kMaxTextSizeMultiplier); - float zoom_factor = static_cast<float>(multiplier); - if (zoom_factor != frame->zoomFactor()) { - ++zoom_level_; - frame->setZoomFactor(zoom_factor, text_only); - } -} - -void WebViewImpl::zoomOut(bool text_only) { - Frame* frame = main_frame()->frame(); - double multiplier = std::max(std::pow(kTextSizeMultiplierRatio, - zoom_level_ - 1), - kMinTextSizeMultiplier); - float zoom_factor = static_cast<float>(multiplier); - if (zoom_factor != frame->zoomFactor()) { - --zoom_level_; - frame->setZoomFactor(zoom_factor, text_only); - } -} - -void WebViewImpl::zoomDefault() { - // We don't change the zoom mode (text only vs. full page) here. We just want - // to reset whatever is already set. - zoom_level_ = 0; - main_frame()->frame()->setZoomFactor( - 1.0f, - main_frame()->frame()->isZoomFactorTextOnly()); -} - -void WebViewImpl::performMediaPlayerAction(const WebMediaPlayerAction& action, - const WebPoint& location) { - HitTestResult result = - HitTestResultForWindowPos(webkit_glue::WebPointToIntPoint(location)); - WTF::RefPtr<WebCore::Node> node = result.innerNonSharedNode(); - if (!node->hasTagName(WebCore::HTMLNames::videoTag) && - !node->hasTagName(WebCore::HTMLNames::audioTag)) - return; - - WTF::RefPtr<WebCore::HTMLMediaElement> media_element = - static_pointer_cast<WebCore::HTMLMediaElement>(node); - switch (action.type) { - case WebMediaPlayerAction::Play: - if (action.enable) { - media_element->play(); - } else { - media_element->pause(); - } - break; - case WebMediaPlayerAction::Mute: - media_element->setMuted(action.enable); - break; - case WebMediaPlayerAction::Loop: - media_element->setLoop(action.enable); - break; - default: - ASSERT_NOT_REACHED(); - } -} - -void WebViewImpl::copyImageAt(const WebPoint& point) { - if (!page_.get()) - return; - - HitTestResult result = - HitTestResultForWindowPos(webkit_glue::WebPointToIntPoint(point)); - - if (result.absoluteImageURL().isEmpty()) { - // There isn't actually an image at these coordinates. Might be because - // the window scrolled while the context menu was open or because the page - // changed itself between when we thought there was an image here and when - // we actually tried to retreive the image. - // - // TODO: implement a cache of the most recent HitTestResult to avoid having - // to do two hit tests. - return; - } - - page_->mainFrame()->editor()->copyImage(result); -} - -void WebViewImpl::dragSourceEndedAt( - const WebPoint& client_point, - const WebPoint& screen_point, - WebDragOperation operation) { - PlatformMouseEvent pme(webkit_glue::WebPointToIntPoint(client_point), - webkit_glue::WebPointToIntPoint(screen_point), - LeftButton, MouseEventMoved, 0, false, false, false, - false, 0); - page_->mainFrame()->eventHandler()->dragSourceEndedAt(pme, - static_cast<WebCore::DragOperation>(operation)); -} - -void WebViewImpl::dragSourceMovedTo( - const WebPoint& client_point, - const WebPoint& screen_point) { - PlatformMouseEvent pme(webkit_glue::WebPointToIntPoint(client_point), - webkit_glue::WebPointToIntPoint(screen_point), - LeftButton, MouseEventMoved, 0, false, false, false, - false, 0); - page_->mainFrame()->eventHandler()->dragSourceMovedTo(pme); -} - -void WebViewImpl::dragSourceSystemDragEnded() { - // It's possible for us to get this callback while not doing a drag if - // it's from a previous page that got unloaded. - if (doing_drag_and_drop_) { - page_->dragController()->dragEnded(); - doing_drag_and_drop_ = false; - } -} - -WebDragOperation WebViewImpl::dragTargetDragEnter( - const WebDragData& web_drag_data, int identity, - const WebPoint& client_point, - const WebPoint& screen_point, - WebDragOperationsMask operations_allowed) { - ASSERT(!current_drag_data_.get()); - - current_drag_data_ = - webkit_glue::WebDragDataToChromiumDataObject(web_drag_data); - drag_identity_ = identity; - operations_allowed_ = operations_allowed; - - DragData drag_data( - current_drag_data_.get(), - webkit_glue::WebPointToIntPoint(client_point), - webkit_glue::WebPointToIntPoint(screen_point), - static_cast<WebCore::DragOperation>(operations_allowed)); - - drop_effect_ = DROP_EFFECT_DEFAULT; - drag_target_dispatch_ = true; - DragOperation effect = page_->dragController()->dragEntered(&drag_data); - // Mask the operation against the drag source's allowed operations. - if ((effect & drag_data.draggingSourceOperationMask()) != effect) { - effect = DragOperationNone; - } - drag_target_dispatch_ = false; - - if (drop_effect_ != DROP_EFFECT_DEFAULT) - drag_operation_ = (drop_effect_ != DROP_EFFECT_NONE) ? - WebDragOperationCopy : WebDragOperationNone; - else - drag_operation_ = static_cast<WebDragOperation>(effect); - return drag_operation_; -} - -WebDragOperation WebViewImpl::dragTargetDragOver( - const WebPoint& client_point, - const WebPoint& screen_point, - WebDragOperationsMask operations_allowed) { - ASSERT(current_drag_data_.get()); - - operations_allowed_ = operations_allowed; - DragData drag_data( - current_drag_data_.get(), - webkit_glue::WebPointToIntPoint(client_point), - webkit_glue::WebPointToIntPoint(screen_point), - static_cast<WebCore::DragOperation>(operations_allowed)); - - drop_effect_ = DROP_EFFECT_DEFAULT; - drag_target_dispatch_ = true; - DragOperation effect = page_->dragController()->dragUpdated(&drag_data); - // Mask the operation against the drag source's allowed operations. - if ((effect & drag_data.draggingSourceOperationMask()) != effect) { - effect = DragOperationNone; - } - drag_target_dispatch_ = false; - - if (drop_effect_ != DROP_EFFECT_DEFAULT) - drag_operation_ = (drop_effect_ != DROP_EFFECT_NONE) ? - WebDragOperationCopy : WebDragOperationNone; - else - drag_operation_ = static_cast<WebDragOperation>(effect); - return drag_operation_; -} - -void WebViewImpl::dragTargetDragLeave() { - ASSERT(current_drag_data_.get()); - - DragData drag_data( - current_drag_data_.get(), - IntPoint(), - IntPoint(), - static_cast<WebCore::DragOperation>(operations_allowed_)); - - drag_target_dispatch_ = true; - page_->dragController()->dragExited(&drag_data); - drag_target_dispatch_ = false; - - current_drag_data_ = NULL; - drop_effect_ = DROP_EFFECT_DEFAULT; - drag_operation_ = WebDragOperationNone; - drag_identity_ = 0; -} - -void WebViewImpl::dragTargetDrop(const WebPoint& client_point, - const WebPoint& screen_point) { - ASSERT(current_drag_data_.get()); - - // If this webview transitions from the "drop accepting" state to the "not - // accepting" state, then our IPC message reply indicating that may be in- - // flight, or else delayed by javascript processing in this webview. If a - // drop happens before our IPC reply has reached the browser process, then - // the browser forwards the drop to this webview. So only allow a drop to - // proceed if our webview drag_operation_ state is not DragOperationNone. - - if (drag_operation_ == WebDragOperationNone) { // IPC RACE CONDITION: do not allow this drop. - dragTargetDragLeave(); - return; - } - - DragData drag_data( - current_drag_data_.get(), - webkit_glue::WebPointToIntPoint(client_point), - webkit_glue::WebPointToIntPoint(screen_point), - static_cast<WebCore::DragOperation>(operations_allowed_)); - - drag_target_dispatch_ = true; - page_->dragController()->performDrag(&drag_data); - drag_target_dispatch_ = false; - - current_drag_data_ = NULL; - drop_effect_ = DROP_EFFECT_DEFAULT; - drag_operation_ = WebDragOperationNone; - drag_identity_ = 0; -} - -int WebViewImpl::dragIdentity() { - if (drag_target_dispatch_) - return drag_identity_; - return 0; -} - -void WebViewImpl::inspectElementAt(const WebPoint& point) { - if (!page_.get()) - return; - - if (point.x == -1 || point.y == -1) { - page_->inspectorController()->inspect(NULL); - } else { - HitTestResult result = - HitTestResultForWindowPos(webkit_glue::WebPointToIntPoint(point)); - - if (!result.innerNonSharedNode()) - return; - - page_->inspectorController()->inspect(result.innerNonSharedNode()); - } -} - -WebString WebViewImpl::inspectorSettings() const { - return inspector_settings_; -} - -void WebViewImpl::setInspectorSettings(const WebString& settings) { - inspector_settings_ = settings; -} - -WebDevToolsAgent* WebViewImpl::devToolsAgent() { - return devtools_agent_.get(); -} - -WebAccessibilityObject WebViewImpl::accessibilityObject() { - if (!main_frame()) - return WebAccessibilityObject(); - - WebCore::Document* document = main_frame()->frame()->document(); - - return AccessibilityObjectToWebAccessibilityObject( - document->axObjectCache()->getOrCreate(document->renderer())); -} - -void WebViewImpl::applyAutofillSuggestions( - const WebNode& node, - const WebVector<WebString>& suggestions, - int default_suggestion_index) { - if (!page_.get() || suggestions.isEmpty()) { - HideAutoCompletePopup(); - return; - } - - ASSERT(default_suggestion_index < static_cast<int>(suggestions.size())); - - if (RefPtr<Frame> focused = page_->focusController()->focusedFrame()) { - RefPtr<Document> document = focused->document(); - if (!document.get()) { - HideAutoCompletePopup(); - return; - } - - RefPtr<Node> focused_node = document->focusedNode(); - // If the node for which we queried the autofill suggestions is not the - // focused node, then we have nothing to do. - // TODO(jcampan): also check the carret is at the end and that the text has - // not changed. - if (!focused_node.get() || - focused_node != webkit_glue::WebNodeToNode(node)) { - HideAutoCompletePopup(); - return; - } - - if (!focused_node->hasTagName(WebCore::HTMLNames::inputTag)) { - ASSERT_NOT_REACHED(); - return; - } - - WebCore::HTMLInputElement* input_elem = - static_cast<WebCore::HTMLInputElement*>(focused_node.get()); - - // The first time the autocomplete is shown we'll create the client and the - // popup. - if (!autocomplete_popup_client_.get()) - autocomplete_popup_client_.set(new AutocompletePopupMenuClient(this)); - autocomplete_popup_client_->Init(input_elem, - suggestions, - default_suggestion_index); - if (!autocomplete_popup_.get()) { - autocomplete_popup_ = - WebCore::PopupContainer::create(autocomplete_popup_client_.get(), - kAutocompletePopupSettings); - } - - if (autocomplete_popup_showing_) { - autocomplete_popup_client_->SetSuggestions(suggestions); - RefreshAutofillPopup(); - } else { - autocomplete_popup_->show(focused_node->getRect(), - focused_node->ownerDocument()->view(), 0); - autocomplete_popup_showing_ = true; - } - } -} - -void WebViewImpl::hideAutofillPopup() { - HideAutoCompletePopup(); -} - -// WebView -------------------------------------------------------------------- - -bool WebViewImpl::setDropEffect(bool accept) { - if (drag_target_dispatch_) { - drop_effect_ = accept ? DROP_EFFECT_COPY : DROP_EFFECT_NONE; - return true; - } else { - return false; - } -} - -WebDevToolsAgentImpl* WebViewImpl::GetWebDevToolsAgentImpl() { - return devtools_agent_.get(); -} - -void WebViewImpl::setIsTransparent(bool is_transparent) { - // Set any existing frames to be transparent. - WebCore::Frame* frame = page_->mainFrame(); - while (frame) { - frame->view()->setTransparent(is_transparent); - frame = frame->tree()->traverseNext(); - } - - // Future frames check this to know whether to be transparent. - is_transparent_ = is_transparent; -} - -bool WebViewImpl::isTransparent() const { - return is_transparent_; -} - -void WebViewImpl::setIsActive(bool active) { - if (page() && page()->focusController()) - page()->focusController()->setActive(active); -} - -bool WebViewImpl::isActive() const { - return (page() && page()->focusController()) - ? page()->focusController()->isActive() - : false; -} - -void WebViewImpl::DidCommitLoad(bool* is_new_navigation) { - if (is_new_navigation) - *is_new_navigation = observed_new_navigation_; - -#ifndef NDEBUG - ASSERT(!observed_new_navigation_ || - page_->mainFrame()->loader()->documentLoader() == new_navigation_loader_); - new_navigation_loader_ = NULL; -#endif - observed_new_navigation_ = false; -} - -// static -bool WebViewImpl::NavigationPolicyFromMouseEvent(unsigned short button, - bool ctrl, bool shift, - bool alt, bool meta, - WebNavigationPolicy* policy) { -#if PLATFORM(WIN_OS) || PLATFORM(LINUX) || PLATFORM(FREEBSD) - const bool new_tab_modifier = (button == 1) || ctrl; -#elif PLATFORM(DARWIN) - const bool new_tab_modifier = (button == 1) || meta; -#endif - if (!new_tab_modifier && !shift && !alt) - return false; - - ASSERT(policy); - if (new_tab_modifier) { - if (shift) { - *policy = WebKit::WebNavigationPolicyNewForegroundTab; - } else { - *policy = WebKit::WebNavigationPolicyNewBackgroundTab; - } - } else { - if (shift) { - *policy = WebKit::WebNavigationPolicyNewWindow; - } else { - *policy = WebKit::WebNavigationPolicyDownload; - } - } - return true; -} - -void WebViewImpl::StartDragging(const WebPoint& event_pos, - const WebDragData& drag_data, - WebDragOperationsMask mask) { - if (!client_) - return; - ASSERT(!doing_drag_and_drop_); - doing_drag_and_drop_ = true; - client_->startDragging(event_pos, drag_data, mask); -} - -void WebViewImpl::SetCurrentHistoryItem(WebCore::HistoryItem* item) { - back_forward_list_client_impl_.SetCurrentHistoryItem(item); -} - -WebCore::HistoryItem* WebViewImpl::GetPreviousHistoryItem() { - return back_forward_list_client_impl_.GetPreviousHistoryItem(); -} - -void WebViewImpl::ObserveNewNavigation() { - observed_new_navigation_ = true; -#ifndef NDEBUG - new_navigation_loader_ = page_->mainFrame()->loader()->documentLoader(); -#endif -} - -void WebViewImpl::HideAutoCompletePopup() { - if (autocomplete_popup_showing_) { - autocomplete_popup_->hidePopup(); - AutoCompletePopupDidHide(); - } -} - -void WebViewImpl::AutoCompletePopupDidHide() { - autocomplete_popup_showing_ = false; -} - -void WebViewImpl::SetIgnoreInputEvents(bool new_value) { - ASSERT(ignore_input_events_ != new_value); - ignore_input_events_ = new_value; -} - -#if ENABLE(NOTIFICATIONS) -WebKit::NotificationPresenterImpl* WebViewImpl::GetNotificationPresenter() { - if (!notification_presenter_.isInitialized() && client_) - notification_presenter_.initialize(client_->notificationPresenter()); - return ¬ification_presenter_; -} -#endif - -void WebViewImpl::RefreshAutofillPopup() { - ASSERT(autocomplete_popup_showing_); - - // Hide the popup if it has become empty. - if (autocomplete_popup_client_->listSize() == 0) { - HideAutoCompletePopup(); - return; - } - - IntRect old_bounds = autocomplete_popup_->boundsRect(); - autocomplete_popup_->refresh(); - IntRect new_bounds = autocomplete_popup_->boundsRect(); - // Let's resize the backing window if necessary. - if (old_bounds != new_bounds) { - WebPopupMenuImpl* popup_menu = - static_cast<WebPopupMenuImpl*>(autocomplete_popup_->client()); - popup_menu->client()->setWindowRect( - webkit_glue::IntRectToWebRect(new_bounds)); - } -} - -Node* WebViewImpl::GetFocusedNode() { - Frame* frame = page_->focusController()->focusedFrame(); - if (!frame) - return NULL; - - Document* document = frame->document(); - if (!document) - return NULL; - - return document->focusedNode(); -} - -HitTestResult WebViewImpl::HitTestResultForWindowPos(const IntPoint& pos) { - IntPoint doc_point( - page_->mainFrame()->view()->windowToContents(pos)); - return page_->mainFrame()->eventHandler()-> - hitTestResultAtPoint(doc_point, false); -} - -void WebViewImpl::setTabsToLinks(bool enable) { - tabs_to_links_ = enable; -} - -bool WebViewImpl::tabsToLinks() const { - return tabs_to_links_; -} diff --git a/webkit/glue/webview_impl.h b/webkit/glue/webview_impl.h deleted file mode 100644 index 977b597..0000000 --- a/webkit/glue/webview_impl.h +++ /dev/null @@ -1,401 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef WEBKIT_GLUE_WEBVIEW_IMPL_H_ -#define WEBKIT_GLUE_WEBVIEW_IMPL_H_ - -#include <wtf/OwnPtr.h> -#include <wtf/RefCounted.h> - -#include "webkit/api/public/WebPoint.h" -#include "webkit/api/public/WebSize.h" -#include "webkit/api/public/WebString.h" -#include "webkit/api/public/WebView.h" -#include "webkit/api/src/BackForwardListClientImpl.h" -#include "webkit/api/src/ChromeClientImpl.h" -#include "webkit/api/src/ContextMenuClientImpl.h" -#include "webkit/api/src/DragClientImpl.h" -#include "webkit/api/src/EditorClientImpl.h" -#include "webkit/api/src/InspectorClientImpl.h" -#include "webkit/api/src/NotificationPresenterImpl.h" -#include "webkit/glue/webframe_impl.h" - -namespace WebCore { -class ChromiumDataObject; -class Frame; -class HistoryItem; -class HitTestResult; -class KeyboardEvent; -class Page; -class PlatformKeyboardEvent; -class PopupContainer; -class Range; -class RenderTheme; -class Widget; -} - -namespace WebKit { -class ContextMenuClientImpl; -class WebAccessibilityObject; -class WebKeyboardEvent; -class WebMouseEvent; -class WebMouseWheelEvent; -class WebSettingsImpl; -} - -namespace webkit_glue { -class ImageResourceFetcher; -} - -class AutocompletePopupMenuClient; -class WebHistoryItemImpl; -class WebDevToolsAgentImpl; - -class WebViewImpl : public WebKit::WebView, public RefCounted<WebViewImpl> { - public: - // WebWidget methods: - virtual void close(); - virtual WebKit::WebSize size() { return size_; } - virtual void resize(const WebKit::WebSize& new_size); - virtual void layout(); - virtual void paint(WebKit::WebCanvas* canvas, - const WebKit::WebRect& rect); - virtual bool handleInputEvent(const WebKit::WebInputEvent& input_event); - virtual void mouseCaptureLost(); - virtual void setFocus(bool enable); - virtual bool handleCompositionEvent(WebKit::WebCompositionCommand command, - int cursor_position, - int target_start, - int target_end, - const WebKit::WebString& text); - virtual bool queryCompositionStatus(bool* enabled, - WebKit::WebRect* caret_rect); - virtual void setTextDirection(WebKit::WebTextDirection direction); - - // WebView methods: - virtual void initializeMainFrame(WebKit::WebFrameClient*); - virtual WebKit::WebSettings* settings(); - virtual WebKit::WebString pageEncoding() const; - virtual void setPageEncoding(const WebKit::WebString& encoding); - virtual bool isTransparent() const; - virtual void setIsTransparent(bool value); - virtual bool tabsToLinks() const; - virtual void setTabsToLinks(bool value); - virtual bool tabKeyCyclesThroughElements() const; - virtual void setTabKeyCyclesThroughElements(bool value); - virtual bool isActive() const; - virtual void setIsActive(bool value); - virtual bool dispatchBeforeUnloadEvent(); - virtual void dispatchUnloadEvent(); - virtual WebKit::WebFrame* mainFrame(); - virtual WebKit::WebFrame* findFrameByName( - const WebKit::WebString& name, WebKit::WebFrame* relative_to_frame); - virtual WebKit::WebFrame* focusedFrame(); - virtual void setFocusedFrame(WebKit::WebFrame* frame); - virtual void setInitialFocus(bool reverse); - virtual void clearFocusedNode(); - virtual void zoomIn(bool text_only); - virtual void zoomOut(bool text_only); - virtual void zoomDefault(); - virtual void performMediaPlayerAction( - const WebKit::WebMediaPlayerAction& action, - const WebKit::WebPoint& location); - virtual void copyImageAt(const WebKit::WebPoint& point); - virtual void dragSourceEndedAt( - const WebKit::WebPoint& client_point, - const WebKit::WebPoint& screen_point, - WebKit::WebDragOperation operation); - virtual void dragSourceMovedTo( - const WebKit::WebPoint& client_point, - const WebKit::WebPoint& screen_point); - virtual void dragSourceSystemDragEnded(); - virtual WebKit::WebDragOperation dragTargetDragEnter( - const WebKit::WebDragData& drag_data, int identity, - const WebKit::WebPoint& client_point, - const WebKit::WebPoint& screen_point, - WebKit::WebDragOperationsMask operations_allowed); - virtual WebKit::WebDragOperation dragTargetDragOver( - const WebKit::WebPoint& client_point, - const WebKit::WebPoint& screen_point, - WebKit::WebDragOperationsMask operations_allowed); - virtual void dragTargetDragLeave(); - virtual void dragTargetDrop( - const WebKit::WebPoint& client_point, - const WebKit::WebPoint& screen_point); - virtual int dragIdentity(); - virtual bool setDropEffect(bool accept); - virtual void inspectElementAt(const WebKit::WebPoint& point); - virtual WebKit::WebString inspectorSettings() const; - virtual void setInspectorSettings(const WebKit::WebString& settings); - virtual WebKit::WebDevToolsAgent* devToolsAgent(); - virtual WebKit::WebAccessibilityObject accessibilityObject(); - virtual void applyAutofillSuggestions( - const WebKit::WebNode&, - const WebKit::WebVector<WebKit::WebString>& suggestions, - int defaultSuggestionIndex); - virtual void hideAutofillPopup(); - - // WebViewImpl - - void SetIgnoreInputEvents(bool new_value); - WebDevToolsAgentImpl* GetWebDevToolsAgentImpl(); - - const WebKit::WebPoint& last_mouse_down_point() const { - return last_mouse_down_point_; - } - - WebCore::Frame* GetFocusedWebCoreFrame(); - - // Returns the currently focused Node or NULL if no node has focus. - WebCore::Node* GetFocusedNode(); - - static WebViewImpl* FromPage(WebCore::Page* page); - - WebKit::WebViewClient* client() { - return client_; - } - - // Returns the page object associated with this view. This may be NULL when - // the page is shutting down, but will be valid at all other times. - WebCore::Page* page() const { - return page_.get(); - } - - WebCore::RenderTheme* theme() const; - - // Returns the main frame associated with this view. This may be NULL when - // the page is shutting down, but will be valid at all other times. - WebFrameImpl* main_frame() { - return page_.get() ? WebFrameImpl::FromFrame(page_->mainFrame()) : NULL; - } - - // History related methods: - void SetCurrentHistoryItem(WebCore::HistoryItem* item); - WebCore::HistoryItem* GetPreviousHistoryItem(); - void ObserveNewNavigation(); - - // Event related methods: - void MouseMove(const WebKit::WebMouseEvent& mouse_event); - void MouseLeave(const WebKit::WebMouseEvent& mouse_event); - void MouseDown(const WebKit::WebMouseEvent& mouse_event); - void MouseUp(const WebKit::WebMouseEvent& mouse_event); - void MouseContextMenu(const WebKit::WebMouseEvent& mouse_event); - void MouseDoubleClick(const WebKit::WebMouseEvent& mouse_event); - void MouseWheel(const WebKit::WebMouseWheelEvent& wheel_event); - bool KeyEvent(const WebKit::WebKeyboardEvent& key_event); - bool CharEvent(const WebKit::WebKeyboardEvent& key_event); - - // Handles context menu events orignated via the the keyboard. These - // include the VK_APPS virtual key and the Shift+F10 combine. - // Code is based on the Webkit function - // bool WebView::handleContextMenuEvent(WPARAM wParam, LPARAM lParam) in - // webkit\webkit\win\WebView.cpp. The only significant change in this - // function is the code to convert from a Keyboard event to the Right - // Mouse button down event. - bool SendContextMenuEvent(const WebKit::WebKeyboardEvent& event); - - // Notifies the WebView that a load has been committed. - // is_new_navigation will be true if a new session history item should be - // created for that load. - void DidCommitLoad(bool* is_new_navigation); - - bool context_menu_allowed() const { - return context_menu_allowed_; - } - - // Set the disposition for how this webview is to be initially shown. - void set_initial_navigation_policy(WebKit::WebNavigationPolicy policy) { - initial_navigation_policy_ = policy; - } - WebKit::WebNavigationPolicy initial_navigation_policy() const { - return initial_navigation_policy_; - } - - // Determines whether a page should e.g. be opened in a background tab. - // Returns false if it has no opinion, in which case it doesn't set *policy. - static bool NavigationPolicyFromMouseEvent( - unsigned short button, - bool ctrl, - bool shift, - bool alt, - bool meta, - WebKit::WebNavigationPolicy* policy); - - // Start a system drag and drop operation. - void StartDragging( - const WebKit::WebPoint& event_pos, - const WebKit::WebDragData& drag_data, - WebKit::WebDragOperationsMask drag_source_operation_mask); - - // Hides the autocomplete popup if it is showing. - void HideAutoCompletePopup(); - void AutoCompletePopupDidHide(); - -#if ENABLE(NOTIFICATIONS) - // Returns the provider of desktop notifications. - WebKit::NotificationPresenterImpl* GetNotificationPresenter(); -#endif - - // Tries to scroll a frame or any parent of a frame. Returns true if the view - // was scrolled. - bool PropagateScroll(WebCore::ScrollDirection scroll_direction, - WebCore::ScrollGranularity scroll_granularity); - - protected: - friend class WebKit::WebView; // So WebView::Create can call our constructor - friend class WTF::RefCounted<WebViewImpl>; - - WebViewImpl(WebKit::WebViewClient* client); - ~WebViewImpl(); - - void ModifySelection(uint32 message, - WebCore::Frame* frame, - const WebCore::PlatformKeyboardEvent& e); - - WebKit::WebViewClient* client_; - - WebKit::BackForwardListClientImpl back_forward_list_client_impl_; - WebKit::ChromeClientImpl chrome_client_impl_; - WebKit::ContextMenuClientImpl context_menu_client_impl_; - WebKit::DragClientImpl drag_client_impl_; - WebKit::EditorClientImpl editor_client_impl_; - WebKit::InspectorClientImpl inspector_client_impl_; - - WebKit::WebSize size_; - - WebKit::WebPoint last_mouse_position_; - OwnPtr<WebCore::Page> page_; - - // This flag is set when a new navigation is detected. It is used to satisfy - // the corresponding argument to WebFrameClient::didCommitProvisionalLoad. - bool observed_new_navigation_; -#ifndef NDEBUG - // Used to assert that the new navigation we observed is the same navigation - // when we make use of observed_new_navigation_. - const WebCore::DocumentLoader* new_navigation_loader_; -#endif - - // An object that can be used to manipulate page_->settings() without linking - // against WebCore. This is lazily allocated the first time GetWebSettings() - // is called. - OwnPtr<WebKit::WebSettingsImpl> web_settings_; - - // A copy of the web drop data object we received from the browser. - RefPtr<WebCore::ChromiumDataObject> current_drag_data_; - - private: - // Returns true if the event was actually processed. - bool KeyEventDefault(const WebKit::WebKeyboardEvent& event); - - // Returns true if the autocomple has consumed the event. - bool AutocompleteHandleKeyEvent(const WebKit::WebKeyboardEvent& event); - - // Repaints the autofill popup. Should be called when the suggestions have - // changed. Note that this should only be called when the autofill popup is - // showing. - void RefreshAutofillPopup(); - - // Returns true if the view was scrolled. - bool ScrollViewWithKeyboard(int key_code, int modifiers); - - // Converts |pos| from window coordinates to contents coordinates and gets - // the HitTestResult for it. - WebCore::HitTestResult HitTestResultForWindowPos( - const WebCore::IntPoint& pos); - - // The point relative to the client area where the mouse was last pressed - // down. This is used by the drag client to determine what was under the - // mouse when the drag was initiated. We need to track this here in - // WebViewImpl since DragClient::startDrag does not pass the position the - // mouse was at when the drag was initiated, only the current point, which - // can be misleading as it is usually not over the element the user actually - // dragged by the time a drag is initiated. - WebKit::WebPoint last_mouse_down_point_; - - // Keeps track of the current text zoom level. 0 means no zoom, positive - // values mean larger text, negative numbers mean smaller. - int zoom_level_; - - bool context_menu_allowed_; - - bool doing_drag_and_drop_; - - bool ignore_input_events_; - - // Webkit expects keyPress events to be suppressed if the associated keyDown - // event was handled. Safari implements this behavior by peeking out the - // associated WM_CHAR event if the keydown was handled. We emulate - // this behavior by setting this flag if the keyDown was handled. - bool suppress_next_keypress_event_; - - // The policy for how this webview is to be initially shown. - WebKit::WebNavigationPolicy initial_navigation_policy_; - - // Represents whether or not this object should process incoming IME events. - bool ime_accept_events_; - - // True while dispatching system drag and drop events to drag/drop targets - // within this WebView. - bool drag_target_dispatch_; - - // Valid when drag_target_dispatch_ is true; the identity of the drag data - // copied from the WebDropData object sent from the browser process. - int32 drag_identity_; - - // Valid when drag_target_dispatch_ is true. Used to override the default - // browser drop effect with the effects "none" or "copy". - enum DragTargetDropEffect { - DROP_EFFECT_DEFAULT = -1, - DROP_EFFECT_NONE, - DROP_EFFECT_COPY - } drop_effect_; - - // The available drag operations (copy, move link...) allowed by the source. - WebKit::WebDragOperation operations_allowed_; - - // The current drag operation as negotiated by the source and destination. - // When not equal to DragOperationNone, the drag data can be dropped onto the - // current drop target in this WebView (the drop target can accept the drop). - WebKit::WebDragOperation drag_operation_; - - // The autocomplete popup. Kept around and reused every-time new suggestions - // should be shown. - RefPtr<WebCore::PopupContainer> autocomplete_popup_; - - // Whether the autocomplete popup is currently showing. - bool autocomplete_popup_showing_; - - // The autocomplete client. - OwnPtr<AutocompletePopupMenuClient> autocomplete_popup_client_; - - OwnPtr<WebDevToolsAgentImpl> devtools_agent_; - - // Whether the webview is rendering transparently. - bool is_transparent_; - - // Whether the user can press tab to focus links. - bool tabs_to_links_; - - // Inspector settings. - WebKit::WebString inspector_settings_; - -#if ENABLE(NOTIFICATIONS) - // The provider of desktop notifications; - WebKit::NotificationPresenterImpl notification_presenter_; -#endif - - // HACK: current_input_event is for ChromeClientImpl::show(), until we can fix - // WebKit to pass enough information up into ChromeClient::show() so we can - // decide if the window.open event was caused by a middle-mouse click - public: - static const WebKit::WebInputEvent* current_input_event() { - return g_current_input_event; - } - private: - static const WebKit::WebInputEvent* g_current_input_event; - - DISALLOW_COPY_AND_ASSIGN(WebViewImpl); -}; - -#endif // WEBKIT_GLUE_WEBVIEW_IMPL_H_ diff --git a/webkit/webkit.gyp b/webkit/webkit.gyp index 578fbc9..39d8fa3 100644 --- a/webkit/webkit.gyp +++ b/webkit/webkit.gyp @@ -172,6 +172,8 @@ 'api/public/win/WebScreenInfoFactory.h', 'api/src/ApplicationCacheHost.cpp', 'api/src/AssertMatchingEnums.cpp', + 'api/src/AutocompletePopupMenuClient.cpp', + 'api/src/AutocompletePopupMenuClient.h', 'api/src/BackForwardListClientImpl.cpp', 'api/src/BackForwardListClientImpl.h', 'api/src/ChromeClientImpl.cpp', @@ -187,6 +189,9 @@ 'api/src/DragClientImpl.h', 'api/src/EditorClientImpl.cpp', 'api/src/EditorClientImpl.h', + 'api/src/FrameLoaderClientImpl.cpp', + 'api/src/FrameLoaderClientImpl.h', + 'api/src/EmptyWebFrameClientImpl.h', 'api/src/gtk/WebFontInfo.cpp', 'api/src/gtk/WebFontInfo.h', 'api/src/gtk/WebInputEventFactory.cpp', @@ -231,6 +236,8 @@ 'api/src/WebFileChooserCompletionImpl.h', 'api/src/WebFontCache.cpp', 'api/src/WebForm.cpp', + 'api/src/WebFrameImpl.cpp', + 'api/src/WebFrameImpl.h', 'api/src/WebHistoryItem.cpp', 'api/src/WebHTTPBody.cpp', 'api/src/WebImageCG.cpp', @@ -271,6 +278,8 @@ 'api/src/WebURLResponse.cpp', 'api/src/WebURLResponsePrivate.h', 'api/src/WebURLError.cpp', + 'api/src/WebViewImpl.cpp', + 'api/src/WebViewImpl.h', 'api/src/WebWorkerClientImpl.cpp', 'api/src/WebWorkerClientImpl.h', 'api/src/WebWorkerImpl.cpp', @@ -645,10 +654,6 @@ 'glue/webdropdata.cc', 'glue/webdropdata_win.cc', 'glue/webdropdata.h', - 'glue/webframe_impl.cc', - 'glue/webframe_impl.h', - 'glue/webframeloaderclient_impl.cc', - 'glue/webframeloaderclient_impl.h', 'glue/webkit_glue.cc', 'glue/webkit_glue.h', 'glue/webkitclient_impl.cc', @@ -672,8 +677,6 @@ 'glue/webthemeengine_impl_win.cc', 'glue/weburlloader_impl.cc', 'glue/weburlloader_impl.h', - 'glue/webview_impl.cc', - 'glue/webview_impl.h', 'glue/window_open_disposition.h', 'glue/window_open_disposition.cc', |