diff options
author | amanda@chromium.org <amanda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-09-15 19:54:42 +0000 |
---|---|---|
committer | amanda@chromium.org <amanda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-09-15 19:54:42 +0000 |
commit | faf19bbf27a42842d4d2bc9a1e689dfcac3bd675 (patch) | |
tree | ffd7eb58cac407e6f66595f5201fb4b394260d17 /webkit/tools/test_shell | |
parent | 8dd3dddd1cd80d28cc8237a5dbcf9f60e3c24566 (diff) | |
download | chromium_src-faf19bbf27a42842d4d2bc9a1e689dfcac3bd675.zip chromium_src-faf19bbf27a42842d4d2bc9a1e689dfcac3bd675.tar.gz chromium_src-faf19bbf27a42842d4d2bc9a1e689dfcac3bd675.tar.bz2 |
Add test shell WebView and WebWidget host classes. This are stopgaps and
are subject to change as the rest of the rendering and event handling paths
come together.
Review URL: http://codereview.chromium.org/3062
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@2230 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/tools/test_shell')
-rw-r--r-- | webkit/tools/test_shell/mac/Info.plist | 2 | ||||
-rw-r--r-- | webkit/tools/test_shell/mac/TestShell.xcodeproj/project.pbxproj | 6 | ||||
-rw-r--r-- | webkit/tools/test_shell/mac/test_webview_delegate.mm | 838 | ||||
-rw-r--r-- | webkit/tools/test_shell/mac/webview_host.mm | 42 | ||||
-rw-r--r-- | webkit/tools/test_shell/mac/webwidget_host.mm | 260 |
5 files changed, 1144 insertions, 4 deletions
diff --git a/webkit/tools/test_shell/mac/Info.plist b/webkit/tools/test_shell/mac/Info.plist index d9a2cdb..7747ba0 100644 --- a/webkit/tools/test_shell/mac/Info.plist +++ b/webkit/tools/test_shell/mac/Info.plist @@ -9,7 +9,7 @@ <key>CFBundleIconFile</key> <string></string> <key>CFBundleIdentifier</key> - <string>com.yourcompany.TestShell</string> + <string>com.google.TestShell</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundleName</key> diff --git a/webkit/tools/test_shell/mac/TestShell.xcodeproj/project.pbxproj b/webkit/tools/test_shell/mac/TestShell.xcodeproj/project.pbxproj index e72b12d..b5f988b 100644 --- a/webkit/tools/test_shell/mac/TestShell.xcodeproj/project.pbxproj +++ b/webkit/tools/test_shell/mac/TestShell.xcodeproj/project.pbxproj @@ -347,11 +347,11 @@ AB8A78520DC553A8005C27B8 /* event_sending_controller.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = event_sending_controller.cc; sourceTree = "<group>"; }; AB8A78540DC553BC005C27B8 /* node_leak_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = node_leak_test.cc; sourceTree = "<group>"; }; AB8A78560DC553C7005C27B8 /* test_shell_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = test_shell_test.cc; sourceTree = "<group>"; }; - AB8A78580DC553D7005C27B8 /* test_webview_delegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = test_webview_delegate.mm; sourceTree = "<group>"; }; + AB8A78580DC553D7005C27B8 /* test_webview_delegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = test_webview_delegate.mm; path = mac/test_webview_delegate.mm; sourceTree = "<group>"; }; AB8A78590DC553D7005C27B8 /* test_webview_delegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = test_webview_delegate.h; sourceTree = "<group>"; }; AB8A785B0DC553E4005C27B8 /* text_input_controller.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = text_input_controller.cc; sourceTree = "<group>"; }; AB8A785C0DC553E4005C27B8 /* text_input_controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = text_input_controller.h; sourceTree = "<group>"; }; - AB8A785E0DC553EE005C27B8 /* webview_host.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = webview_host.mm; sourceTree = "<group>"; }; + AB8A785E0DC553EE005C27B8 /* webview_host.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = webview_host.mm; path = mac/webview_host.mm; sourceTree = "<group>"; }; AB8A78600DC553EE005C27B8 /* webview_host.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = webview_host.h; sourceTree = "<group>"; }; AB8A786E0DC5544D005C27B8 /* test_shell_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = test_shell_test.h; sourceTree = "<group>"; }; ABA65EFD0DD50BFF003A4FC8 /* test_shell_webview.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = test_shell_webview.h; sourceTree = "<group>"; }; @@ -362,7 +362,7 @@ ABC8C4180DC7F7D000B59C21 /* zlib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = zlib.xcodeproj; path = third_party/zlib/zlib.xcodeproj; sourceTree = "<group>"; }; ABCF253B0DB8436B00099567 /* test_shell_switches.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = test_shell_switches.h; sourceTree = "<group>"; }; ABCF253C0DB8436B00099567 /* test_shell_switches.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = test_shell_switches.cc; sourceTree = "<group>"; }; - ABD16F380DC6A73B0013D3AA /* webwidget_host.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = webwidget_host.mm; sourceTree = "<group>"; }; + ABD16F380DC6A73B0013D3AA /* webwidget_host.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = webwidget_host.mm; path = mac/webwidget_host.mm; sourceTree = "<group>"; }; ABD16F390DC6A73B0013D3AA /* webwidget_host.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = webwidget_host.h; sourceTree = "<group>"; }; ABD16F700DC6CBDF0013D3AA /* base.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = base.xcodeproj; path = base/base.xcodeproj; sourceTree = "<group>"; }; E450637C0E4100740025A81A /* test_shell_request_context.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = test_shell_request_context.h; sourceTree = "<group>"; }; diff --git a/webkit/tools/test_shell/mac/test_webview_delegate.mm b/webkit/tools/test_shell/mac/test_webview_delegate.mm new file mode 100644 index 0000000..746835e --- /dev/null +++ b/webkit/tools/test_shell/mac/test_webview_delegate.mm @@ -0,0 +1,838 @@ +// Copyright (c) 2008 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 "webkit/tools/test_shell/test_webview_delegate.h" + +#import <Cocoa/Cocoa.h> +#include "base/gfx/point.h" +#include "base/string_util.h" +#include "net/base/net_errors.h" +#include "chrome/common/page_transition_types.h" +#include "webkit/glue/webdatasource.h" +#include "webkit/glue/webdropdata.h" +#include "webkit/glue/weberror.h" +#include "webkit/glue/webframe.h" +#include "webkit/glue/webpreferences.h" +#include "webkit/glue/weburlrequest.h" +#include "webkit/glue/webkit_glue.h" +#include "webkit/glue/webview.h" +// #include "webkit/glue/plugins/plugin_list.h" +// #include "webkit/glue/plugins/webplugin_delegate_impl.h" +#include "webkit/glue/window_open_disposition.h" +// #include "webkit/tools/test_shell/drag_delegate.h" +// #include "webkit/tools/test_shell/drop_delegate.h" +#include "webkit/tools/test_shell/test_navigation_controller.h" +#include "webkit/tools/test_shell/test_shell.h" + + +static int32 next_page_id_ = 1; + +// WebViewDelegate ----------------------------------------------------------- + +TestWebViewDelegate::~TestWebViewDelegate() { +} + +WebView* TestWebViewDelegate::CreateWebView(WebView* webview, + bool user_gesture) { + return shell_->CreateWebView(webview); +} + +WebWidget* TestWebViewDelegate::CreatePopupWidget(WebView* webview) { + return shell_->CreatePopupWidget(webview); +} + +WebPluginDelegate* TestWebViewDelegate::CreatePluginDelegate( + WebView* webview, + const GURL& url, + const std::string& mime_type, + const std::string& clsid, + std::string* actual_mime_type) { + // TODO(awalker): once Mac plugins are working, enable this code to + // connect up the web plugin delegate for a plugin. +#if 0 + WindowHandle WindowHandle = GetContainingWindow(webview); + if (!WindowHandle) + return NULL; + + bool allow_wildcard = true; + WebPluginInfo info; + if (!NPAPI::PluginList::Singleton()->GetPluginInfo(url, mime_type, clsid, + allow_wildcard, &info, + actual_mime_type)) + return NULL; + + if (actual_mime_type && !actual_mime_type->empty()) + return WebPluginDelegateImpl::Create(info.file, *actual_mime_type, + WindowHandle); + else + return WebPluginDelegateImpl::Create(info.file, mime_type, WindowHandle); +#else + return NULL; +#endif +} + +void TestWebViewDelegate::OpenURL(WebView* webview, const GURL& url, + WindowOpenDisposition disposition) { + DCHECK_NE(disposition, CURRENT_TAB); // No code for this + if (disposition == SUPPRESS_OPEN) + return; + TestShell* shell = NULL; + if (TestShell::CreateNewWindow(UTF8ToWide(url.spec()), &shell)) + shell->Show(shell->webView(), disposition); +} + +void TestWebViewDelegate::DidStartLoading(WebView* webview) { + if (page_is_loading_) { + LOG(ERROR) << "DidStartLoading called while loading"; + return; + } + page_is_loading_ = true; +} + +void TestWebViewDelegate::DidStopLoading(WebView* webview) { + if (!page_is_loading_) { + LOG(ERROR) << "DidStopLoading called while not loading"; + return; + } + page_is_loading_ = false; +} + +void TestWebViewDelegate::WindowObjectCleared(WebFrame* webframe) { + shell_->BindJSObjectsToWindow(webframe); +} + +WindowOpenDisposition TestWebViewDelegate::DispositionForNavigationAction( + WebView* webview, + WebFrame* frame, + const WebRequest* request, + WebNavigationType type, + WindowOpenDisposition disposition, + bool is_redirect) { + if (is_custom_policy_delegate_) { + std::wstring frame_name = frame->GetName(); + printf("Policy delegate: attempt to load %s\n", + request->GetURL().spec().c_str()); + return IGNORE_ACTION; + } else { + return static_cast<WindowOpenDisposition>( + WebViewDelegate::DispositionForNavigationAction(webview, frame, request, + type, disposition, + is_redirect)); + } +} + +void TestWebViewDelegate::SetCustomPolicyDelegate(bool isCustom) { + is_custom_policy_delegate_ = isCustom; +} + +void TestWebViewDelegate::AssignIdentifierToRequest(WebView* webview, + uint32 identifier, + const WebRequest& request) { + if (shell_->ShouldDumpResourceLoadCallbacks()) { + resource_identifier_map_[identifier] = request.GetURL().spec(); + } +} + +std::string TestWebViewDelegate::GetResourceDescription(uint32 identifier) { + ResourceMap::iterator it = resource_identifier_map_.find(identifier); + return it != resource_identifier_map_.end() ? it->second : "<unknown>"; +} + +void TestWebViewDelegate::WillSendRequest(WebView* webview, + uint32 identifier, + WebRequest* request) { + std::string request_url = request->GetURL().spec(); + + if (shell_->ShouldDumpResourceLoadCallbacks()) { + printf("%s - willSendRequest <WebRequest URL \"%s\">\n", + GetResourceDescription(identifier).c_str(), + request_url.c_str()); + } + + // Set the new substituted URL. + request->SetURL(GURL(TestShell::RewriteLocalUrl(request_url))); +} + +void TestWebViewDelegate::DidFinishLoading(WebView* webview, + uint32 identifier) { + if (shell_->ShouldDumpResourceLoadCallbacks()) { + printf("%s - didFinishLoading\n", + GetResourceDescription(identifier).c_str()); + } + + resource_identifier_map_.erase(identifier); +} + +void TestWebViewDelegate::DidFailLoadingWithError(WebView* webview, + uint32 identifier, + const WebError& error) { + if (shell_->ShouldDumpResourceLoadCallbacks()) { + printf("%s - didFailLoadingWithError <WebError code %d," + " failing URL \"%s\">\n", + GetResourceDescription(identifier).c_str(), + error.GetErrorCode(), + error.GetFailedURL().spec().c_str()); + } + + resource_identifier_map_.erase(identifier); +} + +void TestWebViewDelegate::DidStartProvisionalLoadForFrame( + WebView* webview, + WebFrame* frame, + NavigationGesture gesture) { + if (shell_->ShouldDumpFrameLoadCallbacks()) { + printf("%S - didStartProvisionalLoadForFrame\n", + GetFrameDescription(frame).c_str()); + } + + if (!top_loading_frame_) { + top_loading_frame_ = frame; + } + UpdateAddressBar(webview); +} + +void TestWebViewDelegate::DidReceiveServerRedirectForProvisionalLoadForFrame( + WebView* webview, + WebFrame* frame) { + if (shell_->ShouldDumpFrameLoadCallbacks()) { + printf("%S - didReceiveServerRedirectForProvisionalLoadForFrame\n", + GetFrameDescription(frame).c_str()); + } + + UpdateAddressBar(webview); +} + +void TestWebViewDelegate::DidFailProvisionalLoadWithError( + WebView* webview, + const WebError& error, + WebFrame* frame) { + if (shell_->ShouldDumpFrameLoadCallbacks()) { + printf("%S - didFailProvisionalLoadWithError\n", + GetFrameDescription(frame).c_str()); + } + + if (page_is_loading_) + DidStopLoading(webview); + LocationChangeDone(frame->GetProvisionalDataSource()); + + // Don't display an error page if we're running layout tests, because + // DumpRenderTree doesn't. + if (!shell_->interactive()) + return; + + // Don't display an error page if this is simply a cancelled load. Aside + // from being dumb, WebCore doesn't expect it and it will cause a crash. + if (error.GetErrorCode() == net::ERR_ABORTED) + return; + + const WebRequest& failed_request = + frame->GetProvisionalDataSource()->GetRequest(); + TestShellExtraRequestData* extra_data = + static_cast<TestShellExtraRequestData*>(failed_request.GetExtraData()); + bool replace = extra_data && extra_data->pending_page_id != -1; + + scoped_ptr<WebRequest> request(failed_request.Clone()); + request->SetURL(GURL("testshell-error:")); + + std::string error_text = + StringPrintf("Error loading url: %d", error.GetErrorCode()); + + frame->LoadAlternateHTMLString(request.get(), error_text, + error.GetFailedURL(), replace); +} + +void TestWebViewDelegate::DidCommitLoadForFrame(WebView* webview, + WebFrame* frame, + bool is_new_navigation) { + if (shell_->ShouldDumpFrameLoadCallbacks()) { + printf("%S - didCommitLoadForFrame\n", + GetFrameDescription(frame).c_str()); + } + + UpdateForCommittedLoad(frame, is_new_navigation); +} + +void TestWebViewDelegate::DidReceiveTitle(WebView* webview, + const std::wstring& title, + WebFrame* frame) { + if (shell_->ShouldDumpFrameLoadCallbacks()) { + printf("%S - didReceiveTitle\n", + GetFrameDescription(frame).c_str()); + } + + if (shell_->ShouldDumpTitleChanges()) { + printf("TITLE CHANGED: %S\n", title.c_str()); + } + [[shell_->webViewHost()->window_handle() window] + setTitle:[NSString stringWithUTF8String:WideToUTF8(title).c_str()]]; +} + +void TestWebViewDelegate::DidFinishLoadForFrame(WebView* webview, + WebFrame* frame) { + if (shell_->ShouldDumpFrameLoadCallbacks()) { + printf("%S - didFinishLoadForFrame\n", + GetFrameDescription(frame).c_str()); + } + + UpdateAddressBar(webview); + LocationChangeDone(frame->GetDataSource()); +} + +void TestWebViewDelegate::DidFailLoadWithError(WebView* webview, + const WebError& error, + WebFrame* frame) { + if (shell_->ShouldDumpFrameLoadCallbacks()) { + printf("%S - didFailLoadWithError\n", + GetFrameDescription(frame).c_str()); + } + + if (page_is_loading_) + DidStopLoading(webview); + LocationChangeDone(frame->GetDataSource()); +} + +void TestWebViewDelegate::DidFinishDocumentLoadForFrame(WebView* webview, + WebFrame* frame) { + if (shell_->ShouldDumpFrameLoadCallbacks()) { + printf("%S - didFinishDocumentLoadForFrame\n", + GetFrameDescription(frame).c_str()); + } +} + +void TestWebViewDelegate::DidHandleOnloadEventsForFrame(WebView* webview, + WebFrame* frame) { + if (shell_->ShouldDumpFrameLoadCallbacks()) { + printf("%S - didHandleOnloadEventsForFrame\n", + GetFrameDescription(frame).c_str()); + } +} + +void TestWebViewDelegate::DidChangeLocationWithinPageForFrame( + WebView* webview, WebFrame* frame, bool is_new_navigation) { + if (shell_->ShouldDumpFrameLoadCallbacks()) { + printf("%S - didChangeLocationWithinPageForFrame\n", + GetFrameDescription(frame).c_str()); + } + + UpdateForCommittedLoad(frame, is_new_navigation); +} + +void TestWebViewDelegate::DidReceiveIconForFrame(WebView* webview, + WebFrame* frame) { + if (shell_->ShouldDumpFrameLoadCallbacks()) { + printf("%S - didReceiveIconForFrame\n", + GetFrameDescription(frame).c_str()); + } +} + +void TestWebViewDelegate::WillPerformClientRedirect( + WebView* webview, WebFrame* frame, const std::wstring& dest_url, + unsigned int delay_seconds, unsigned int fire_date) { + if (shell_->ShouldDumpFrameLoadCallbacks()) { + // TODO: prettyprint the url? + printf("%S - willPerformClientRedirectToURL: %S\n", + GetFrameDescription(frame).c_str(), dest_url.c_str()); + } +} + +void TestWebViewDelegate::DidCancelClientRedirect(WebView* webview, + WebFrame* frame) { + if (shell_->ShouldDumpFrameLoadCallbacks()) { + printf("%S - didCancelClientRedirectForFrame\n", + GetFrameDescription(frame).c_str()); + } +} + +void TestWebViewDelegate::AddMessageToConsole(WebView* webview, + const std::wstring& message, + unsigned int line_no, + const std::wstring& source_id) { + if (shell_->interactive()) { + logging::LogMessage("CONSOLE", 0).stream() << "\"" + << message.c_str() + << ",\" source: " + << source_id.c_str() + << "(" + << line_no + << ")"; + } else { + // This matches win DumpRenderTree's UIDelegate.cpp. + std::wstring new_message = message; + if (!message.empty()) { + new_message = message; + size_t file_protocol = new_message.find(L"file://"); + if (file_protocol != std::wstring::npos) { + new_message = new_message.substr(0, file_protocol) + new_message; + // UrlSuitableForTestResult(new_message); + } + } + + std::string utf8 = WideToUTF8(new_message); + printf("CONSOLE MESSAGE: line %d: %s\n", line_no, utf8.c_str()); + } +} + +void TestWebViewDelegate::RunJavaScriptAlert(WebView* webview, + const std::wstring& message) { + if (shell_->interactive()) { + NSString *text = + [NSString stringWithUTF8String:WideToUTF8(message).c_str()]; + NSAlert *alert = [NSAlert alertWithMessageText:@"JavaScript Alert" + defaultButton:@"OK" + alternateButton:nil + otherButton:nil + informativeTextWithFormat:text]; + [alert runModal]; + } else { + std::string utf8 = WideToUTF8(message); + printf("ALERT: %s\n", utf8.c_str()); + } +} + +bool TestWebViewDelegate::RunJavaScriptConfirm(WebView* webview, + const std::wstring& message) { + if (!shell_->interactive()) { + // When running tests, write to stdout. + std::string utf8 = WideToUTF8(message); + printf("CONFIRM: %s\n", utf8.c_str()); + return true; + } + return false; +} + +bool TestWebViewDelegate::RunJavaScriptPrompt(WebView* webview, + const std::wstring& message, const std::wstring& default_value, + std::wstring* result) { + if (!shell_->interactive()) { + // When running tests, write to stdout. + std::string utf8_message = WideToUTF8(message); + std::string utf8_default_value = WideToUTF8(default_value); + printf("PROMPT: %s, default text: %s\n", utf8_message.c_str(), + utf8_default_value.c_str()); + return true; + } + return false; +} + +void TestWebViewDelegate::StartDragging(WebView* webview, + const WebDropData& drop_data) { +#if 0 +// TODO(pinkerton): fill in drag&drop code later. + if (!drag_delegate_) + drag_delegate_ = new TestDragDelegate(shell_->webViewWnd(), + shell_->webView()); + if (webkit_glue::IsLayoutTestMode()) { + if (shell_->layout_test_controller()->ShouldAddFileToPasteboard()) { + // Add a file called DRTFakeFile to the drag&drop clipboard. + // AddDRTFakeFileToDataObject(drop_data.data_object); + } + + // When running a test, we need to fake a drag drop operation otherwise + // Windows waits for real mouse events to know when the drag is over. + EventSendingController::DoDragDrop(drop_data.data_object); + } else { + // Process a real drag and drop + } + webview->DragSourceSystemDragEnded(); +#endif +} + +void TestWebViewDelegate::ShowContextMenu(WebView* webview, + ContextNode::Type type, + int x, + int y, + const GURL& link_url, + const GURL& image_url, + const GURL& page_url, + const GURL& frame_url, + const std::wstring& selection_text, + const std::wstring& misspelled_word, + int edit_flags) { + CapturedContextMenuEvent context(type, x, y); + captured_context_menu_events_.push_back(context); +} + +// The output from these methods in non-interactive mode should match that +// expected by the layout tests. See EditingDelegate.m in DumpRenderTree. +bool TestWebViewDelegate::ShouldBeginEditing(WebView* webview, + std::wstring range) { + if (shell_->ShouldDumpEditingCallbacks()) { + std::string utf8 = WideToUTF8(range); + printf("EDITING DELEGATE: shouldBeginEditingInDOMRange:%s\n", + utf8.c_str()); + } + return shell_->AcceptsEditing(); +} + +bool TestWebViewDelegate::ShouldEndEditing(WebView* webview, + std::wstring range) { + if (shell_->ShouldDumpEditingCallbacks()) { + std::string utf8 = WideToUTF8(range); + printf("EDITING DELEGATE: shouldEndEditingInDOMRange:%s\n", + utf8.c_str()); + } + return shell_->AcceptsEditing(); +} + +bool TestWebViewDelegate::ShouldInsertNode(WebView* webview, + std::wstring node, + std::wstring range, + std::wstring action) { + if (shell_->ShouldDumpEditingCallbacks()) { + std::string utf8_node = WideToUTF8(node); + std::string utf8_range = WideToUTF8(range); + std::string utf8_action = WideToUTF8(action); + printf("EDITING DELEGATE: shouldInsertNode:%s " + "replacingDOMRange:%s givenAction:%s\n", + utf8_node.c_str(), utf8_range.c_str(), utf8_action.c_str()); + } + return shell_->AcceptsEditing(); +} + +bool TestWebViewDelegate::ShouldInsertText(WebView* webview, + std::wstring text, + std::wstring range, + std::wstring action) { + if (shell_->ShouldDumpEditingCallbacks()) { + std::string utf8_text = WideToUTF8(text); + std::string utf8_range = WideToUTF8(range); + std::string utf8_action = WideToUTF8(action); + printf("EDITING DELEGATE: shouldInsertText:%s " + "replacingDOMRange:%s givenAction:%s\n", + utf8_text.c_str(), utf8_range.c_str(), utf8_action.c_str()); + } + return shell_->AcceptsEditing(); +} + +bool TestWebViewDelegate::ShouldChangeSelectedRange(WebView* webview, + std::wstring fromRange, + std::wstring toRange, + std::wstring affinity, + bool stillSelecting) { + if (shell_->ShouldDumpEditingCallbacks()) { + std::string utf8_from = WideToUTF8(fromRange); + std::string utf8_to = WideToUTF8(toRange); + std::string utf8_affinity = WideToUTF8(affinity); + printf("EDITING DELEGATE: shouldChangeSelectedDOMRange:%s " + "toDOMRange:%s affinity:%s stillSelecting:%s\n", + utf8_from.c_str(), + utf8_to.c_str(), + utf8_affinity.c_str(), + (stillSelecting ? "TRUE" : "FALSE")); + } + return shell_->AcceptsEditing(); +} + +bool TestWebViewDelegate::ShouldDeleteRange(WebView* webview, + std::wstring range) { + if (shell_->ShouldDumpEditingCallbacks()) { + std::string utf8 = WideToUTF8(range); + printf("EDITING DELEGATE: shouldDeleteDOMRange:%s\n", utf8.c_str()); + } + return shell_->AcceptsEditing(); +} + +bool TestWebViewDelegate::ShouldApplyStyle(WebView* webview, + std::wstring style, + std::wstring range) { + if (shell_->ShouldDumpEditingCallbacks()) { + std::string utf8_style = WideToUTF8(style); + std::string utf8_range = WideToUTF8(range); + printf("EDITING DELEGATE: shouldApplyStyle:%s toElementsInDOMRange:%s\n", + utf8_style.c_str(), utf8_range.c_str()); + } + return shell_->AcceptsEditing(); +} + +bool TestWebViewDelegate::SmartInsertDeleteEnabled() { + return true; +} + +void TestWebViewDelegate::DidBeginEditing() { + if (shell_->ShouldDumpEditingCallbacks()) { + printf("EDITING DELEGATE: " + "webViewDidBeginEditing:WebViewDidBeginEditingNotification\n"); + } +} + +void TestWebViewDelegate::DidChangeSelection() { + if (shell_->ShouldDumpEditingCallbacks()) { + printf("EDITING DELEGATE: " + "webViewDidChangeSelection:WebViewDidChangeSelectionNotification\n"); + } +} + +void TestWebViewDelegate::DidChangeContents() { + if (shell_->ShouldDumpEditingCallbacks()) { + printf("EDITING DELEGATE: " + "webViewDidChange:WebViewDidChangeNotification\n"); + } +} + +void TestWebViewDelegate::DidEndEditing() { + if (shell_->ShouldDumpEditingCallbacks()) { + printf("EDITING DELEGATE: " + "webViewDidEndEditing:WebViewDidEndEditingNotification\n"); + } +} + +WebHistoryItem* TestWebViewDelegate::GetHistoryEntryAtOffset(int offset) { + TestNavigationEntry* entry = static_cast<TestNavigationEntry*>( + shell_->navigation_controller()->GetEntryAtOffset(offset)); + if (!entry) + return NULL; + + return entry->GetHistoryItem(); +} + +void TestWebViewDelegate::GoToEntryAtOffsetAsync(int offset) { + shell_->navigation_controller()->GoToOffset(offset); +} + +int TestWebViewDelegate::GetHistoryBackListCount() { + int current_index = + shell_->navigation_controller()->GetLastCommittedEntryIndex(); + return current_index; +} + +int TestWebViewDelegate::GetHistoryForwardListCount() { + int current_index = + shell_->navigation_controller()->GetLastCommittedEntryIndex(); + return shell_->navigation_controller()->GetEntryCount() - current_index - 1; +} + +void TestWebViewDelegate::SetUserStyleSheetEnabled(bool is_enabled) { + WebPreferences* prefs = shell_->GetWebPreferences(); + prefs->user_style_sheet_enabled = is_enabled; + shell_->webView()->SetPreferences(*prefs); +} + +void TestWebViewDelegate::SetUserStyleSheetLocation(const GURL& location) { + WebPreferences* prefs = shell_->GetWebPreferences(); + prefs->user_style_sheet_location = location; + shell_->webView()->SetPreferences(*prefs); +} + +void TestWebViewDelegate::SetDashboardCompatibilityMode(bool use_mode) { + WebPreferences* prefs = shell_->GetWebPreferences(); + prefs->dashboard_compatibility_mode = use_mode; + shell_->webView()->SetPreferences(*prefs); +} + +// WebWidgetDelegate --------------------------------------------------------- + +gfx::ViewHandle TestWebViewDelegate::GetContainingWindow(WebWidget* webwidget) { + if (WebWidgetHost* host = GetHostForWidget(webwidget)) + return host->window_handle(); + + return NULL; +} + +void TestWebViewDelegate::DidInvalidateRect(WebWidget* webwidget, + const gfx::Rect& rect) { + if (shell_ && shell_->webViewHost() && shell_->webViewHost()->window_handle()) + [shell_->webViewHost()->window_handle() setNeedsDisplay:YES]; +} + +void TestWebViewDelegate::DidScrollRect(WebWidget* webwidget, int dx, int dy, + const gfx::Rect& clip_rect) { + if (WebWidgetHost* host = GetHostForWidget(webwidget)) + host->DidScrollRect(dx, dy, clip_rect); +} + +void TestWebViewDelegate::Show(WebWidget* webview, + WindowOpenDisposition disposition) { +} + +void TestWebViewDelegate::CloseWidgetSoon(WebWidget* webwidget) { + if (webwidget == shell_->webView()) { + NSWindow *win = shell_->mainWnd(); + // Tell Cocoa to close the window. When the view is deallocated, + // the delegate (and therefore shell_) will be destroyed as well, so + // we do not need to explicitly null out the pointer shell_ is + // holding to the window. + [win performClose:nil]; + } else if (webwidget == shell_->popup()) { + shell_->ClosePopup(); + } +} + +void TestWebViewDelegate::Focus(WebWidget* webwidget) { + if (WebWidgetHost* host = GetHostForWidget(webwidget)) + shell_->SetFocus(host, true); +} + +void TestWebViewDelegate::Blur(WebWidget* webwidget) { + if (WebWidgetHost* host = GetHostForWidget(webwidget)) + shell_->SetFocus(host, false); +} + +void TestWebViewDelegate::SetCursor(WebWidget* webwidget, + const WebCursor& cursor) { + //TODO: Mac cursor handling +} + +void TestWebViewDelegate::GetWindowRect(WebWidget* webwidget, + gfx::Rect* out_rect) { + DCHECK(out_rect); + if (WebWidgetHost* host = GetHostForWidget(webwidget)) { + NSView *view = host->window_handle(); + NSRect rect = [[[view window] contentView] frame]; + *out_rect = gfx::Rect(NSRectToCGRect(rect)); + } +} + +void TestWebViewDelegate::SetWindowRect(WebWidget* webwidget, + const gfx::Rect& rect) { + // TODO: Mac window movement + if (webwidget == shell_->webView()) { + // ignored + } else if (webwidget == shell_->popup()) { + // MoveWindow(shell_->popupWnd(), + // rect.x(), rect.y(), rect.width(), rect.height(), FALSE); + } +} + +void TestWebViewDelegate::DidMove(WebWidget* webwidget, + const WebPluginGeometry& move) { + // TODO: uncomment when Mac plugins are working + // WebPluginDelegateImpl::MoveWindow( + // move.window, move.window_rect, move.clip_rect, move.visible); */ +} + +void TestWebViewDelegate::RegisterDragDrop() { + // TODO: uncomment when Mac drag and drop is working + // DCHECK(!drop_delegate_); + // drop_delegate_ = new TestDropDelegate(shell_->webViewWnd(), + // shell_->webView()); +} + +void TestWebViewDelegate::RunModal(WebWidget* webwidget) { + // TODO(pinkerton): implement me +} + +// Private methods ----------------------------------------------------------- + +void TestWebViewDelegate::UpdateAddressBar(WebView* webView) { + WebFrame* mainFrame = webView->GetMainFrame(); + + WebDataSource* dataSource = mainFrame->GetDataSource(); + if (!dataSource) + dataSource = mainFrame->GetProvisionalDataSource(); + if (!dataSource) + return; + + std::string frameURL = dataSource->GetRequest().GetMainDocumentURL().spec(); + NSString *address = [NSString stringWithUTF8String:frameURL.c_str()]; + [shell_->editWnd() setStringValue:address]; +} + +void TestWebViewDelegate::LocationChangeDone(WebDataSource* data_source) { + if (data_source->GetWebFrame() == top_loading_frame_) { + top_loading_frame_ = NULL; + [shell_->webViewHost()->window_handle() setNeedsDisplay:YES]; + + if (!shell_->interactive()) + shell_->layout_test_controller()->LocationChangeDone(); + } +} + +WebWidgetHost* TestWebViewDelegate::GetHostForWidget(WebWidget* webwidget) { + if (webwidget == shell_->webView()) + return shell_->webViewHost(); + if (webwidget == shell_->popup()) + return shell_->popupHost(); + return NULL; +} + +void TestWebViewDelegate::UpdateForCommittedLoad(WebFrame* frame, + bool is_new_navigation) { + WebView* webview = shell_->webView(); + + // Code duplicated from RenderView::DidCommitLoadForFrame. + const WebRequest& request = + webview->GetMainFrame()->GetDataSource()->GetRequest(); + TestShellExtraRequestData* extra_data = + static_cast<TestShellExtraRequestData*>(request.GetExtraData()); + + if (is_new_navigation) { + // New navigation. + UpdateSessionHistory(frame); + page_id_ = next_page_id_++; + } else if (extra_data && extra_data->pending_page_id != -1 && + !extra_data->request_committed) { + // This is a successful session history navigation! + UpdateSessionHistory(frame); + page_id_ = extra_data->pending_page_id; + } + + // Don't update session history multiple times. + if (extra_data) + extra_data->request_committed = true; + + UpdateURL(frame); +} + +void TestWebViewDelegate::UpdateURL(WebFrame* frame) { + WebDataSource* ds = frame->GetDataSource(); + DCHECK(ds); + + const WebRequest& request = ds->GetRequest(); + + scoped_ptr<TestNavigationEntry> entry(new TestNavigationEntry); + + // Bug 654101: the referrer will be empty on https->http transitions. It + // would be nice if we could get the real referrer from somewhere. + entry->SetPageID(page_id_); + if (ds->HasUnreachableURL()) { + entry->SetURL(GURL(ds->GetUnreachableURL())); + } else { + entry->SetURL(GURL(request.GetURL())); + } + + shell_->navigation_controller()->DidNavigateToEntry(entry.release()); + + last_page_id_updated_ = std::max(last_page_id_updated_, page_id_); +} + +void TestWebViewDelegate::UpdateSessionHistory(WebFrame* frame) { + // If we have a valid page ID at this point, then it corresponds to the page + // we are navigating away from. Otherwise, this is the first navigation, so + // there is no past session history to record. + if (page_id_ == -1) + return; + + TestNavigationEntry* entry = static_cast<TestNavigationEntry*>( + shell_->navigation_controller()->GetEntryWithPageID(page_id_)); + if (!entry) + return; + + GURL url; + std::wstring title; + std::string state; + if (!shell_->webView()->GetMainFrame()-> + GetPreviousState(&url, &title, &state)) + return; + + entry->SetURL(url); + entry->SetTitle(title); + entry->SetContentState(state); +} + +std::wstring TestWebViewDelegate::GetFrameDescription(WebFrame* webframe) { + std::wstring name = webframe->GetName(); + + if (webframe == shell_->webView()->GetMainFrame()) { + if (name.length()) + return L"main frame \"" + name + L"\""; + else + return L"main frame"; + } else { + if (name.length()) + return L"frame \"" + name + L"\""; + else + return L"frame (anonymous)"; + } +} diff --git a/webkit/tools/test_shell/mac/webview_host.mm b/webkit/tools/test_shell/mac/webview_host.mm new file mode 100644 index 0000000..803555a --- /dev/null +++ b/webkit/tools/test_shell/mac/webview_host.mm @@ -0,0 +1,42 @@ +// Copyright (c) 2008 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. + +#import <Cocoa/Cocoa.h> + +#include "webkit/tools/test_shell/webview_host.h" +#include "webkit/tools/test_shell/mac/test_shell_webview.h" + +#include "base/gfx/platform_canvas.h" +#include "base/gfx/rect.h" +#include "base/gfx/size.h" +#include "webkit/glue/webinputevent.h" +#include "webkit/glue/webview.h" + +/*static*/ +WebViewHost* WebViewHost::Create(NSWindow *parent_window, + WebViewDelegate* delegate, + const WebPreferences& prefs) { + WebViewHost* host = new WebViewHost(); + + NSRect content_rect = [[parent_window contentView] frame]; + // bump down the top of the view so that it doesn't overlap the buttons + // and URL field. 32 is an ad hoc constant. + // TODO(awalker): replace explicit view layout with a little nib file + // and use that for view geometry. + content_rect.size.height -= 32; + host->view_ = [[TestShellWebView alloc] initWithFrame:content_rect]; + // make the height and width track the window size. + [host->view_ setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; + [[parent_window contentView] addSubview:host->view_]; + + host->webwidget_ = WebView::Create(delegate, prefs); + host->webwidget_->Resize(gfx::Size(content_rect.size.width, + content_rect.size.height)); + + return host; +} + +WebView* WebViewHost::webview() const { + return static_cast<WebView*>(webwidget_); +} diff --git a/webkit/tools/test_shell/mac/webwidget_host.mm b/webkit/tools/test_shell/mac/webwidget_host.mm new file mode 100644 index 0000000..bf38fc4 --- /dev/null +++ b/webkit/tools/test_shell/mac/webwidget_host.mm @@ -0,0 +1,260 @@ +// Copyright (c) 2008 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. + +#import <Cocoa/Cocoa.h> + +#include "webkit/tools/test_shell/webwidget_host.h" + +#include "base/gfx/platform_canvas_mac.h" +#include "base/gfx/rect.h" +#include "base/gfx/size.h" +#include "base/logging.h" +#include "webkit/glue/webinputevent.h" +#include "webkit/glue/webwidget.h" + +/*static*/ +WebWidgetHost* WebWidgetHost::Create(NSWindow* parent_window, + WebWidgetDelegate* delegate) { + WebWidgetHost* host = new WebWidgetHost(); + + NSRect content_rect = [parent_window frame]; + content_rect.origin.y += 64; + content_rect.size.height -= 64; + host->view_ = [[NSView alloc] initWithFrame:content_rect]; + [[parent_window contentView] addSubview:host->view_]; + + // win_util::SetWindowUserData(host->hwnd_, host); + + host->webwidget_ = WebWidget::Create(delegate); + host->webwidget_->Resize(gfx::Size(content_rect.size.width, + content_rect.size.height)); + return host; +} + +/*static*/ +WebWidgetHost* WebWidgetHost::FromWindow(NSWindow* hwnd) { + return NULL; +} + +/*static*/ +void WebWidgetHost::HandleEvent(NSWindow *window, NSEvent *event) { + WebWidgetHost* host = FromWindow(window); + if (host) { + switch ([event type]) { + case NSLeftMouseDown: + case NSLeftMouseUp: + case NSRightMouseDown: + case NSRightMouseUp: + case NSOtherMouseDown: + case NSOtherMouseUp: + case NSMouseEntered: + case NSMouseExited: + host->MouseEvent(event); + break; + + case NSScrollWheel: + host->WheelEvent(event); + break; + + case NSKeyDown: + case NSKeyUp: + host->KeyEvent(event); + break; + + case NSAppKitDefined: + switch ([event subtype]) { + case NSApplicationActivatedEventType: + host->SetFocus(true); + break; + case NSApplicationDeactivatedEventType: + host->SetFocus(false); + break; + } + break; + } + } +} + +void WebWidgetHost::DidInvalidateRect(const gfx::Rect& damaged_rect) { + DLOG_IF(WARNING, painting_) << "unexpected invalidation while painting"; + + // If this invalidate overlaps with a pending scroll, then we have to + // downgrade to invalidating the scroll rect. + if (damaged_rect.Intersects(scroll_rect_)) { + paint_rect_ = paint_rect_.Union(scroll_rect_); + ResetScrollRect(); + } + paint_rect_ = paint_rect_.Union(damaged_rect); + + NSRect r = NSRectFromCGRect(damaged_rect.ToCGRect()); + [view_ setNeedsDisplayInRect:r]; +} + +void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) { + DCHECK(dx || dy); + + // If we already have a pending scroll operation or if this scroll operation + // intersects the existing paint region, then just failover to invalidating. + if (!scroll_rect_.IsEmpty() || paint_rect_.Intersects(clip_rect)) { + paint_rect_ = paint_rect_.Union(scroll_rect_); + ResetScrollRect(); + paint_rect_ = paint_rect_.Union(clip_rect); + } + + // We will perform scrolling lazily, when requested to actually paint. + scroll_rect_ = clip_rect; + scroll_dx_ = dx; + scroll_dy_ = dy; + + NSRect r = NSRectFromCGRect(clip_rect.ToCGRect()); + [view_ setNeedsDisplayInRect:r]; +} + +// void WebWidgetHost::SetCursor(HCURSOR cursor) { +// } + +void WebWidgetHost::DiscardBackingStore() { + canvas_.reset(); +} + +WebWidgetHost::WebWidgetHost() + : view_(NULL), + webwidget_(NULL), + scroll_dx_(0), + scroll_dy_(0), + track_mouse_leave_(false) +{ + set_painting(false); +} + +WebWidgetHost::~WebWidgetHost() { + // win_util::SetWindowUserData(hwnd_, 0); + + TrackMouseLeave(false); + + webwidget_->Close(); + webwidget_->Release(); +} + +void WebWidgetHost::Paint() { + NSRect r = [view_ frame]; + gfx::Rect client_rect(NSRectToCGRect(r)); + NSGraphicsContext* view_context = [NSGraphicsContext currentContext]; + CGContextRef context = static_cast<CGContextRef>([view_context graphicsPort]); + + // Allocate a canvas if necessary + if (!canvas_.get()) { + ResetScrollRect(); + paint_rect_ = client_rect; + canvas_.reset(new gfx::PlatformCanvas( + paint_rect_.width(), paint_rect_.height(), true)); + } + + // make sure webkit draws into our bitmap, not the window + CGContextRef bitmap_context = + canvas_->getTopPlatformDevice().GetBitmapContext(); + [NSGraphicsContext setCurrentContext: + [NSGraphicsContext graphicsContextWithGraphicsPort:bitmap_context + flipped:NO]]; + + // This may result in more invalidation + webwidget_->Layout(); + + // Scroll the canvas if necessary + scroll_rect_ = client_rect.Intersect(scroll_rect_); + if (!scroll_rect_.IsEmpty()) { + // add to invalidate rect, since there's no equivalent of ScrollDC. + paint_rect_.Union(scroll_rect_); + } + ResetScrollRect(); + + // Paint the canvas if necessary. Allow painting to generate extra rects the + // first time we call it. This is necessary because some WebCore rendering + // objects update their layout only when painted. + for (int i = 0; i < 2; ++i) { + paint_rect_ = client_rect;//.Intersect(paint_rect_); + if (!paint_rect_.IsEmpty()) { + gfx::Rect rect(paint_rect_); + paint_rect_ = gfx::Rect(); + +// DLOG_IF(WARNING, i == 1) << "painting caused additional invalidations"; + PaintRect(rect); + } + } + DCHECK(paint_rect_.IsEmpty()); + + // set the context back to our window + [NSGraphicsContext setCurrentContext: view_context]; + + // Paint to the screen + if ([view_ lockFocusIfCanDraw]) { + CGRect paint_rect = NSRectToCGRect(r); + int bitmap_height = CGBitmapContextGetHeight(bitmap_context); + int bitmap_width = CGBitmapContextGetWidth(bitmap_context); + CGRect bitmap_rect = { { 0, 0 }, + { bitmap_width, bitmap_height } }; + canvas_->getTopPlatformDevice().DrawToContext( + context, 0, client_rect.height() - bitmap_height, &bitmap_rect); + + [view_ unlockFocus]; + } + + // Draw children + // UpdateWindow(hwnd_); +} + +void WebWidgetHost::Resize(const gfx::Rect& rect) { + // Force an entire re-paint. TODO(darin): Maybe reuse this memory buffer. + DiscardBackingStore(); + webwidget_->Resize(gfx::Size(rect.width(), rect.height())); +} + +void WebWidgetHost::MouseEvent(NSEvent *event) { + WebMouseEvent web_event(event); + switch (event.type) { + case WebInputEvent::MOUSE_MOVE: + TrackMouseLeave(true); + break; + case WebInputEvent::MOUSE_LEAVE: + TrackMouseLeave(false); + break; + case WebInputEvent::MOUSE_DOWN: + break; + case WebInputEvent::MOUSE_UP: + break; + } + webwidget_->HandleInputEvent(&web_event); +} + +void WebWidgetHost::WheelEvent(NSEvent *event) { + WebMouseWheelEvent web_event(event); + webwidget_->HandleInputEvent(&web_event); +} + +void WebWidgetHost::KeyEvent(NSEvent *event) { + WebKeyboardEvent web_event(event); + webwidget_->HandleInputEvent(&web_event); +} + +void WebWidgetHost::SetFocus(bool enable) { + webwidget_->SetFocus(enable); +} + +void WebWidgetHost::TrackMouseLeave(bool track) { +} + +void WebWidgetHost::ResetScrollRect() { + scroll_rect_ = gfx::Rect(); + scroll_dx_ = 0; + scroll_dy_ = 0; +} + +void WebWidgetHost::PaintRect(const gfx::Rect& rect) { + DCHECK(!painting_); + DCHECK(canvas_.get()); + + set_painting(true); + webwidget_->Paint(canvas_.get(), rect); + set_painting(false); +} |