Move the legacy WebKit API into WebKitLegacy.framework and move it inside WebKit...
[WebKit-https.git] / Source / WebKit / mac / WebCoreSupport / WebInspectorClient.mm
index c89579e..73ce2a3 100644 (file)
@@ -6,13 +6,13 @@
  * are met:
  *
  * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer. 
+ *     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. 
- * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
  *     its contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission. 
+ *     from this software without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 #import "WebFrameInternal.h"
 #import "WebFrameView.h"
 #import "WebInspector.h"
-#import "WebInspectorPrivate.h"
 #import "WebInspectorFrontend.h"
+#import "WebInspectorPrivate.h"
 #import "WebLocalizableStringsInternal.h"
 #import "WebNodeHighlighter.h"
-#import "WebUIDelegate.h"
 #import "WebPolicyDelegate.h"
+#import "WebQuotaManager.h"
+#import "WebSecurityOriginPrivate.h"
+#import "WebUIDelegate.h"
 #import "WebViewInternal.h"
-#import <WebCore/Frame.h>
+#import <algorithm>
+#import <bindings/ScriptValue.h>
+#import <inspector/InspectorAgentBase.h>
 #import <WebCore/InspectorController.h>
+#import <WebCore/InspectorFrontendClient.h>
+#import <WebCore/MainFrame.h>
 #import <WebCore/Page.h>
-#import <WebCore/ScriptValue.h>
+#import <WebCore/ScriptController.h>
 #import <WebCore/SoftLinking.h>
-#import <WebKit/DOMExtensions.h>
+#import <WebKitLegacy/DOMExtensions.h>
 #import <WebKitSystemInterface.h>
-#import <wtf/PassOwnPtr.h>
+#import <wtf/text/Base64.h>
 
-SOFT_LINK_STAGED_FRAMEWORK_OPTIONAL(WebInspector, PrivateFrameworks, A)
+SOFT_LINK_STAGED_FRAMEWORK(WebInspectorUI, PrivateFrameworks, A)
 
 // The margin from the top and right of the dock button (same as the full screen button).
 static const CGFloat dockButtonMargin = 3;
@@ -102,8 +108,9 @@ using namespace WebCore;
     BOOL _visible;
     BOOL _destroyingInspectorView;
 }
-- (id)initWithInspectedWebView:(WebView *)webView;
+- (id)initWithInspectedWebView:(WebView *)webView isUnderTest:(BOOL)isUnderTest;
 - (NSString *)inspectorPagePath;
+- (NSString *)inspectorTestPagePath;
 - (WebView *)webView;
 - (void)attach;
 - (void)detach;
@@ -121,7 +128,7 @@ using namespace WebCore;
 
 WebInspectorClient::WebInspectorClient(WebView *webView)
     : m_webView(webView)
-    , m_highlighter(AdoptNS, [[WebNodeHighlighter alloc] initWithInspectedWebView:webView])
+    , m_highlighter(adoptNS([[WebNodeHighlighter alloc] initWithInspectedWebView:webView]))
     , m_frontendPage(0)
     , m_frontendClient(0)
 {
@@ -135,15 +142,15 @@ void WebInspectorClient::inspectorDestroyed()
 
 InspectorFrontendChannel* WebInspectorClient::openInspectorFrontend(InspectorController* inspectorController)
 {
-    RetainPtr<WebInspectorWindowController> windowController(AdoptNS, [[WebInspectorWindowController alloc] initWithInspectedWebView:m_webView]);
+    RetainPtr<WebInspectorWindowController> windowController = adoptNS([[WebInspectorWindowController alloc] initWithInspectedWebView:m_webView isUnderTest:inspectorController->isUnderTest()]);
     [windowController.get() setInspectorClient:this];
 
     m_frontendPage = core([windowController.get() webView]);
-    OwnPtr<WebInspectorFrontendClient> frontendClient = adoptPtr(new WebInspectorFrontendClient(m_webView, windowController.get(), inspectorController, m_frontendPage, createFrontendSettings()));
+    auto frontendClient = std::make_unique<WebInspectorFrontendClient>(m_webView, windowController.get(), inspectorController, m_frontendPage, createFrontendSettings());
     m_frontendClient = frontendClient.get();
-    RetainPtr<WebInspectorFrontend> webInspectorFrontend(AdoptNS, [[WebInspectorFrontend alloc] initWithFrontendClient:frontendClient.get()]);
+    RetainPtr<WebInspectorFrontend> webInspectorFrontend = adoptNS([[WebInspectorFrontend alloc] initWithFrontendClient:frontendClient.get()]);
     [[m_webView inspector] setFrontend:webInspectorFrontend.get()];
-    m_frontendPage->inspectorController()->setInspectorFrontendClient(frontendClient.release());
+    m_frontendPage->inspectorController().setInspectorFrontendClient(std::move(frontendClient));
     return this;
 }
 
@@ -161,7 +168,7 @@ void WebInspectorClient::bringFrontendToFront()
 void WebInspectorClient::didResizeMainFrame(Frame*)
 {
     if (m_frontendClient)
-        m_frontendClient->attachAvailabilityChanged(m_frontendClient->canAttachWindow());
+        m_frontendClient->attachAvailabilityChanged(m_frontendClient->canAttachWindow() && !inspectorAttachDisabled());
 }
 
 void WebInspectorClient::highlight()
@@ -174,14 +181,27 @@ void WebInspectorClient::hideHighlight()
     [m_highlighter.get() hideHighlight];
 }
 
+void WebInspectorClient::didSetSearchingForNode(bool enabled)
+{
+    WebInspector *inspector = [m_webView inspector];
+
+    ASSERT(isMainThread());
+
+    if (enabled)
+        [[NSNotificationCenter defaultCenter] postNotificationName:WebInspectorDidStartSearchingForNode object:inspector];
+    else
+        [[NSNotificationCenter defaultCenter] postNotificationName:WebInspectorDidStopSearchingForNode object:inspector];
+}
+
 void WebInspectorClient::releaseFrontend()
 {
     m_frontendClient = 0;
     m_frontendPage = 0;
 }
 
-WebInspectorFrontendClient::WebInspectorFrontendClient(WebView* inspectedWebView, WebInspectorWindowController* windowController, InspectorController* inspectorController, Page* frontendPage, WTF::PassOwnPtr<Settings> settings)
-    : InspectorFrontendClientLocal(inspectorController,  frontendPage, settings)
+
+WebInspectorFrontendClient::WebInspectorFrontendClient(WebView* inspectedWebView, WebInspectorWindowController* windowController, InspectorController* inspectorController, Page* frontendPage, std::unique_ptr<Settings> settings)
+    : InspectorFrontendClientLocal(inspectorController,  frontendPage, std::move(settings))
     , m_inspectedWebView(inspectedWebView)
     , m_windowController(windowController)
 {
@@ -203,34 +223,22 @@ void WebInspectorFrontendClient::frontendLoaded()
     InspectorFrontendClientLocal::frontendLoaded();
 
     WebFrame *frame = [m_inspectedWebView mainFrame];
-    
+
     WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(m_inspectedWebView);
     if (implementations->didClearInspectorWindowObjectForFrameFunc)
         CallFrameLoadDelegate(implementations->didClearInspectorWindowObjectForFrameFunc, m_inspectedWebView,
                               @selector(webView:didClearInspectorWindowObject:forFrame:), [frame windowObject], frame);
 
     bool attached = [m_windowController.get() attached];
-    setAttachedWindow(attached);
+    setAttachedWindow(attached ? DOCKED_TO_BOTTOM : UNDOCKED);
 }
 
-static bool useWebKitWebInspector()
+String WebInspectorFrontendClient::localizedStringsURL()
 {
     // Call the soft link framework function to dlopen it, then [NSBundle bundleWithIdentifier:] will work.
-    WebInspectorLibrary();
-
-    if (![[NSBundle bundleWithIdentifier:@"com.apple.WebInspector"] pathForResource:@"Main" ofType:@"html"])
-        return true;
-
-    if (![[NSBundle bundleWithIdentifier:@"com.apple.WebCore"] pathForResource:@"inspector" ofType:@"html" inDirectory:@"inspector"])
-        return false;
-
-    return [[NSUserDefaults standardUserDefaults] boolForKey:@"UseWebKitWebInspector"];
-}
+    WebInspectorUILibrary();
 
-String WebInspectorFrontendClient::localizedStringsURL()
-{
-    NSBundle *bundle = useWebKitWebInspector() ? [NSBundle bundleWithIdentifier:@"com.apple.WebCore"] : [NSBundle bundleWithIdentifier:@"com.apple.WebInspector"]; 
-    NSString *path = [bundle pathForResource:@"localizedStrings" ofType:@"js"];
+    NSString *path = [[NSBundle bundleWithIdentifier:@"com.apple.WebInspectorUI"] pathForResource:@"localizedStrings" ofType:@"js"];
     if ([path length])
         return [[NSURL fileURLWithPath:path] absoluteString];
     return String();
@@ -258,7 +266,7 @@ void WebInspectorFrontendClient::disconnectFromBackend()
     [m_windowController.get() destroyInspectorView:false];
 }
 
-void WebInspectorFrontendClient::attachWindow()
+void WebInspectorFrontendClient::attachWindow(DockSide)
 {
     if ([m_windowController.get() attached])
         return;
@@ -276,6 +284,16 @@ void WebInspectorFrontendClient::setAttachedWindowHeight(unsigned height)
     [m_windowController.get() setAttachedWindowHeight:height];
 }
 
+void WebInspectorFrontendClient::setAttachedWindowWidth(unsigned)
+{
+    // Dock to right is not implemented in WebKit 1.
+}
+
+void WebInspectorFrontendClient::setToolbarHeight(unsigned height)
+{
+    [[m_windowController window] setContentBorderThickness:height forEdge:NSMaxYEdge];
+}
+
 void WebInspectorFrontendClient::inspectedURLChanged(const String& newURL)
 {
     m_inspectedURL = newURL;
@@ -288,28 +306,50 @@ void WebInspectorFrontendClient::updateWindowTitle() const
     [[m_windowController.get() window] setTitle:title];
 }
 
-void WebInspectorFrontendClient::save(const String& refURL, const String& refContent, bool forceSaveAs)
+void WebInspectorFrontendClient::save(const String& suggestedURL, const String& content, bool base64Encoded, bool forceSaveDialog)
 {
-    String url = refURL;
-    String content = refContent;
-    auto saveToURL = ^(NSURL *URL) {
-        m_saveURLs.set(url, URL);
+    ASSERT(!suggestedURL.isEmpty());
+
+    NSURL *platformURL = m_suggestedToActualURLMap.get(suggestedURL).get();
+    if (!platformURL) {
+        platformURL = [NSURL URLWithString:suggestedURL];
+        // The user must confirm new filenames before we can save to them.
+        forceSaveDialog = true;
+    }
+
+    ASSERT(platformURL);
+    if (!platformURL)
+        return;
+
+    // Necessary for the block below.
+    String suggestedURLCopy = suggestedURL;
+    String contentCopy = content;
+
+    auto saveToURL = ^(NSURL *actualURL) {
+        ASSERT(actualURL);
+
+        m_suggestedToActualURLMap.set(suggestedURLCopy, actualURL);
+
+        if (base64Encoded) {
+            Vector<char> out;
+            if (!base64Decode(contentCopy, out, Base64FailOnInvalidCharacterOrExcessPadding))
+                return;
+            RetainPtr<NSData> dataContent = adoptNS([[NSData alloc] initWithBytes:out.data() length:out.size()]);
+            [dataContent writeToURL:actualURL atomically:YES];
+        } else
+            [contentCopy writeToURL:actualURL atomically:YES encoding:NSUTF8StringEncoding error:NULL];
 
-        [content writeToURL:URL atomically:YES encoding:NSUTF8StringEncoding error:NULL];
-        core([m_windowController webView])->mainFrame()->script()->executeScript([NSString stringWithFormat:@"InspectorFrontendAPI.savedURL(\"%@\")", URL.absoluteString]);
+        core([m_windowController webView])->mainFrame().script().executeScript([NSString stringWithFormat:@"InspectorFrontendAPI.savedURL(\"%@\")", actualURL.absoluteString]);
     };
 
-    NSURL *URL = m_saveURLs.get(url).get();
-    if (!URL)
-        URL = [NSURL URLWithString:url];
-    else if (!forceSaveAs) {
-        saveToURL(URL);
+    if (!forceSaveDialog) {
+        saveToURL(platformURL);
         return;
     }
 
     NSSavePanel *panel = [NSSavePanel savePanel];
-    panel.nameFieldStringValue = URL.lastPathComponent;
-    panel.directoryURL = [URL URLByDeletingLastPathComponent];
+    panel.nameFieldStringValue = platformURL.lastPathComponent;
+    panel.directoryURL = [platformURL URLByDeletingLastPathComponent];
 
     [panel beginSheetModalForWindow:[[m_windowController webView] window] completionHandler:^(NSInteger result) {
         if (result == NSFileHandlingPanelCancelButton)
@@ -319,18 +359,21 @@ void WebInspectorFrontendClient::save(const String& refURL, const String& refCon
     }];
 }
 
-void WebInspectorFrontendClient::append(const String& url, const String& content)
+void WebInspectorFrontendClient::append(const String& suggestedURL, const String& content)
 {
-    RetainPtr<NSURL> URL = m_saveURLs.get(url);
-    if (!URL)
-        URL = [NSURL URLWithString:url];
+    ASSERT(!suggestedURL.isEmpty());
 
-    NSFileHandle *handle = [NSFileHandle fileHandleForWritingToURL:URL.get() error:NULL];
+    RetainPtr<NSURL> actualURL = m_suggestedToActualURLMap.get(suggestedURL);
+    // do not append unless the user has already confirmed this filename in save().
+    if (!actualURL)
+        return;
+
+    NSFileHandle *handle = [NSFileHandle fileHandleForWritingToURL:actualURL.get() error:NULL];
     [handle seekToEndOfFile];
     [handle writeData:[content dataUsingEncoding:NSUTF8StringEncoding]];
     [handle closeFile];
 
-    core([m_windowController webView])->mainFrame()->script()->executeScript([NSString stringWithFormat:@"InspectorFrontendAPI.appendedToURL(\"%@\")", [URL absoluteString]]);
+    core([m_windowController webView])->mainFrame().script().executeScript([NSString stringWithFormat:@"InspectorFrontendAPI.appendedToURL(\"%@\")", [actualURL absoluteString]]);
 }
 
 // MARK: -
@@ -368,20 +411,22 @@ void WebInspectorFrontendClient::append(const String& url, const String& content
 
     [preferences release];
 
-    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL fileURLWithPath:[self inspectorPagePath]]];
-    [[_webView mainFrame] loadRequest:request];
-    [request release];
-
     [self setWindowFrameAutosaveName:@"Web Inspector 2"];
     return self;
 }
 
-- (id)initWithInspectedWebView:(WebView *)webView
+- (id)initWithInspectedWebView:(WebView *)webView isUnderTest:(BOOL)isUnderTest
 {
     if (!(self = [self init]))
         return nil;
 
     _inspectedWebView = webView;
+
+    NSString *pagePath = isUnderTest ? [self inspectorTestPagePath] : [self inspectorPagePath];
+    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL fileURLWithPath: pagePath]];
+    [[_webView mainFrame] loadRequest:request];
+    [request release];
+
     return self;
 }
 
@@ -395,16 +440,28 @@ void WebInspectorFrontendClient::append(const String& url, const String& content
 
 - (NSString *)inspectorPagePath
 {
-    NSString *path;
-    if (useWebKitWebInspector())
-        path = [[NSBundle bundleWithIdentifier:@"com.apple.WebCore"] pathForResource:@"inspector" ofType:@"html" inDirectory:@"inspector"];
-    else
-        path = [[NSBundle bundleWithIdentifier:@"com.apple.WebInspector"] pathForResource:@"Main" ofType:@"html"];
+    // Call the soft link framework function to dlopen it, then [NSBundle bundleWithIdentifier:] will work.
+    WebInspectorUILibrary();
 
+    NSString *path = [[NSBundle bundleWithIdentifier:@"com.apple.WebInspectorUI"] pathForResource:@"Main" ofType:@"html"];
     ASSERT([path length]);
     return path;
 }
 
+- (NSString *)inspectorTestPagePath
+{
+    // Call the soft link framework function to dlopen it, then [NSBundle bundleWithIdentifier:] will work.
+    WebInspectorUILibrary();
+
+    NSString *path = [[NSBundle bundleWithIdentifier:@"com.apple.WebInspectorUI"] pathForResource:@"Test" ofType:@"html"];
+
+    // We might not have a Test.html in Production builds.
+    if (!path)
+        return nil;
+
+    return path;
+}
+
 // MARK: -
 
 - (WebView *)webView
@@ -463,7 +520,7 @@ void WebInspectorFrontendClient::append(const String& url, const String& content
     [frameView addSubview:_dockButton.get()];
 
     // Hide the dock button if we can't attach.
-    _dockButton.get().hidden = !_frontendClient->canAttachWindow();
+    _dockButton.get().hidden = !_frontendClient->canAttachWindow() || _inspectorClient->inspectorAttachDisabled();
 
     [self setWindow:window];
     [window release];
@@ -519,7 +576,7 @@ void WebInspectorFrontendClient::append(const String& url, const String& content
 
 - (IBAction)attachWindow:(id)sender
 {
-    _frontendClient->attachWindow();
+    _frontendClient->attachWindow(InspectorFrontendClient::DOCKED_TO_BOTTOM);
 }
 
 - (IBAction)showWindow:(id)sender
@@ -531,11 +588,8 @@ void WebInspectorFrontendClient::append(const String& url, const String& content
     }
 
     _visible = YES;
-    
-    _shouldAttach = _inspectorClient->inspectorStartsAttached();
-    
-    if (_shouldAttach && !_frontendClient->canAttachWindow())
-        _shouldAttach = NO;
+
+    _shouldAttach = _inspectorClient->inspectorStartsAttached() && _frontendClient->canAttachWindow() && !_inspectorClient->inspectorAttachDisabled();
 
     if (_shouldAttach) {
         WebFrameView *frameView = [[_inspectedWebView.get() mainFrame] frameView];
@@ -569,7 +623,7 @@ void WebInspectorFrontendClient::append(const String& url, const String& content
         return;
 
     _inspectorClient->setInspectorStartsAttached(true);
-    _frontendClient->setAttachedWindow(true);
+    _frontendClient->setAttachedWindow(InspectorFrontendClient::DOCKED_TO_BOTTOM);
 
     [self close];
     [self showWindow:nil];
@@ -581,7 +635,7 @@ void WebInspectorFrontendClient::append(const String& url, const String& content
         return;
 
     _inspectorClient->setInspectorStartsAttached(false);
-    _frontendClient->setAttachedWindow(false);
+    _frontendClient->setAttachedWindow(InspectorFrontendClient::UNDOCKED);
 
     [self close];
     [self showWindow:nil];
@@ -646,7 +700,7 @@ void WebInspectorFrontendClient::append(const String& url, const String& content
 
     if (notifyInspectorController) {
         if (Page* inspectedPage = [_inspectedWebView.get() page])
-            inspectedPage->inspectorController()->disconnectFrontend();
+            inspectedPage->inspectorController().disconnectFrontend(Inspector::InspectorDisconnectReason::InspectorDestroyed);
     }
 
     RetainPtr<WebInspectorWindowController> protect(self);
@@ -656,11 +710,6 @@ void WebInspectorFrontendClient::append(const String& url, const String& content
 // MARK: -
 // MARK: UI delegate
 
-- (NSUInteger)webView:(WebView *)sender dragDestinationActionMaskForDraggingInfo:(id <NSDraggingInfo>)draggingInfo
-{
-    return WebDragDestinationActionNone;
-}
-
 - (void)webView:(WebView *)sender runOpenPanelForFileButtonWithResultListener:(id<WebOpenPanelResultListener>)resultListener allowMultipleFiles:(BOOL)allowMultipleFiles
 {
     NSOpenPanel *panel = [NSOpenPanel openPanel];
@@ -684,6 +733,12 @@ void WebInspectorFrontendClient::append(const String& url, const String& content
     }];
 }
 
+- (void)webView:(WebView *)sender frame:(WebFrame *)frame exceededDatabaseQuotaForSecurityOrigin:(WebSecurityOrigin *)origin database:(NSString *)databaseIdentifier
+{
+    id <WebQuotaManager> databaseQuotaManager = origin.databaseQuotaManager;
+    databaseQuotaManager.quota = std::max<unsigned long long>(5 * 1024 * 1024, databaseQuotaManager.usage * 1.25);
+}
+
 // MARK: -
 // MARK: Policy delegate
 
@@ -701,6 +756,13 @@ void WebInspectorFrontendClient::append(const String& url, const String& content
         return;
     }
 
+    // Allow loading of the test inspector file.
+    NSString *testPagePath = [self inspectorTestPagePath];
+    if (testPagePath && [[request URL] isFileURL] && [[[request URL] path] isEqualToString:testPagePath]) {
+        [listener use];
+        return;
+    }
+
     // Prevent everything else from loading in the inspector's page.
     [listener ignore];
 
@@ -752,5 +814,4 @@ void WebInspectorFrontendClient::append(const String& url, const String& content
     return YES;
 }
 
-
 @end