X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/2f70baea2fa2aa1fbcdceb0121eea1cb5c9bedf0..eea4d01c65f9b29baa1193db762b4c6b8144af24:/src/osx/webview_webkit.mm diff --git a/src/osx/webview_webkit.mm b/src/osx/webview_webkit.mm index 37b6eb9cbb..f3efc4e2e5 100644 --- a/src/osx/webview_webkit.mm +++ b/src/osx/webview_webkit.mm @@ -24,22 +24,17 @@ #include "wx/wx.h" #endif -#ifdef __WXCOCOA__ -#include "wx/cocoa/autorelease.h" -#else #include "wx/osx/private.h" +#include "wx/cocoa/string.h" +#include "wx/hashmap.h" +#include "wx/filesys.h" #include #include #include -#endif #include -// FIXME: find cleaner way to find the wxWidgets ID of a webview than this hack -#include -std::map wx_webviewctrls; - #define DEBUG_WEBKIT_SIZING 0 // ---------------------------------------------------------------------------- @@ -302,29 +297,7 @@ DEFINE_ONE_SHOT_HANDLER_GETTER( wxWebViewWebKitEventHandler ) #endif -//--------------------------------------------------------- -// helper functions for NSString<->wxString conversion -//--------------------------------------------------------- - -inline wxString wxStringWithNSString(NSString *nsstring) -{ -#if wxUSE_UNICODE - return wxString([nsstring UTF8String], wxConvUTF8); -#else - return wxString([nsstring lossyCString]); -#endif // wxUSE_UNICODE -} - -inline NSString* wxNSStringWithWxString(const wxString &wxstring) -{ -#if wxUSE_UNICODE - return [NSString stringWithUTF8String: wxstring.mb_str(wxConvUTF8)]; -#else - return [NSString stringWithCString: wxstring.c_str() length:wxstring.Len()]; -#endif // wxUSE_UNICODE -} - -@interface MyFrameLoadMonitor : NSObject +@interface WebViewLoadDelegate : NSObject { wxWebViewWebKit* webKitWindow; } @@ -333,7 +306,7 @@ inline NSString* wxNSStringWithWxString(const wxString &wxstring) @end -@interface MyPolicyDelegate : NSObject +@interface WebViewPolicyDelegate : NSObject { wxWebViewWebKit* webKitWindow; } @@ -342,6 +315,16 @@ inline NSString* wxNSStringWithWxString(const wxString &wxstring) @end +//We use a hash to map scheme names to wxWebHandlers +WX_DECLARE_STRING_HASH_MAP(wxSharedPtr, wxStringToWebHandlerMap); + +static wxStringToWebHandlerMap g_stringHandlerMap; + +@interface WebViewCustomProtocol : NSURLProtocol +{ +} +@end + // ---------------------------------------------------------------------------- // creation/destruction // ---------------------------------------------------------------------------- @@ -354,124 +337,80 @@ bool wxWebViewWebKit::Create(wxWindow *parent, const wxString& name) { m_busy = false; - //m_pageTitle = _("Untitled Page"); - //still needed for wxCocoa?? -/* - int width, height; - wxSize sizeInstance; - if (size.x == wxDefaultCoord || size.y == wxDefaultCoord) - { - m_parent->GetClientSize(&width, &height); - sizeInstance.x = width; - sizeInstance.y = height; - } - else - { - sizeInstance.x = size.x; - sizeInstance.y = size.y; - } -*/ - // now create and attach WebKit view... -#ifdef __WXCOCOA__ - wxControl::Create(parent, m_windowID, pos, sizeInstance, style, name); - SetSize(pos.x, pos.y, sizeInstance.x, sizeInstance.y); - - wxTopLevelWindowCocoa *topWin = wxDynamicCast(this, wxTopLevelWindowCocoa); - NSWindow* nsWin = topWin->GetNSWindow(); - NSRect rect; - rect.origin.x = pos.x; - rect.origin.y = pos.y; - rect.size.width = sizeInstance.x; - rect.size.height = sizeInstance.y; - m_webView = (WebView*)[[WebView alloc] initWithFrame:rect - frameName:@"webkitFrame" - groupName:@"webkitGroup"]; - SetNSView(m_webView); - [m_cocoaNSView release]; - - if(m_parent) m_parent->CocoaAddChild(this); - SetInitialFrameRect(pos,sizeInstance); -#else + DontCreatePeer(); wxControl::Create(parent, winID, pos, size, style, wxDefaultValidator, name); #if wxOSX_USE_CARBON - m_peer = new wxMacControl(this); + wxMacControl* peer = new wxMacControl(this); WebInitForCarbon(); - HIWebViewCreate( m_peer->GetControlRefAddr() ); + HIWebViewCreate( peer->GetControlRefAddr() ); - m_webView = (WebView*) HIWebViewGetWebView( m_peer->GetControlRef() ); + m_webView = (WebView*) HIWebViewGetWebView( peer->GetControlRef() ); #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3 if ( UMAGetSystemVersion() >= 0x1030 ) - HIViewChangeFeatures( m_peer->GetControlRef() , kHIViewIsOpaque , 0 ) ; + HIViewChangeFeatures( peer->GetControlRef() , kHIViewIsOpaque , 0 ) ; #endif - InstallControlEventHandler(m_peer->GetControlRef(), + InstallControlEventHandler(peer->GetControlRef(), GetwxWebViewWebKitEventHandlerUPP(), GetEventTypeCount(eventList), eventList, this, (EventHandlerRef *)&m_webKitCtrlEventHandler); + SetPeer(peer); #else NSRect r = wxOSXGetFrameForControl( this, pos , size ) ; m_webView = [[WebView alloc] initWithFrame:r frameName:@"webkitFrame" groupName:@"webkitGroup"]; - m_peer = new wxWidgetCocoaImpl( this, m_webView ); + SetPeer(new wxWidgetCocoaImpl( this, m_webView )); #endif - wx_webviewctrls[m_webView] = this; - MacPostControlCreate(pos, size); #if wxOSX_USE_CARBON - HIViewSetVisible( m_peer->GetControlRef(), true ); + HIViewSetVisible( GetPeer()->GetControlRef(), true ); #endif [m_webView setHidden:false]; -#endif + // Register event listener interfaces - MyFrameLoadMonitor* myFrameLoadMonitor = - [[MyFrameLoadMonitor alloc] initWithWxWindow: this]; + WebViewLoadDelegate* loadDelegate = + [[WebViewLoadDelegate alloc] initWithWxWindow: this]; - [m_webView setFrameLoadDelegate:myFrameLoadMonitor]; + [m_webView setFrameLoadDelegate:loadDelegate]; // this is used to veto page loads, etc. - MyPolicyDelegate* myPolicyDelegate = - [[MyPolicyDelegate alloc] initWithWxWindow: this]; + WebViewPolicyDelegate* policyDelegate = + [[WebViewPolicyDelegate alloc] initWithWxWindow: this]; + + [m_webView setPolicyDelegate:policyDelegate]; - [m_webView setPolicyDelegate:myPolicyDelegate]; + //Register our own class for custom scheme handling + [NSURLProtocol registerClass:[WebViewCustomProtocol class]]; - InternalLoadURL(strURL); + LoadUrl(strURL); return true; } wxWebViewWebKit::~wxWebViewWebKit() { - MyFrameLoadMonitor* myFrameLoadMonitor = [m_webView frameLoadDelegate]; - MyPolicyDelegate* myPolicyDelegate = [m_webView policyDelegate]; + WebViewLoadDelegate* loadDelegate = [m_webView frameLoadDelegate]; + WebViewPolicyDelegate* policyDelegate = [m_webView policyDelegate]; [m_webView setFrameLoadDelegate: nil]; [m_webView setPolicyDelegate: nil]; - if (myFrameLoadMonitor) - [myFrameLoadMonitor release]; + if (loadDelegate) + [loadDelegate release]; - if (myPolicyDelegate) - [myPolicyDelegate release]; + if (policyDelegate) + [policyDelegate release]; } // ---------------------------------------------------------------------------- // public methods // ---------------------------------------------------------------------------- -void wxWebViewWebKit::InternalLoadURL(const wxString &url) -{ - if( !m_webView ) - return; - - [[m_webView mainFrame] loadRequest:[NSURLRequest requestWithURL: - [NSURL URLWithString:wxNSStringWithWxString(url)]]]; -} - bool wxWebViewWebKit::CanGoBack() { if ( !m_webView ) @@ -493,10 +432,7 @@ void wxWebViewWebKit::GoBack() if ( !m_webView ) return; - bool result = [(WebView*)m_webView goBack]; - - // TODO: return result (if it also exists in other backends...) - //return result; + [(WebView*)m_webView goBack]; } void wxWebViewWebKit::GoForward() @@ -504,10 +440,7 @@ void wxWebViewWebKit::GoForward() if ( !m_webView ) return; - bool result = [(WebView*)m_webView goForward]; - - // TODO: return result (if it also exists in other backends...) - //return result; + [(WebView*)m_webView goForward]; } void wxWebViewWebKit::Reload(wxWebViewReloadFlags flags) @@ -794,7 +727,7 @@ void wxWebViewWebKit::OnSize(wxSizeEvent &event) void wxWebViewWebKit::MacVisibilityChanged(){ #if defined(__WXMAC__) && wxOSX_USE_CARBON - bool isHidden = !IsControlVisible( m_peer->GetControlRef()); + bool isHidden = !IsControlVisible( GetPeer()->GetControlRef()); if (!isHidden) [(WebView*)m_webView display]; @@ -804,7 +737,8 @@ void wxWebViewWebKit::MacVisibilityChanged(){ void wxWebViewWebKit::LoadUrl(const wxString& url) { - InternalLoadURL(url); + [[m_webView mainFrame] loadRequest:[NSURLRequest requestWithURL: + [NSURL URLWithString:wxNSStringWithWxString(url)]]]; } wxString wxWebViewWebKit::GetCurrentURL() @@ -814,7 +748,7 @@ wxString wxWebViewWebKit::GetCurrentURL() wxString wxWebViewWebKit::GetCurrentTitle() { - return GetPageTitle(); + return wxStringWithNSString([m_webView mainFrameTitle]); } float wxWebViewWebKit::GetWebkitZoom() @@ -944,6 +878,35 @@ bool wxWebViewWebKit::HasSelection() } } +void wxWebViewWebKit::ClearSelection() +{ + //We use javascript as selection isn't exposed at the moment in webkit + RunScript("window.getSelection().removeAllRanges();"); +} + +void wxWebViewWebKit::SelectAll() +{ + RunScript("window.getSelection().selectAllChildren(document.body);"); +} + +wxString wxWebViewWebKit::GetSelectedSource() +{ + wxString script = ("var range = window.getSelection().getRangeAt(0);" + "var element = document.createElement('div');" + "element.appendChild(range.cloneContents());" + "return element.innerHTML;"); + id result = [[m_webView windowScriptObject] + evaluateWebScript:wxNSStringWithWxString(script)]; + return wxStringWithNSString([result stringValue]); +} + +wxString wxWebViewWebKit::GetPageText() +{ + id result = [[m_webView windowScriptObject] + evaluateWebScript:@"document.body.textContent"]; + return wxStringWithNSString([result stringValue]); +} + void wxWebViewWebKit::EnableHistory(bool enable) { if ( !m_webView ) @@ -952,6 +915,53 @@ void wxWebViewWebKit::EnableHistory(bool enable) [m_webView setMaintainsBackForwardList:enable]; } +void wxWebViewWebKit::ClearHistory() +{ + [m_webView setMaintainsBackForwardList:NO]; + [m_webView setMaintainsBackForwardList:YES]; +} + +wxVector > wxWebViewWebKit::GetBackwardHistory() +{ + wxVector > backhist; + WebBackForwardList* history = [m_webView backForwardList]; + int count = [history backListCount]; + for(int i = -count; i < 0; i++) + { + WebHistoryItem* item = [history itemAtIndex:i]; + wxString url = wxStringWithNSString([item URLString]); + wxString title = wxStringWithNSString([item title]); + wxWebHistoryItem* wxitem = new wxWebHistoryItem(url, title); + wxitem->m_histItem = item; + wxSharedPtr itemptr(wxitem); + backhist.push_back(itemptr); + } + return backhist; +} + +wxVector > wxWebViewWebKit::GetForwardHistory() +{ + wxVector > forwardhist; + WebBackForwardList* history = [m_webView backForwardList]; + int count = [history forwardListCount]; + for(int i = 1; i <= count; i++) + { + WebHistoryItem* item = [history itemAtIndex:i]; + wxString url = wxStringWithNSString([item URLString]); + wxString title = wxStringWithNSString([item title]); + wxWebHistoryItem* wxitem = new wxWebHistoryItem(url, title); + wxitem->m_histItem = item; + wxSharedPtr itemptr(wxitem); + forwardhist.push_back(itemptr); + } + return forwardhist; +} + +void wxWebViewWebKit::LoadHistoryItem(wxSharedPtr item) +{ + [m_webView goToBackForwardItem:item->m_histItem]; +} + bool wxWebViewWebKit::CanUndo() { return [[m_webView undoManager] canUndo]; @@ -972,6 +982,11 @@ void wxWebViewWebKit::Redo() [[m_webView undoManager] redo]; } +void wxWebViewWebKit::RegisterHandler(wxSharedPtr handler) +{ + g_stringHandlerMap[handler->GetName()] = handler; +} + //------------------------------------------------------------ // Listener interfaces //------------------------------------------------------------ @@ -981,7 +996,7 @@ void wxWebViewWebKit::Redo() // destroyed. Therefore, we must be careful to check both the existence // of the Carbon control and the event handler before firing events. -@implementation MyFrameLoadMonitor +@implementation WebViewLoadDelegate - initWithWxWindow: (wxWebViewWebKit*)inWindow { @@ -993,20 +1008,18 @@ void wxWebViewWebKit::Redo() - (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame { - wxASSERT(wx_webviewctrls.find(sender) != wx_webviewctrls.end()); - wx_webviewctrls[sender]->m_busy = true; + webKitWindow->m_busy = true; } - (void)webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame { - wxASSERT(wx_webviewctrls.find(sender) != wx_webviewctrls.end()); - wx_webviewctrls[sender]->m_busy = true; + webKitWindow->m_busy = true; if (webKitWindow && frame == [sender mainFrame]){ NSString *url = [[[[frame dataSource] request] URL] absoluteString]; wxString target = wxStringWithNSString([frame name]); wxWebNavigationEvent thisEvent(wxEVT_COMMAND_WEB_VIEW_NAVIGATED, - wx_webviewctrls[sender]->GetId(), + webKitWindow->GetId(), wxStringWithNSString( url ), target, false); @@ -1017,15 +1030,14 @@ void wxWebViewWebKit::Redo() - (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame { - wxASSERT(wx_webviewctrls.find(sender) != wx_webviewctrls.end()); - wx_webviewctrls[sender]->m_busy = false; + webKitWindow->m_busy = false; if (webKitWindow && frame == [sender mainFrame]){ NSString *url = [[[[frame dataSource] request] URL] absoluteString]; wxString target = wxStringWithNSString([frame name]); wxWebNavigationEvent thisEvent(wxEVT_COMMAND_WEB_VIEW_LOADED, - wx_webviewctrls[sender]->GetId(), + webKitWindow->GetId(), wxStringWithNSString( url ), target, false); @@ -1111,8 +1123,7 @@ wxString nsErrorToWxHtmlError(NSError* error, wxWebNavigationError* out) - (void)webView:(WebView *)sender didFailLoadWithError:(NSError*) error forFrame:(WebFrame *)frame { - wxASSERT(wx_webviewctrls.find(sender) != wx_webviewctrls.end()); - wx_webviewctrls[sender]->m_busy = false; + webKitWindow->m_busy = false; if (webKitWindow && frame == [sender mainFrame]){ NSString *url = [[[[frame dataSource] request] URL] absoluteString]; @@ -1120,7 +1131,7 @@ wxString nsErrorToWxHtmlError(NSError* error, wxWebNavigationError* out) wxWebNavigationError type; wxString description = nsErrorToWxHtmlError(error, &type); wxWebNavigationEvent thisEvent(wxEVT_COMMAND_WEB_VIEW_ERROR, - wx_webviewctrls[sender]->GetId(), + webKitWindow->GetId(), wxStringWithNSString( url ), wxEmptyString, false); thisEvent.SetString(description); @@ -1137,8 +1148,7 @@ wxString nsErrorToWxHtmlError(NSError* error, wxWebNavigationError* out) didFailProvisionalLoadWithError:(NSError*)error forFrame:(WebFrame *)frame { - wxASSERT(wx_webviewctrls.find(sender) != wx_webviewctrls.end()); - wx_webviewctrls[sender]->m_busy = false; + webKitWindow->m_busy = false; if (webKitWindow && frame == [sender mainFrame]){ NSString *url = [[[[frame provisionalDataSource] request] URL] @@ -1147,7 +1157,7 @@ wxString nsErrorToWxHtmlError(NSError* error, wxWebNavigationError* out) wxWebNavigationError type; wxString description = nsErrorToWxHtmlError(error, &type); wxWebNavigationEvent thisEvent(wxEVT_COMMAND_WEB_VIEW_ERROR, - wx_webviewctrls[sender]->GetId(), + webKitWindow->GetId(), wxStringWithNSString( url ), wxEmptyString, false); thisEvent.SetString(description); @@ -1161,14 +1171,10 @@ wxString nsErrorToWxHtmlError(NSError* error, wxWebNavigationError* out) - (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame { - if (webKitWindow && frame == [sender mainFrame]) - { - webKitWindow->SetPageTitle(wxStringWithNSString( title )); - } wxString target = wxStringWithNSString([frame name]); wxWebNavigationEvent thisEvent(wxEVT_COMMAND_WEB_VIEW_TITLE_CHANGED, - wx_webviewctrls[sender]->GetId(), - wx_webviewctrls[sender]->GetCurrentURL(), + webKitWindow->GetId(), + webKitWindow->GetCurrentURL(), target, true); thisEvent.SetString(wxStringWithNSString(title)); @@ -1178,7 +1184,7 @@ wxString nsErrorToWxHtmlError(NSError* error, wxWebNavigationError* out) } @end -@implementation MyPolicyDelegate +@implementation WebViewPolicyDelegate - initWithWxWindow: (wxWebViewWebKit*)inWindow { @@ -1195,12 +1201,11 @@ wxString nsErrorToWxHtmlError(NSError* error, wxWebNavigationError* out) { wxUnusedVar(frame); - wxASSERT(wx_webviewctrls.find(sender) != wx_webviewctrls.end()); - wx_webviewctrls[sender]->m_busy = true; + webKitWindow->m_busy = true; NSString *url = [[request URL] absoluteString]; wxString target = wxStringWithNSString([frame name]); wxWebNavigationEvent thisEvent(wxEVT_COMMAND_WEB_VIEW_NAVIGATING, - wx_webviewctrls[sender]->GetId(), + webKitWindow->GetId(), wxStringWithNSString( url ), target, true); if (webKitWindow && webKitWindow->GetEventHandler()) @@ -1208,7 +1213,7 @@ wxString nsErrorToWxHtmlError(NSError* error, wxWebNavigationError* out) if (thisEvent.IsVetoed()) { - wx_webviewctrls[sender]->m_busy = false; + webKitWindow->m_busy = false; [listener ignore]; } else @@ -1224,11 +1229,10 @@ wxString nsErrorToWxHtmlError(NSError* error, wxWebNavigationError* out) decisionListener:(id < WebPolicyDecisionListener >)listener { wxUnusedVar(actionInformation); - - wxASSERT(wx_webviewctrls.find(sender) != wx_webviewctrls.end()); + NSString *url = [[request URL] absoluteString]; wxWebNavigationEvent thisEvent(wxEVT_COMMAND_WEB_VIEW_NEWWINDOW, - wx_webviewctrls[sender]->GetId(), + webKitWindow->GetId(), wxStringWithNSString( url ), "", true); if (webKitWindow && webKitWindow->GetEventHandler()) @@ -1238,4 +1242,71 @@ wxString nsErrorToWxHtmlError(NSError* error, wxWebNavigationError* out) } @end +@implementation WebViewCustomProtocol + ++ (BOOL)canInitWithRequest:(NSURLRequest *)request +{ + NSString *scheme = [[request URL] scheme]; + + wxStringToWebHandlerMap::const_iterator it; + for( it = g_stringHandlerMap.begin(); it != g_stringHandlerMap.end(); ++it ) + { + if(it->first.IsSameAs(wxStringWithNSString(scheme))) + { + return YES; + } + } + + return NO; +} + ++ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request +{ + //We don't do any processing here as the wxWebHandler classes do it + return request; +} + +- (void)startLoading +{ + NSURLRequest *request = [self request]; + NSString* path = [[request URL] absoluteString]; + + wxString wxpath = wxStringWithNSString(path); + wxString scheme = wxStringWithNSString([[request URL] scheme]); + wxFSFile* file = g_stringHandlerMap[scheme]->GetFile(wxpath); + size_t length = file->GetStream()->GetLength(); + + + NSURLResponse *response = [[NSURLResponse alloc] initWithURL:[request URL] + MIMEType:wxNSStringWithWxString(file->GetMimeType()) + expectedContentLength:length + textEncodingName:nil]; + + //Load the data, we malloc it so it is tidied up properly + void* buffer = malloc(length); + file->GetStream()->Read(buffer, length); + NSData *data = [[NSData alloc] initWithBytesNoCopy:buffer length:length]; + + id client = [self client]; + + //We do not support caching anything yet + [client URLProtocol:self didReceiveResponse:response + cacheStoragePolicy:NSURLCacheStorageNotAllowed]; + + //Set the data + [client URLProtocol:self didLoadData:data]; + + //Notify that we have finished + [client URLProtocolDidFinishLoading:self]; + + [response release]; +} + +- (void)stopLoading +{ + +} + +@end + #endif //wxUSE_WEBVIEW_WEBKIT