WebCore:
authordarin <darin@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 1 Jun 2005 23:49:50 +0000 (23:49 +0000)
committerdarin <darin@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 1 Jun 2005 23:49:50 +0000 (23:49 +0000)
        Reviewed by John Sullivan.
        No layout tests added because showModalDialog won't work in DumpRenderTree at the moment.

        - WebKit part of fix for <rdar://problem/3166090> add IE JavaScript extension window.showModalDialog

        * khtml/ecma/kjs_window.cpp:
        (KJS::allowPopUp): Added. Used by showModalDialog now and should be used by window.open later.
        (KJS::parseFeatures): Ditto.
        (KJS::boolFeature): Ditto.
        (KJS::intFeature): Ditto.
        (KJS::createNewWindow): Ditto.
        (KJS::canShowModalDialog): Added.
        (KJS::canShowModalDialogNow): Added.
        (KJS::showModalDialog): Added.
        (KJS::Window::get): Return the showModalDialog function object if the extension can run modal.
        (KJS::Window::clear): Add code to store the return value for the case where the window is a modal dialog.
        (KJS::WindowFunc::tryCall): Add the call to the showModalDialog function.

        * khtml/ecma/kjs_window.h: Add setReturnValueSlot function so showModalDialog can get the return
        value from the dialog it creates. Also add a data member to keep track of the pointer and a constant
        for the ShowModalDialog method.

        * khtml/khtml_part.h: Added new changeLocation member function. Made setOpener, openedByJS, and
        setOpenedByJS public.

        * khtml/khtml_part.cpp:
        (KHTMLPart::changeLocation): Broke out the part of slotRedirect that actually does the location change
        into a separate function so it can be called when needed. The case using it now is to load the content
        of a new window in KJS::createNewWindow.
        (KHTMLPart::slotRedirect): Call changeLocation to do most of the work.
        (KHTMLPart::urlSelected): Fixed a broken case where the "lack of referrer" in a new window would cause
        the referrer passed in by JavaScript to be ignored when opening a new window -- match logic elsewhere
        that leaves the referrer in the args alone if one is not set in the window.

        * khtml/khtmlpart_p.h: Initialize m_bCleared to true to avoid an unnecessary clear before loading the
        first URL in a new window. This change is needed to avoid blowing away the "dialogArguments" value in
        a modal dialog window, but it also avoid unnecessary work for each new window.

        * kwq/KWQApplication.h: Add availableGeometry function for QDesktopWidget. Used by the showModalDialog
        function inside kjs_window.cpp (and should be used elsewhere eventually too). Matches a Qt function that
        we just didn't have implemented before.
        * kwq/KWQApplication.mm: (QDesktopWidget::availableGeometry): Added.

        * kwq/KWQKHTMLPartBrowserExtension.h: Added new canRunModal, canRunModalNow, and runModal functions.
        * kwq/KWQKHTMLPartBrowserExtension.mm:
        (KHTMLPartBrowserExtension::createNewWindow): Call createModalDialogWithURL on the bridge if the
        new window is a dialog. Also fixed the early return case for when the bridge returns nil.
        (KHTMLPartBrowserExtension::canRunModal): Added. Calls bridge.
        (KHTMLPartBrowserExtension::canRunModalNow): Ditto.
        (KHTMLPartBrowserExtension::runModal): Ditto.

        * kwq/KWQKPartsBrowserExtension.h:
        (KParts::URLArgs::URLArgs): Initialize m_lockHistory to false.
        (KParts::WindowArgs::WindowArgs): Add a dialog boolean.

        * kwq/WebCoreBridge.h: Declared canRunModal, canRunModalNow, createModalDialogWithURL, and runModal methods.

WebKit:

        Reviewed by John Sullivan.

        - WebKit part of fix for <rdar://problem/3166090> add IE JavaScript extension window.showModalDialog

        * WebCoreSupport.subproj/WebBridge.m:
        (-[WebBridge createModalDialogWithURL:]): Added. Calls the UI delegate, falling back to the generic
        "create WebView" method.
        (-[WebBridge canRunModal]): Added. Checks the UI delegate to see if it implements runModal.
        (-[WebBridge canRunModalNow]): Added. Checks the "inConnectionCallback" field so we can prevent
        deadlock since we can't do any I/O while inside a connection callback until this aspect of NSURLConnection
        is changed.
        (-[WebBridge runModal]): Added. Sets "defersCallbacks" on all other web views in the group, then
        calls runModal on the UI delegate.

        * WebView.subproj/WebBaseResourceHandleDelegate.h: Added inConnectionCallback class method.
        * WebView.subproj/WebBaseResourceHandleDelegate.m:
        (-[WebBaseResourceHandleDelegate connection:willSendRequest:redirectResponse:]): Bump count and then
        decrement count so we can tell if we are in a callback.
        (-[WebBaseResourceHandleDelegate connection:didReceiveAuthenticationChallenge:]): Ditto.
        (-[WebBaseResourceHandleDelegate connection:didCancelAuthenticationChallenge:]): Ditto.
        (-[WebBaseResourceHandleDelegate connection:didReceiveResponse:]): Ditto.
        (-[WebBaseResourceHandleDelegate connection:didReceiveData:lengthReceived:]): Ditto.
        (-[WebBaseResourceHandleDelegate connection:willStopBufferingData:]): Ditto.
        (-[WebBaseResourceHandleDelegate connectionDidFinishLoading:]): Ditto.
        (-[WebBaseResourceHandleDelegate connection:didFailWithError:]): Ditto.
        (-[WebBaseResourceHandleDelegate connection:willCacheResponse:]): Ditto.
        (+[WebBaseResourceHandleDelegate inConnectionCallback]): Added. Return YES if count is not 0.

        * WebView.subproj/WebMainResourceClient.m:
        (-[WebMainResourceClient receivedError:]): Changed to use the method without the connection: parameter
        in the base class, since we no longer are overriding the connection: version.
        (-[WebMainResourceClient willSendRequest:redirectResponse:]): Change to override the version without
        the connection prefix/parameter; now only the base class overrides the actual connection delegate methods.
        (-[WebMainResourceClient continueAfterContentPolicy:response:]): Ditto.
        (-[WebMainResourceClient didReceiveResponse:]): Ditto.
        (-[WebMainResourceClient didReceiveData:lengthReceived:]): Ditto.
        (-[WebMainResourceClient didFinishLoading]): Ditto.
        (-[WebMainResourceClient didFailWithError:]): Ditto.
        (-[WebMainResourceClient loadWithRequestNow:]): Call the method without the connection parameter.

        * WebView.subproj/WebUIDelegatePrivate.h: Added new SPI here that WebBrowser implements.

WebBrowser:

        Reviewed by John.

        - WebBrowser part of fix for <rdar://problem/3166090> add IE JavaScript extension window.showModalDialog

        * AppController.m: (-[AppController validateUserInterfaceItem:]): Disable the find panel
        when there's a modal panel up.
        * BrowserApplication.m: (-[BrowserApplication nextEventMatchingMask:untilDate:inMode:dequeue:]):
        Force the event loop to use the default run loop mode instead of the modal panel mode for
        modal BrowserWindows. This is required to work around the WebFoundation issue where it will
        only give us data in the default run loop mode.
        * BrowserDocument.m:
        (-[BrowserDocument canAddBookmark]): Return NO when a modal window is up.
        (-[BrowserDocument canViewSource]): Ditto.
        (-[BrowserDocument canMailPage]): Ditto.
        (-[BrowserDocument canMailPageAddress]): Ditto.
        (-[BrowserDocument canOpenInDashboard]): Ditto.
        (-[BrowserDocument canSave]): Ditto.
        (-[BrowserDocument validateUserInterfaceItem:]): Disable save commands when modal window is up.
        Also implement validation for all three of the save commands that we implement.
        * BrowserDocumentController.m: (-[BrowserDocumentController validateUserInterfaceItem:]):
        Disable newTab: when modal window is up.
        * BrowserWebView.m:
        (-[BrowserWebView webView:createWebViewModalDialogWithRequest:]): Added. Creates a window that
        has no toolbar, which is an efficient way to disable all the toolbar-related commands for that
        window, even ones built into AppKit which otherwise would be difficult to disable.
        (-[BrowserWebView webViewRunModal:]): Added. Currently just calls -[NSApplication runModalForWindow:]
        but could do more in the future. More importantly, having this implemented is how the Web Kit can
        tell that this application supports modal web dialogs.
        (-[BrowserWebView validateUserInterfaceItem:]): Disable setPageForSnapBackToCurrentPage: for
        modal windows.
        * BrowserWindow.m: (-[BrowserWindow close]): Abort the modal session if the window being closed is
        the modal window. This is the only way we return from webViewRunModal:.
        * BrowserWindowController.m:
        (-[BrowserWindowController canShowInputFields]): Return no when this window is modal.
        (-[BrowserWindowController validateUserInterfaceItem:]): Disable newTab: and newBookmarkFolder: when
        modal window is up.
        (-[BrowserWindowController validateMenuItem:]): Disable Show/Hide of address bar, bookmarks bar,
        bookmarks collection, and toggleFullScreen: when modal window is up.
        (-[BrowserWindowController showWindow:]): Change code so that a new window always comes up behind
        a modal window. Also rearranged things so that setWindowFocusDisabled:YES will be called in any
        case where the window does not start out as key.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@9250 268f45cc-cd09-0410-ab3c-d52691b4dbfc

21 files changed:
WebCore/ChangeLog-2005-08-23
WebCore/khtml/ecma/kjs_window.cpp
WebCore/khtml/ecma/kjs_window.h
WebCore/khtml/khtml_part.cpp
WebCore/khtml/khtml_part.h
WebCore/khtml/khtmlpart_p.h
WebCore/kwq/KWQApplication.h
WebCore/kwq/KWQApplication.mm
WebCore/kwq/KWQKHTMLPartBrowserExtension.h
WebCore/kwq/KWQKHTMLPartBrowserExtension.mm
WebCore/kwq/KWQKPartsBrowserExtension.h
WebCore/kwq/WebCoreBridge.h
WebKit/ChangeLog
WebKit/WebCoreSupport.subproj/WebBridge.m
WebKit/WebView.subproj/WebBaseResourceHandleDelegate.h
WebKit/WebView.subproj/WebBaseResourceHandleDelegate.m
WebKit/WebView.subproj/WebLoader.h
WebKit/WebView.subproj/WebLoader.m
WebKit/WebView.subproj/WebMainResourceClient.m
WebKit/WebView.subproj/WebMainResourceLoader.m
WebKit/WebView.subproj/WebUIDelegatePrivate.h

index 5dbe93899a933a0833a3b83277a9bf3f0d468dc6..d9703e1c24f6293a8f0283b2c550c4a5bc75d7fc 100644 (file)
@@ -1,3 +1,62 @@
+2005-06-01  Darin Adler  <darin@apple.com>
+
+        Reviewed by John Sullivan.
+        No layout tests added because showModalDialog won't work in DumpRenderTree at the moment.
+
+        - WebKit part of fix for <rdar://problem/3166090> add IE JavaScript extension window.showModalDialog
+
+        * khtml/ecma/kjs_window.cpp:
+        (KJS::allowPopUp): Added. Used by showModalDialog now and should be used by window.open later.
+        (KJS::parseFeatures): Ditto.
+        (KJS::boolFeature): Ditto.
+        (KJS::intFeature): Ditto.
+        (KJS::createNewWindow): Ditto.
+        (KJS::canShowModalDialog): Added.
+        (KJS::canShowModalDialogNow): Added.
+        (KJS::showModalDialog): Added.
+        (KJS::Window::get): Return the showModalDialog function object if the extension can run modal.
+        (KJS::Window::clear): Add code to store the return value for the case where the window is a modal dialog.
+        (KJS::WindowFunc::tryCall): Add the call to the showModalDialog function.
+
+        * khtml/ecma/kjs_window.h: Add setReturnValueSlot function so showModalDialog can get the return
+        value from the dialog it creates. Also add a data member to keep track of the pointer and a constant
+        for the ShowModalDialog method.
+
+        * khtml/khtml_part.h: Added new changeLocation member function. Made setOpener, openedByJS, and
+        setOpenedByJS public.
+
+        * khtml/khtml_part.cpp:
+        (KHTMLPart::changeLocation): Broke out the part of slotRedirect that actually does the location change
+        into a separate function so it can be called when needed. The case using it now is to load the content
+        of a new window in KJS::createNewWindow.
+        (KHTMLPart::slotRedirect): Call changeLocation to do most of the work.
+        (KHTMLPart::urlSelected): Fixed a broken case where the "lack of referrer" in a new window would cause
+        the referrer passed in by JavaScript to be ignored when opening a new window -- match logic elsewhere
+        that leaves the referrer in the args alone if one is not set in the window.
+
+        * khtml/khtmlpart_p.h: Initialize m_bCleared to true to avoid an unnecessary clear before loading the
+        first URL in a new window. This change is needed to avoid blowing away the "dialogArguments" value in
+        a modal dialog window, but it also avoid unnecessary work for each new window.
+
+        * kwq/KWQApplication.h: Add availableGeometry function for QDesktopWidget. Used by the showModalDialog
+        function inside kjs_window.cpp (and should be used elsewhere eventually too). Matches a Qt function that
+        we just didn't have implemented before.
+        * kwq/KWQApplication.mm: (QDesktopWidget::availableGeometry): Added.
+
+        * kwq/KWQKHTMLPartBrowserExtension.h: Added new canRunModal, canRunModalNow, and runModal functions.
+        * kwq/KWQKHTMLPartBrowserExtension.mm:
+        (KHTMLPartBrowserExtension::createNewWindow): Call createModalDialogWithURL on the bridge if the
+        new window is a dialog. Also fixed the early return case for when the bridge returns nil.
+        (KHTMLPartBrowserExtension::canRunModal): Added. Calls bridge.
+        (KHTMLPartBrowserExtension::canRunModalNow): Ditto.
+        (KHTMLPartBrowserExtension::runModal): Ditto.
+
+        * kwq/KWQKPartsBrowserExtension.h:
+        (KParts::URLArgs::URLArgs): Initialize m_lockHistory to false.
+        (KParts::WindowArgs::WindowArgs): Add a dialog boolean.
+
+        * kwq/WebCoreBridge.h: Declared canRunModal, canRunModalNow, createModalDialogWithURL, and runModal methods.
+
 2005-06-01  Adele Peterson  <adele@apple.com>
 
         fix for <rdar://problem/4135705> REGRESSION (412-TOT) crash in TV Tracker widget - KJS::XMLHttpRequest::removeFromRequestsByDocument()
index 3185423397167a93a8c6f16bbdc02895ffd8e004..7192cdf2e38a4f394da6b6d1f69c45872c75ef78 100644 (file)
@@ -54,6 +54,7 @@
 
 #include "khtmlview.h"
 #include "khtml_part.h"
+#include "khtml_ext.h"
 #include "dom/dom_string.h"
 #include "dom/dom_node.h"
 #include "editing/htmlediting.h"
@@ -85,6 +86,10 @@ using DOM::Position;
 
 using khtml::TypingCommand;
 
+using KParts::ReadOnlyPart;
+using KParts::URLArgs;
+using KParts::WindowArgs;
+
 using std::isnan;
 
 namespace KJS {
@@ -311,6 +316,7 @@ const ClassInfo Window::info = { "Window", 0, &WindowTable, 0 };
   onsubmit     Window::Onsubmit        DontDelete
   onunload     Window::Onunload        DontDelete
   frameElement  Window::FrameElement    DontDelete|ReadOnly
+  showModalDialog Window::ShowModalDialog    DontDelete|Function 1
 @end
 */
 IMPLEMENT_PROTOFUNC(WindowFunc)
@@ -477,6 +483,206 @@ UString Window::toString(ExecState *) const
   return "[object Window]";
 }
 
+static bool allowPopUp(ExecState *exec, Window *window)
+{
+#if APPLE_CHANGES
+    return window->part()
+        && (window->part()->settings()->JavaScriptCanOpenWindowsAutomatically()
+            || static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture());
+#else    
+    KConfig config("konquerorrc");
+    config.setGroup("Java/JavaScript Settings");
+    switch (config.readUnsignedNumEntry("WindowOpenPolicy", 0)) { // 0=allow, 1=ask, 2=deny, 3=smart
+        default:
+        case 0: // allow
+            return true;
+        case 1: // ask
+            return KMessageBox::questionYesNo(widget,
+                i18n("This site is trying to open up a new browser window using Javascript.\n"
+                     "Do you want to allow this?"),
+                i18n("Confirmation: Javascript Popup")) == KMessageBox::Yes;
+        case 2: // deny
+            return false;
+        case 3: // smart
+            return static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
+    }
+#endif
+}
+
+static QMap<QString, QString> parseFeatures(ExecState *exec, ValueImp *featuresArg)
+{
+    QMap<QString, QString> map;
+
+    QStringList features = QStringList::split(';', featuresArg->dispatchToString(exec).qstring());
+    QStringList::ConstIterator end = features.end();
+    for (QStringList::ConstIterator it = features.begin(); it != end; ++it) {
+        QString s = *it;
+        int pos = s.find('=');
+        if (pos < 0) {
+            // null string for value means key without value
+            map.insert(s.stripWhiteSpace().lower(), QString());
+        } else {
+            QString key = s.left(pos).stripWhiteSpace().lower();
+            QString val = s.mid(pos + 1).stripWhiteSpace().lower();
+            int spacePos = val.find(' ');
+            if (spacePos != -1)
+                val = val.left(spacePos);
+            map.insert(key, val);
+        }
+    }
+
+    return map;
+}
+
+static bool boolFeature(const QMap<QString, QString> &features, const char *key, bool defaultValue = false)
+{
+    QMap<QString, QString>::ConstIterator it = features.find(key);
+    if (it == features.end())
+        return defaultValue;
+    QString value = it.data();
+    return value.isNull() || value == "1" || value == "yes" || value == "on";
+}
+
+static int intFeature(const QMap<QString, QString> &features, const char *key, int min, int max, int defaultValue)
+{
+    QMap<QString, QString>::ConstIterator it = features.find(key);
+    if (it == features.end())
+        return defaultValue;
+    QString value = it.data();
+    // FIXME: Can't distinguish "0q" from string with no digits in it -- both return d == 0 and ok == false.
+    // Would be good to tell them apart somehow since string with no digits should be default value and
+    // "0q" should be minimum value.
+    bool ok;
+    double d = value.toDouble(&ok);
+    if ((d == 0 && !ok) || isnan(d))
+        return defaultValue;
+    if (d < min || max <= min)
+        return min;
+    if (d > max)
+        return max;
+    return static_cast<int>(d);
+}
+
+static KHTMLPart *createNewWindow(ExecState *exec, Window *openerWindow, const QString &URL,
+    const QString &frameName, const WindowArgs &windowArgs, ValueImp *dialogArgs)
+{
+    KHTMLPart *openerPart = openerWindow->part();
+    KHTMLPart *activePart = Window::retrieveActive(exec)->part();
+
+    URLArgs uargs;
+
+    uargs.frameName = frameName;
+    if (activePart)
+        uargs.metaData()["referrer"] = activePart->referrer();
+    uargs.serviceType = "text/html";
+
+    // FIXME: It's much better for client API if a new window starts with a URL, here where we
+    // know what URL we are going to open. Unfortunately, this code passes the empty string
+    // for the URL, but there's a reason for that. Before loading we have to set up the opener,
+    // openedByJS, and dialogArguments values. Also, to decide whether to use the URL we currently
+    // do an isSafeScript call using the window we create, which can't be done before creating it.
+    // We'd have to resolve all those issues to pass the URL instead of "".
+
+    ReadOnlyPart *newReadOnlyPart = 0;
+    emit openerPart->browserExtension()->createNewWindow("", uargs, windowArgs, newReadOnlyPart);
+
+    if (!newReadOnlyPart || !newReadOnlyPart->inherits("KHTMLPart"))
+        return 0;
+
+    KHTMLPart *newPart = static_cast<KHTMLPart *>(newReadOnlyPart);
+    Window *newWindow = Window::retrieveWindow(newPart);
+
+    newPart->setOpener(openerPart);
+    newPart->setOpenedByJS(true);
+    if (dialogArgs)
+        newWindow->putDirect("dialogArguments", dialogArgs);
+
+    DocumentImpl *activeDoc = activePart ? activePart->xmlDocImpl() : 0;
+    if (!URL.isEmpty() && activeDoc) {
+        QString completedURL = activeDoc->completeURL(URL);
+        if (!completedURL.startsWith("javascript:", false) || newWindow->isSafeScript(exec)) {
+            bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
+            newPart->changeLocation(completedURL, activePart->referrer(), false, userGesture);
+        }
+    }
+
+    return newPart;
+}
+
+static bool canShowModalDialog(const Window *window)
+{
+    KHTMLPart *part = window->part();
+    return part && static_cast<KHTMLPartBrowserExtension *>(part->browserExtension())->canRunModal();
+}
+
+static bool canShowModalDialogNow(const Window *window)
+{
+    KHTMLPart *part = window->part();
+    return part && static_cast<KHTMLPartBrowserExtension *>(part->browserExtension())->canRunModalNow();
+}
+
+static ValueImp *showModalDialog(ExecState *exec, Window *openerWindow, const List &args)
+{
+    UString URL = args[0].toString(exec);
+
+    if (!canShowModalDialogNow(openerWindow) || !allowPopUp(exec, openerWindow))
+        return Undefined().imp();
+    
+    const QMap<QString, QString> features = parseFeatures(exec, args[2]);
+
+    bool trusted = false;
+
+    WindowArgs wargs;
+
+    // The following features from Microsoft's documentation are not implemented:
+    // - default font settings
+    // - width, height, left, and top specified in units other than "px"
+    // - edge (sunken or raised, default is raised)
+    // - dialogHide: trusted && boolFeature(features, "dialoghide"), makes dialog hide when you print
+    // - help: boolFeature(features, "help", true), makes help icon appear in dialog (what does it do on Windows?)
+    // - unadorned: trusted && boolFeature(features, "unadorned");
+
+    QRect screenRect = QApplication::desktop()->availableGeometry(openerWindow->part()->view());
+
+    wargs.width = intFeature(features, "dialogwidth", 100, screenRect.width(), 620); // default here came from frame size of dialog in MacIE
+    wargs.widthSet = true;
+    wargs.height = intFeature(features, "dialogheight", 100, screenRect.height(), 450); // default here came from frame size of dialog in MacIE
+    wargs.heightSet = true;
+
+    wargs.x = intFeature(features, "dialogleft", screenRect.x(), screenRect.x() + screenRect.width() - wargs.width, -1);
+    wargs.xSet = wargs.x > 0;
+    wargs.y = intFeature(features, "dialogtop", screenRect.y(), screenRect.y() + screenRect.height() - wargs.height, -1);
+    wargs.ySet = wargs.y > 0;
+
+    if (boolFeature(features, "center", true)) {
+        if (!wargs.xSet) {
+            wargs.x = screenRect.x() + (screenRect.width() - wargs.width) / 2;
+            wargs.xSet = true;
+        }
+        if (!wargs.ySet) {
+            wargs.y = screenRect.y() + (screenRect.height() - wargs.height) / 2;
+            wargs.ySet = true;
+        }
+    }
+       
+    wargs.dialog = true;
+    wargs.resizable = boolFeature(features, "resizable");
+    wargs.scrollbarsVisible = boolFeature(features, "scroll", true);
+    wargs.statusBarVisible = boolFeature(features, "status", !trusted);
+    wargs.toolBarsVisible = false;
+
+    KHTMLPart *dialogPart = createNewWindow(exec, openerWindow, URL.qstring(), "", wargs, args[1]);
+    if (!dialogPart)
+        return Undefined().imp();
+
+    Window *dialogWindow = Window::retrieveWindow(dialogPart);
+    ValueImp *returnValue = Undefined().imp();
+    dialogWindow->setReturnValueSlot(&returnValue);
+    static_cast<KHTMLPartBrowserExtension *>(dialogPart->browserExtension())->runModal();
+    dialogWindow->setReturnValueSlot(NULL);
+    return returnValue;
+}
+
 Value Window::get(ExecState *exec, const Identifier &p) const
 {
 #ifdef KJS_VERBOSE
@@ -687,6 +893,10 @@ Value Window::get(ExecState *exec, const Identifier &p) const
     case Blur:
     case Close:
        return lookupOrCreateFunction<WindowFunc>(exec,p,this,entry->value,entry->params,entry->attr);
+    case ShowModalDialog:
+        if (!canShowModalDialog(this))
+            return Undefined();
+        // fall through
     case Alert:
     case Confirm:
     case Prompt:
@@ -1332,9 +1542,12 @@ JSLazyEventListener *Window::getJSLazyEventListener(const QString& code, DOM::No
 void Window::clear( ExecState *exec )
 {
   KJS::Interpreter::lock();
+  if (m_returnValueSlot)
+    if (ValueImp *returnValue = getDirect("returnValue"))
+      *m_returnValueSlot = returnValue;
   kdDebug(6070) << "Window::clear " << this << endl;
   delete winq;
-  winq = new WindowQObject(this);;
+  winq = new WindowQObject(this);
   // Get rid of everything, those user vars could hold references to DOM nodes
   deleteAllProperties( exec );
   // Really delete those properties, so that the DOM nodes get deref'ed
@@ -1859,7 +2072,8 @@ Value WindowFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
         }
         return Undefined();
     }
-
+  case Window::ShowModalDialog:
+    return showModalDialog(exec, window, args);
   }
   return Undefined();
 }
index 4fe63de62085f71b0444c8f27df1421be7eee4f1..424378a43d36603efcdd585b7448c27fd681c043 100644 (file)
@@ -127,6 +127,9 @@ namespace KJS {
     // Set the current "event" object
     void setCurrentEvent(DOM::EventImpl *evt);
 
+    // Set a place to put a dialog return value when the window is cleared.
+    void setReturnValueSlot(ValueImp **slot) { m_returnValueSlot = slot; }
+
     QPtrDict<JSEventListener> jsEventListeners;
     QPtrDict<JSUnprotectedEventListener> jsUnprotectedEventListeners;
     virtual const ClassInfo* classInfo() const { return &info; }
@@ -145,7 +148,7 @@ namespace KJS {
           Onfocus, Onkeydown, Onkeypress, Onkeyup, Onload, Onmousedown, Onmousemove,
            Onmouseout, Onmouseover, Onmouseup, OnWindowMouseWheel, Onmove, Onreset, Onresize, Onscroll, Onsearch,
            Onselect, Onsubmit, Onunload,
-           Statusbar, Toolbar, FrameElement };
+           Statusbar, Toolbar, FrameElement, ShowModalDialog };
   protected:
     Value getListener(ExecState *exec, int eventId) const;
     void setListener(ExecState *exec, int eventId, Value func);
@@ -166,6 +169,7 @@ namespace KJS {
     BarInfo *m_toolbar;
     WindowQObject *winq;
     DOM::EventImpl *m_evt;
+    ValueImp **m_returnValueSlot;
   };
 
   /**
index e0d4ea9eba31c6c2a8b5436c86bf24c4d4fc3c9d..ec06e1c2ed1a0f9144187e3fa2fb559b672cae82 100644 (file)
@@ -2107,6 +2107,30 @@ void KHTMLPart::cancelRedirection(bool cancelWithLoadInProgress)
     }
 }
 
+void KHTMLPart::changeLocation(const QString &URL, const QString &referrer, bool lockHistory, bool userGesture)
+{
+    if (URL.find("javascript:", 0, false) == 0) {
+        QString script = KURL::decode_string(URL.mid(11));
+        QVariant result = executeScript(script, userGesture);
+        if (result.type() == QVariant::String) {
+            begin(url());
+            write(result.asString());
+            end();
+        }
+        return;
+    }
+
+    KParts::URLArgs args;
+
+    if (urlcmp(URL, m_url.url(), true, false))
+        args.reload = true;
+    args.setLockHistory(lockHistory);
+    if (!referrer.isEmpty())
+        args.metaData()["referrer"] = referrer;
+
+    urlSelected(URL, 0, 0, "_self", args);
+}
+
 void KHTMLPart::slotRedirect()
 {
     if (d->m_scheduledRedirection == historyNavigationScheduled) {
@@ -2127,34 +2151,18 @@ void KHTMLPart::slotRedirect()
         }
         return;
     }
-  
-  QString u = d->m_redirectURL;
 
-  d->m_scheduledRedirection = noRedirectionScheduled;
-  d->m_delayRedirect = 0;
-  d->m_redirectURL = QString::null;
-  if ( u.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
-  {
-    QString script = KURL::decode_string( u.right( u.length() - 11 ) );
-    //kdDebug( 6050 ) << "KHTMLPart::slotRedirect script=" << script << endl;
-    QVariant res = executeScript( script, d->m_redirectUserGesture );
-    if ( res.type() == QVariant::String ) {
-      begin( url() );
-      write( res.asString() );
-      end();
-    }
-    return;
-  }
-  KParts::URLArgs args;
-  if ( urlcmp( u, m_url.url(), true, false ) )
-    args.reload = true;
+    QString URL = d->m_redirectURL;
+    QString referrer = d->m_redirectReferrer;
+    bool lockHistory = d->m_redirectLockHistory;
+    bool userGesture = d->m_redirectUserGesture;
 
-  args.setLockHistory( d->m_redirectLockHistory );
-  if (!d->m_redirectReferrer.isEmpty())
-    args.metaData()["referrer"] = d->m_redirectReferrer;
-  d->m_redirectReferrer = QString::null;
+    d->m_scheduledRedirection = noRedirectionScheduled;
+    d->m_delayRedirect = 0;
+    d->m_redirectURL = QString::null;
+    d->m_redirectReferrer = QString::null;
 
-  urlSelected( u, 0, 0, "_self", args );
+    changeLocation(URL, referrer, lockHistory, userGesture);
 }
 
 void KHTMLPart::slotRedirection(KIO::Job*, const KURL& url)
@@ -2865,7 +2873,8 @@ void KHTMLPart::urlSelected( const QString &url, int button, int state, const QS
 #endif
 
 #if APPLE_CHANGES
-  args.metaData()["referrer"] = d->m_referrer;
+  if (!d->m_referrer.isEmpty())
+    args.metaData()["referrer"] = d->m_referrer;
   KWQ(this)->urlSelected(cURL, button, state, args);
 #else
   if ( hasTarget )
index d5d1096a8851462e696323f59b60a5bc62155c13..57b5822b32177b9883b8bf3ebff1a484436dc76f 100644 (file)
@@ -401,9 +401,10 @@ public:
   void scheduleRedirection(double delay, const QString &url, bool lockHistory = true);
 
   /**
-   * Schedules a location change.
-   * This is used for JavaScript-triggered location changes.
+   * Make a location change, or schedule one for later.
+   * These are used for JavaScript-triggered location changes.
    */
+  void changeLocation(const QString &URL, const QString &referrer, bool lockHistory = true, bool userGesture = false);
   void scheduleLocationChange(const QString &url, const QString &referrer, bool lockHistory = true, bool userGesture = false);
   bool isScheduledLocationChangePending() const;
 
@@ -1344,13 +1345,13 @@ private:
  public:
 #endif
   KHTMLPart *opener();
+  void setOpener(KHTMLPart *_opener);
+  bool openedByJS();
+  void setOpenedByJS(bool _openedByJS);
 #if APPLE_CHANGES
  private:
 #endif
   long cacheId() const;
-  void setOpener(KHTMLPart *_opener);
-  bool openedByJS();
-  void setOpenedByJS(bool _openedByJS);
 
   void checkEmitLoadEvent();
   void emitLoadEvent();
index c31a3a2784d1cb43638534ccbeb0b8f2c33f7315..ada837d9f65ff1af94fd7fbc37f8dcccf25a8c48 100644 (file)
@@ -128,7 +128,7 @@ public:
     m_settings = new KHTMLSettings(*KHTMLFactory::defaultHTMLSettings());
 #endif
     m_bClearing = false;
-    m_bCleared = false;
+    m_bCleared = true;
     m_zoomFactor = 100;
     m_bDnd = true;
 #if !APPLE_CHANGES
index 88a28de0d5121a920feb77901d6b3ebe53623fa3..b2ea01d34a05cda30dd8e095abe666f68acb535b 100644 (file)
@@ -46,6 +46,7 @@ class QDesktopWidget : public QWidget {
 public:
     static int screenNumber(QWidget *);
     static QRect screenGeometry(int screenNumber);
+    static QRect availableGeometry(QWidget *);
     static int width();
     static int height();
 };
index de0d41c52bab70619a23bc906c92ff99416c22cf..356b3d81cc7d7520976dffb9c08be2cb955f1f5e 100644 (file)
@@ -58,6 +58,16 @@ QRect QDesktopWidget::screenGeometry(int screenNumber)
     return QRect(rect);
 }
 
+QRect QDesktopWidget::availableGeometry(QWidget *widget)
+{
+    NSScreen *screen = widget ? [[widget->getView() window] screen] : nil;
+    if (!screen)
+        screen = [NSScreen mainScreen];
+    NSRect rect = [screen visibleFrame];
+    rect.origin.y = NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]) - NSMaxY(rect);
+    return QRect(rect);
+}
+
 void QApplication::setOverrideCursor(const QCursor &c)
 {
     // FIXME: Should implement this so that frame border dragging has the proper cursor.
index 372ef33cba41a9f051e941134f34637140525f75..00b8e95be19af8da47cbe42d1991076d981c6c12 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
+ * Copyright (C) 2005 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
@@ -24,7 +24,6 @@
  */
 
 #include "KWQKPartsBrowserExtension.h"
-
 #include "KWQKPartsBrowserInterface.h"
 
 class QWidget;
@@ -33,6 +32,7 @@ class KHTMLPart;
 class KHTMLPartBrowserExtension : public KParts::BrowserExtension {
 public:
     KHTMLPartBrowserExtension(KHTMLPart *);
+
     void editableWidgetFocused(QWidget *) { }
     void editableWidgetBlurred(QWidget *) { }
     void setLocationBarURL(const QString &) { }
@@ -52,6 +52,10 @@ public:
 
     virtual void setIconURL(const KURL &url);
     virtual void setTypedIconURL(const KURL &url, const QString &type);
+
+    bool canRunModal();
+    bool canRunModalNow();
+    void runModal();
     
 private:
      void createNewWindow(const KURL &url, 
index 22d99374c0be17211cc2df85cce9eaf1f3b14618..7fc8788b6ddca3737afc9a5378813c746861adc8 100644 (file)
@@ -82,6 +82,10 @@ void KHTMLPartBrowserExtension::createNewWindow(const KURL &url,
         referrer = [_part->bridge() referrer];
     }
 
+    ASSERT(!winArgs.dialog || urlArgs.frameName.isEmpty());
+
+    if (partResult)
+       *partResult = NULL;
 
     if (frameName != nil) {
        bridge = [_part->bridge() findFrameNamed:frameName];
@@ -97,7 +101,12 @@ void KHTMLPartBrowserExtension::createNewWindow(const KURL &url,
        }
     }
     
-    bridge = [_part->bridge() createWindowWithURL:url.getNSURL() frameName:frameName];
+    if (winArgs.dialog)
+        bridge = [_part->bridge() createModalDialogWithURL:url.getNSURL()];
+    else
+        bridge = [_part->bridge() createWindowWithURL:url.getNSURL() frameName:frameName];
+    if (!bridge)
+        return;
     
     if (!winArgs.toolBarsVisible) {
        [bridge setToolbarsVisible:NO];
@@ -150,13 +159,8 @@ void KHTMLPartBrowserExtension::createNewWindow(const KURL &url,
     if (partResult) {
        *partResult = [bridge part];
     }
-    return;
 
     KWQ_UNBLOCK_EXCEPTIONS;
-
-    if (partResult) {
-       *partResult = NULL;
-    }
 }
 
 void KHTMLPartBrowserExtension::setIconURL(const KURL &url)
@@ -172,3 +176,26 @@ void KHTMLPartBrowserExtension::setTypedIconURL(const KURL &url, const QString &
     [_part->bridge() setIconURL:url.getNSURL() withType:type.getNSString()];
     KWQ_UNBLOCK_EXCEPTIONS;
 }
+
+bool KHTMLPartBrowserExtension::canRunModal()
+{
+    KWQ_BLOCK_EXCEPTIONS;
+    return [_part->bridge() canRunModal];
+    KWQ_UNBLOCK_EXCEPTIONS;
+    return false;
+}
+
+bool KHTMLPartBrowserExtension::canRunModalNow()
+{
+    KWQ_BLOCK_EXCEPTIONS;
+    return [_part->bridge() canRunModalNow];
+    KWQ_UNBLOCK_EXCEPTIONS;
+    return false;
+}
+
+void KHTMLPartBrowserExtension::runModal()
+{
+    KWQ_BLOCK_EXCEPTIONS;
+    [_part->bridge() runModal];
+    KWQ_UNBLOCK_EXCEPTIONS;
+}
index fee3380de495c301617a06e79f262e0046d959ba..e8708305487d34471d73a012fcff66b68b1dfbff 100644 (file)
@@ -50,7 +50,7 @@ struct URLArgs {
     int xOffset;
     int yOffset;
 
-    URLArgs() : reload(false), xOffset(0), yOffset(0), m_doPost(false) { }
+    URLArgs() : reload(false), xOffset(0), yOffset(0), m_doPost(false), m_lockHistory(false) { }
     
     QString contentType() const { return m_contentType; }
     void setContentType(const QString &t) { m_contentType = t; }
@@ -88,8 +88,14 @@ struct WindowArgs {
     bool ySet;
     bool widthSet;
     bool heightSet;
-
-    WindowArgs() : x(0), y(0), width(0), height(0), menuBarVisible(false), statusBarVisible(true), toolBarsVisible(true), scrollbarsVisible(true), resizable(true), fullscreen(true), xSet(false), ySet(false), widthSet(false), heightSet(false) { }
+    bool dialog;
+
+    WindowArgs() : x(0), y(0), width(0), height(0),
+        menuBarVisible(false), statusBarVisible(true), toolBarsVisible(true), scrollbarsVisible(true),
+        resizable(true), fullscreen(false),
+        xSet(false), ySet(false), widthSet(false), heightSet(false),
+        dialog(false)
+        { }
 
 };
 
index eee9946b8805758db8125a680f932160ad27be1e..5fceb0dd270200e6a729813bf4848c2cda4e994d 100644 (file)
@@ -471,6 +471,11 @@ typedef enum
 - (WebCoreBridge *)createWindowWithURL:(NSURL *)URL frameName:(NSString *)name;
 - (void)showWindow;
 
+- (BOOL)canRunModal;
+- (BOOL)canRunModalNow;
+- (WebCoreBridge *)createModalDialogWithURL:(NSURL *)URL;
+- (void)runModal;
+
 - (NSString *)userAgentForURL:(NSURL *)URL;
 
 - (void)setTitle:(NSString *)title;
index 84e364d22879dbbc6164019f831c82cd44ece059..f62331cf997d95d043b388d4909233bc5957409b 100644 (file)
@@ -1,3 +1,47 @@
+2005-06-01  Darin Adler  <darin@apple.com>
+
+        Reviewed by John Sullivan.
+
+        - WebKit part of fix for <rdar://problem/3166090> add IE JavaScript extension window.showModalDialog
+
+        * WebCoreSupport.subproj/WebBridge.m:
+        (-[WebBridge createModalDialogWithURL:]): Added. Calls the UI delegate, falling back to the generic
+        "create WebView" method.
+        (-[WebBridge canRunModal]): Added. Checks the UI delegate to see if it implements runModal.
+        (-[WebBridge canRunModalNow]): Added. Checks the "inConnectionCallback" field so we can prevent
+        deadlock since we can't do any I/O while inside a connection callback until this aspect of NSURLConnection
+        is changed.
+        (-[WebBridge runModal]): Added. Sets "defersCallbacks" on all other web views in the group, then
+        calls runModal on the UI delegate.
+
+        * WebView.subproj/WebBaseResourceHandleDelegate.h: Added inConnectionCallback class method.
+        * WebView.subproj/WebBaseResourceHandleDelegate.m:
+        (-[WebBaseResourceHandleDelegate connection:willSendRequest:redirectResponse:]): Bump count and then
+        decrement count so we can tell if we are in a callback.
+        (-[WebBaseResourceHandleDelegate connection:didReceiveAuthenticationChallenge:]): Ditto.
+        (-[WebBaseResourceHandleDelegate connection:didCancelAuthenticationChallenge:]): Ditto.
+        (-[WebBaseResourceHandleDelegate connection:didReceiveResponse:]): Ditto.
+        (-[WebBaseResourceHandleDelegate connection:didReceiveData:lengthReceived:]): Ditto.
+        (-[WebBaseResourceHandleDelegate connection:willStopBufferingData:]): Ditto.
+        (-[WebBaseResourceHandleDelegate connectionDidFinishLoading:]): Ditto.
+        (-[WebBaseResourceHandleDelegate connection:didFailWithError:]): Ditto.
+        (-[WebBaseResourceHandleDelegate connection:willCacheResponse:]): Ditto.
+        (+[WebBaseResourceHandleDelegate inConnectionCallback]): Added. Return YES if count is not 0.
+
+        * WebView.subproj/WebMainResourceClient.m:
+        (-[WebMainResourceClient receivedError:]): Changed to use the method without the connection: parameter
+        in the base class, since we no longer are overriding the connection: version.
+        (-[WebMainResourceClient willSendRequest:redirectResponse:]): Change to override the version without
+        the connection prefix/parameter; now only the base class overrides the actual connection delegate methods.
+        (-[WebMainResourceClient continueAfterContentPolicy:response:]): Ditto.
+        (-[WebMainResourceClient didReceiveResponse:]): Ditto.
+        (-[WebMainResourceClient didReceiveData:lengthReceived:]): Ditto.
+        (-[WebMainResourceClient didFinishLoading]): Ditto.
+        (-[WebMainResourceClient didFailWithError:]): Ditto.
+        (-[WebMainResourceClient loadWithRequestNow:]): Call the method without the connection parameter.
+
+        * WebView.subproj/WebUIDelegatePrivate.h: Added new SPI here that WebBrowser implements.
+
 2005-05-26  Darin Adler  <darin@apple.com>
 
         Reviewed by John.
index 6d827d678a602512b1d79c730487f33fd0741532..76dba8651aa41a26de8ca6f98d2eeabf495560fb 100644 (file)
@@ -10,6 +10,7 @@
 #import <WebKit/WebBaseNetscapePluginView.h>
 #import <WebKit/WebBasePluginPackage.h>
 #import <WebKit/WebBaseResourceHandleDelegate.h>
+#import "WebControllerSets.h"
 #import <WebKit/WebDataSourcePrivate.h>
 #import <WebKit/WebDefaultUIDelegate.h>
 #import <WebKit/WebEditingDelegate.h>
@@ -1598,4 +1599,79 @@ static NSCharacterSet *_getPostSmartSet(void)
     return [isPreviousCharacter ? _getPreSmartSet() : _getPostSmartSet() characterIsMember:c];
 }
 
+- (WebCoreBridge *)createModalDialogWithURL:(NSURL *)URL
+{
+    ASSERT(_frame != nil);
+
+    NSMutableURLRequest *request = nil;
+
+    if (URL != nil && ![URL _web_isEmpty]) {
+       request = [NSMutableURLRequest requestWithURL:URL];
+       [request setHTTPReferrer:[self referrer]];
+    }
+
+    WebView *currentWebView = [_frame webView];
+    id UIDelegate = [currentWebView UIDelegate];
+
+    WebView *newWebView = nil;
+    if ([UIDelegate respondsToSelector:@selector(webView:createWebViewModalDialogWithRequest:)])
+        newWebView = [UIDelegate webView:currentWebView createWebViewModalDialogWithRequest:request];
+    else if ([UIDelegate respondsToSelector:@selector(webView:createWebViewWithRequest:)])
+        newWebView = [UIDelegate webView:currentWebView createWebViewWithRequest:request];
+    else
+        newWebView = [[WebDefaultUIDelegate sharedUIDelegate] webView:currentWebView createWebViewWithRequest:request];
+
+    return [[newWebView mainFrame] _bridge];
+}
+
+- (BOOL)canRunModal
+{
+    WebView *webView = [_frame webView];
+    id UIDelegate = [webView UIDelegate];
+    return [UIDelegate respondsToSelector:@selector(webViewRunModal:)];
+}
+
+- (BOOL)canRunModalNow
+{
+    return [self canRunModal] && ![WebBaseResourceHandleDelegate inConnectionCallback];
+}
+
+- (void)runModal
+{
+    if (![self canRunModal])
+        return;
+
+    WebView *webView = [_frame webView];
+    if ([webView defersCallbacks]) {
+        ERROR("tried to run modal in a view when it was deferring callbacks -- should never happen");
+        return;
+    }
+
+    // Defer callbacks in all the other views in this group, so we don't try to run JavaScript
+    // in a way that could interact with this view.
+    NSMutableArray *deferredWebViews = [NSMutableArray array];
+    NSString *setName = [webView groupName];
+    if (setName) {
+        NSEnumerator *enumerator = [WebViewSets webViewsInSetNamed:setName];
+        WebView *otherWebView;
+        while ((otherWebView = [enumerator nextObject]) != nil) {
+            if (otherWebView != webView && ![otherWebView defersCallbacks]) {
+                [otherWebView setDefersCallbacks:YES];
+                [deferredWebViews addObject:otherWebView];
+            }
+        }
+    }
+
+    // Go run the modal event loop.
+    [[webView UIDelegate] webViewRunModal:webView];
+
+    // Restore the callbacks for any views that we deferred them for.
+    unsigned count = [deferredWebViews count];
+    unsigned i;
+    for (i = 0; i < count; ++i) {
+        WebView *otherWebView = [deferredWebViews objectAtIndex:i];
+        [otherWebView setDefersCallbacks:NO];
+    }
+}
+
 @end
index dd716ca9faa0121ca49854d9691df0896393f30b..20efbc300e3f477b6c779e249a474b8626c874a0 100644 (file)
 - (void)didFailWithError:(NSError *)error;
 - (NSCachedURLResponse *)willCacheResponse:(NSCachedURLResponse *)cachedResponse;
 
+// Used to work around the fact that you don't get any more NSURLConnection callbacks until you return from the first one.
++ (BOOL)inConnectionCallback;
+
 @end
 
 // Note: This interface can be removed once this method is declared
 // in Foundation (probably will be in Foundation-485).
 @interface NSObject (WebBaseResourceHandleDelegateExtras)
 - (void)connection:(NSURLConnection *)con didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived;
-@end
\ No newline at end of file
+@end
index e20e3866f14993c94bb546e9e662a3e5f4a77d16..3db87f7013e0c7f431224bd785db196029684cc0 100644 (file)
@@ -27,6 +27,7 @@
 #import <WebKit/WebResourcePrivate.h>
 #import <WebKit/WebViewPrivate.h>
 
+static unsigned inNSURLConnectionCallback;
 static BOOL NSURLConnectionSupportsBufferedData;
 
 @interface NSURLConnection (NSURLConnectionTigerPrivate)
@@ -572,37 +573,50 @@ static BOOL NSURLConnectionSupportsBufferedData;
 - (NSURLRequest *)connection:(NSURLConnection *)con willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse
 {
     ASSERT(con == connection);
-    return [self willSendRequest:newRequest redirectResponse:redirectResponse];
+    ++inNSURLConnectionCallback;
+    NSURLRequest *result = [self willSendRequest:newRequest redirectResponse:redirectResponse];
+    --inNSURLConnectionCallback;
+    return result;
 }
 
 - (void)connection:(NSURLConnection *)con didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
 {
     ASSERT(con == connection);
+    ++inNSURLConnectionCallback;
     [self didReceiveAuthenticationChallenge:challenge];
+    --inNSURLConnectionCallback;
 }
 
 - (void)connection:(NSURLConnection *)con didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
 {
     ASSERT(con == connection);
+    ++inNSURLConnectionCallback;
     [self didCancelAuthenticationChallenge:challenge];
+    --inNSURLConnectionCallback;
 }
 
 - (void)connection:(NSURLConnection *)con didReceiveResponse:(NSURLResponse *)r
 {
     ASSERT(con == connection);
+    ++inNSURLConnectionCallback;
     [self didReceiveResponse:r];
+    --inNSURLConnectionCallback;
 }
 
 - (void)connection:(NSURLConnection *)con didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived
 {
     ASSERT(con == connection);
+    ++inNSURLConnectionCallback;
     [self didReceiveData:data lengthReceived:lengthReceived];
+    --inNSURLConnectionCallback;
 }
 
 - (void)connection:(NSURLConnection *)con willStopBufferingData:(NSData *)data
 {
     ASSERT(con == connection);
+    ++inNSURLConnectionCallback;
     [self willStopBufferingData:data];
+    --inNSURLConnectionCallback;
 }
 
 - (void)connectionDidFinishLoading:(NSURLConnection *)con
@@ -610,13 +624,17 @@ static BOOL NSURLConnectionSupportsBufferedData;
     // don't worry about checking connection consistency if this load
     // got cancelled while finishing.
     ASSERT(cancelledFlag || con == connection);
+    ++inNSURLConnectionCallback;
     [self didFinishLoading];
+    --inNSURLConnectionCallback;
 }
 
 - (void)connection:(NSURLConnection *)con didFailWithError:(NSError *)error
 {
     ASSERT(con == connection);
+    ++inNSURLConnectionCallback;
     [self didFailWithError:error];
+    --inNSURLConnectionCallback;
 }
 
 - (NSCachedURLResponse *)connection:(NSURLConnection *)con willCacheResponse:(NSCachedURLResponse *)cachedResponse
@@ -626,7 +644,10 @@ static BOOL NSURLConnectionSupportsBufferedData;
         ERROR("connection:willCacheResponse: was called inside of [NSURLConnection initWithRequest:delegate:] (40676250)");
     }
 #endif
-    return [self willCacheResponse:cachedResponse];
+    ++inNSURLConnectionCallback;
+    NSCachedURLResponse *result = [self willCacheResponse:cachedResponse];
+    --inNSURLConnectionCallback;
+    return result;
 }
 
 - (void)cancelWithError:(NSError *)error
@@ -685,4 +706,9 @@ static BOOL NSURLConnectionSupportsBufferedData;
     return response;
 }
 
++ (BOOL)inConnectionCallback
+{
+    return inNSURLConnectionCallback != 0;
+}
+
 @end
index dd716ca9faa0121ca49854d9691df0896393f30b..20efbc300e3f477b6c779e249a474b8626c874a0 100644 (file)
 - (void)didFailWithError:(NSError *)error;
 - (NSCachedURLResponse *)willCacheResponse:(NSCachedURLResponse *)cachedResponse;
 
+// Used to work around the fact that you don't get any more NSURLConnection callbacks until you return from the first one.
++ (BOOL)inConnectionCallback;
+
 @end
 
 // Note: This interface can be removed once this method is declared
 // in Foundation (probably will be in Foundation-485).
 @interface NSObject (WebBaseResourceHandleDelegateExtras)
 - (void)connection:(NSURLConnection *)con didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived;
-@end
\ No newline at end of file
+@end
index e20e3866f14993c94bb546e9e662a3e5f4a77d16..3db87f7013e0c7f431224bd785db196029684cc0 100644 (file)
@@ -27,6 +27,7 @@
 #import <WebKit/WebResourcePrivate.h>
 #import <WebKit/WebViewPrivate.h>
 
+static unsigned inNSURLConnectionCallback;
 static BOOL NSURLConnectionSupportsBufferedData;
 
 @interface NSURLConnection (NSURLConnectionTigerPrivate)
@@ -572,37 +573,50 @@ static BOOL NSURLConnectionSupportsBufferedData;
 - (NSURLRequest *)connection:(NSURLConnection *)con willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse
 {
     ASSERT(con == connection);
-    return [self willSendRequest:newRequest redirectResponse:redirectResponse];
+    ++inNSURLConnectionCallback;
+    NSURLRequest *result = [self willSendRequest:newRequest redirectResponse:redirectResponse];
+    --inNSURLConnectionCallback;
+    return result;
 }
 
 - (void)connection:(NSURLConnection *)con didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
 {
     ASSERT(con == connection);
+    ++inNSURLConnectionCallback;
     [self didReceiveAuthenticationChallenge:challenge];
+    --inNSURLConnectionCallback;
 }
 
 - (void)connection:(NSURLConnection *)con didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
 {
     ASSERT(con == connection);
+    ++inNSURLConnectionCallback;
     [self didCancelAuthenticationChallenge:challenge];
+    --inNSURLConnectionCallback;
 }
 
 - (void)connection:(NSURLConnection *)con didReceiveResponse:(NSURLResponse *)r
 {
     ASSERT(con == connection);
+    ++inNSURLConnectionCallback;
     [self didReceiveResponse:r];
+    --inNSURLConnectionCallback;
 }
 
 - (void)connection:(NSURLConnection *)con didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived
 {
     ASSERT(con == connection);
+    ++inNSURLConnectionCallback;
     [self didReceiveData:data lengthReceived:lengthReceived];
+    --inNSURLConnectionCallback;
 }
 
 - (void)connection:(NSURLConnection *)con willStopBufferingData:(NSData *)data
 {
     ASSERT(con == connection);
+    ++inNSURLConnectionCallback;
     [self willStopBufferingData:data];
+    --inNSURLConnectionCallback;
 }
 
 - (void)connectionDidFinishLoading:(NSURLConnection *)con
@@ -610,13 +624,17 @@ static BOOL NSURLConnectionSupportsBufferedData;
     // don't worry about checking connection consistency if this load
     // got cancelled while finishing.
     ASSERT(cancelledFlag || con == connection);
+    ++inNSURLConnectionCallback;
     [self didFinishLoading];
+    --inNSURLConnectionCallback;
 }
 
 - (void)connection:(NSURLConnection *)con didFailWithError:(NSError *)error
 {
     ASSERT(con == connection);
+    ++inNSURLConnectionCallback;
     [self didFailWithError:error];
+    --inNSURLConnectionCallback;
 }
 
 - (NSCachedURLResponse *)connection:(NSURLConnection *)con willCacheResponse:(NSCachedURLResponse *)cachedResponse
@@ -626,7 +644,10 @@ static BOOL NSURLConnectionSupportsBufferedData;
         ERROR("connection:willCacheResponse: was called inside of [NSURLConnection initWithRequest:delegate:] (40676250)");
     }
 #endif
-    return [self willCacheResponse:cachedResponse];
+    ++inNSURLConnectionCallback;
+    NSCachedURLResponse *result = [self willCacheResponse:cachedResponse];
+    --inNSURLConnectionCallback;
+    return result;
 }
 
 - (void)cancelWithError:(NSError *)error
@@ -685,4 +706,9 @@ static BOOL NSURLConnectionSupportsBufferedData;
     return response;
 }
 
++ (BOOL)inConnectionCallback
+{
+    return inNSURLConnectionCallback != 0;
+}
+
 @end
index c8eb15e13e4130d7e7be6c5caf903d242accafff..40d9c7a4e44cdf865a5206a95ea63f6b009067a7 100644 (file)
@@ -71,7 +71,7 @@
     // Calling _receivedMainResourceError will likely result in a call to release, so we must retain.
     [self retain];
     [dataSource _receivedMainResourceError:error complete:YES];
-    [super connection:connection didFailWithError:error];
+    [super didFailWithError:error];
     [self release];
 }
 
     // Override. We don't want to save the main resource as a subresource of the data source.
 }
 
-- (NSURLRequest *)connection:(NSURLConnection *)con willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse
+- (NSURLRequest *)willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse
 {
     // Note that there are no asserts here as there are for the other callbacks. This is due to the
     // fact that this "callback" is sent when starting every load, and the state of callback
     // Note super will make a copy for us, so reassigning newRequest is important. Since we are returning this value, but
     // it's only guaranteed to be retained by self, and self might be dealloc'ed in this method, we have to autorelease.
     // See 3777253 for an example.
-    newRequest = [[[super connection:con willSendRequest:newRequest redirectResponse:redirectResponse] retain] autorelease];
+    newRequest = [[[super willSendRequest:newRequest redirectResponse:redirectResponse] retain] autorelease];
 
     // Don't set this on the first request.  It is set
     // when the main load was started.
         }
     }
 
-    [super connection:connection didReceiveResponse:r];
+    [super didReceiveResponse:r];
 
     if (![dataSource _isStopping] && ([URL _webkit_shouldLoadAsEmptyDocument] || [WebView _representationExistsForURLScheme:[URL scheme]])) {
-        [self connectionDidFinishLoading:connection];
+        [self didFinishLoading];
     }
     
     [self release];
 }
 
 
-- (void)connection:(NSURLConnection *)con didReceiveResponse:(NSURLResponse *)r
+- (void)didReceiveResponse:(NSURLResponse *)r
 {
-    ASSERT([[r URL] _webkit_shouldLoadAsEmptyDocument] || ![con defersCallbacks]);
+    ASSERT([[r URL] _webkit_shouldLoadAsEmptyDocument] || ![connection defersCallbacks]);
     ASSERT([[r URL] _webkit_shouldLoadAsEmptyDocument] || ![self defersCallbacks]);
     ASSERT([[r URL] _webkit_shouldLoadAsEmptyDocument] || ![[dataSource _webView] defersCallbacks]);
 
     [self release];
 }
 
-- (void)connection:(NSURLConnection *)con didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived
+- (void)didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived
 {
     ASSERT(data);
     ASSERT([data length] != 0);
                                        fromDataSource:dataSource
                                              complete:NO];
     
-    [super connection:con didReceiveData:data lengthReceived:lengthReceived];
+    [super didReceiveData:data lengthReceived:lengthReceived];
     _bytesReceived += [data length];
 
     LOG(Loading, "%d of %d", _bytesReceived, _contentLength);
     [self release];
 }
 
-- (void)connectionDidFinishLoading:(NSURLConnection *)con
+- (void)didFinishLoading
 {
-    ASSERT([[dataSource _URL] _webkit_shouldLoadAsEmptyDocument] || ![con defersCallbacks]);
+    ASSERT([[dataSource _URL] _webkit_shouldLoadAsEmptyDocument] || ![connection defersCallbacks]);
     ASSERT([[dataSource _URL] _webkit_shouldLoadAsEmptyDocument] || ![self defersCallbacks]);
     ASSERT([[dataSource _URL] _webkit_shouldLoadAsEmptyDocument] || ![[dataSource _webView] defersCallbacks]);
 
     [[dataSource _webView] _mainReceivedBytesSoFar:_bytesReceived
                                     fromDataSource:dataSource
                                             complete:YES];
-    [super connectionDidFinishLoading:con];
+    [super didFinishLoading];
 
     [self release];
 }
 
-- (void)connection:(NSURLConnection *)con didFailWithError:(NSError *)error
+- (void)didFailWithError:(NSError *)error
 {
-    ASSERT(![con defersCallbacks]);
+    ASSERT(![connection defersCallbacks]);
     ASSERT(![self defersCallbacks]);
     ASSERT(![[dataSource _webView] defersCallbacks]);
 
     // Send this synthetic delegate callback since clients expect it, and
     // we no longer send the callback from within NSURLConnection for
     // initial requests.
-    r = [self connection:nil willSendRequest:r redirectResponse:nil];
+    r = [self willSendRequest:r redirectResponse:nil];
     NSURL *URL = [r URL];
     BOOL shouldLoadEmpty = [URL _webkit_shouldLoadAsEmptyDocument];
 
 
         NSURLResponse *resp = [[NSURLResponse alloc] initWithURL:URL MIMEType:MIMEType
             expectedContentLength:0 textEncodingName:nil];
-       [self connection:nil didReceiveResponse:resp];
+       [self didReceiveResponse:resp];
        [resp release];
     } else {
         connection = [[NSURLConnection alloc] initWithRequest:r delegate:proxy];
index c8eb15e13e4130d7e7be6c5caf903d242accafff..40d9c7a4e44cdf865a5206a95ea63f6b009067a7 100644 (file)
@@ -71,7 +71,7 @@
     // Calling _receivedMainResourceError will likely result in a call to release, so we must retain.
     [self retain];
     [dataSource _receivedMainResourceError:error complete:YES];
-    [super connection:connection didFailWithError:error];
+    [super didFailWithError:error];
     [self release];
 }
 
     // Override. We don't want to save the main resource as a subresource of the data source.
 }
 
-- (NSURLRequest *)connection:(NSURLConnection *)con willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse
+- (NSURLRequest *)willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse
 {
     // Note that there are no asserts here as there are for the other callbacks. This is due to the
     // fact that this "callback" is sent when starting every load, and the state of callback
     // Note super will make a copy for us, so reassigning newRequest is important. Since we are returning this value, but
     // it's only guaranteed to be retained by self, and self might be dealloc'ed in this method, we have to autorelease.
     // See 3777253 for an example.
-    newRequest = [[[super connection:con willSendRequest:newRequest redirectResponse:redirectResponse] retain] autorelease];
+    newRequest = [[[super willSendRequest:newRequest redirectResponse:redirectResponse] retain] autorelease];
 
     // Don't set this on the first request.  It is set
     // when the main load was started.
         }
     }
 
-    [super connection:connection didReceiveResponse:r];
+    [super didReceiveResponse:r];
 
     if (![dataSource _isStopping] && ([URL _webkit_shouldLoadAsEmptyDocument] || [WebView _representationExistsForURLScheme:[URL scheme]])) {
-        [self connectionDidFinishLoading:connection];
+        [self didFinishLoading];
     }
     
     [self release];
 }
 
 
-- (void)connection:(NSURLConnection *)con didReceiveResponse:(NSURLResponse *)r
+- (void)didReceiveResponse:(NSURLResponse *)r
 {
-    ASSERT([[r URL] _webkit_shouldLoadAsEmptyDocument] || ![con defersCallbacks]);
+    ASSERT([[r URL] _webkit_shouldLoadAsEmptyDocument] || ![connection defersCallbacks]);
     ASSERT([[r URL] _webkit_shouldLoadAsEmptyDocument] || ![self defersCallbacks]);
     ASSERT([[r URL] _webkit_shouldLoadAsEmptyDocument] || ![[dataSource _webView] defersCallbacks]);
 
     [self release];
 }
 
-- (void)connection:(NSURLConnection *)con didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived
+- (void)didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived
 {
     ASSERT(data);
     ASSERT([data length] != 0);
                                        fromDataSource:dataSource
                                              complete:NO];
     
-    [super connection:con didReceiveData:data lengthReceived:lengthReceived];
+    [super didReceiveData:data lengthReceived:lengthReceived];
     _bytesReceived += [data length];
 
     LOG(Loading, "%d of %d", _bytesReceived, _contentLength);
     [self release];
 }
 
-- (void)connectionDidFinishLoading:(NSURLConnection *)con
+- (void)didFinishLoading
 {
-    ASSERT([[dataSource _URL] _webkit_shouldLoadAsEmptyDocument] || ![con defersCallbacks]);
+    ASSERT([[dataSource _URL] _webkit_shouldLoadAsEmptyDocument] || ![connection defersCallbacks]);
     ASSERT([[dataSource _URL] _webkit_shouldLoadAsEmptyDocument] || ![self defersCallbacks]);
     ASSERT([[dataSource _URL] _webkit_shouldLoadAsEmptyDocument] || ![[dataSource _webView] defersCallbacks]);
 
     [[dataSource _webView] _mainReceivedBytesSoFar:_bytesReceived
                                     fromDataSource:dataSource
                                             complete:YES];
-    [super connectionDidFinishLoading:con];
+    [super didFinishLoading];
 
     [self release];
 }
 
-- (void)connection:(NSURLConnection *)con didFailWithError:(NSError *)error
+- (void)didFailWithError:(NSError *)error
 {
-    ASSERT(![con defersCallbacks]);
+    ASSERT(![connection defersCallbacks]);
     ASSERT(![self defersCallbacks]);
     ASSERT(![[dataSource _webView] defersCallbacks]);
 
     // Send this synthetic delegate callback since clients expect it, and
     // we no longer send the callback from within NSURLConnection for
     // initial requests.
-    r = [self connection:nil willSendRequest:r redirectResponse:nil];
+    r = [self willSendRequest:r redirectResponse:nil];
     NSURL *URL = [r URL];
     BOOL shouldLoadEmpty = [URL _webkit_shouldLoadAsEmptyDocument];
 
 
         NSURLResponse *resp = [[NSURLResponse alloc] initWithURL:URL MIMEType:MIMEType
             expectedContentLength:0 textEncodingName:nil];
-       [self connection:nil didReceiveResponse:resp];
+       [self didReceiveResponse:resp];
        [resp release];
     } else {
         connection = [[NSURLConnection alloc] initWithRequest:r delegate:proxy];
index 05b8d2bc28f9d3634f609c7f2d7e8f0e80ff8477..f1784cdea9a620f75cf2cf4100b7e775df5a8bb1 100644 (file)
@@ -27,4 +27,7 @@ enum {
 // regions is an dictionary whose keys are regions label and values are arrays of WebDashboardRegions.
 - (void)webView:(WebView *)webView dashboardRegionsChanged:(NSDictionary *)regions;
 
+- (WebView *)webView:(WebView *)sender createWebViewModalDialogWithRequest:(NSURLRequest *)request;
+- (void)webViewRunModal:(WebView *)sender;
+
 @end