Add support for disconnection glass panel in Safari plugin.

Patch by: bobv
Review by: scottb

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7135 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/plugins/webkit/Core/WebScriptSessionHandler.cpp b/plugins/webkit/Core/WebScriptSessionHandler.cpp
index 2cc288b..7a4d8fa 100644
--- a/plugins/webkit/Core/WebScriptSessionHandler.cpp
+++ b/plugins/webkit/Core/WebScriptSessionHandler.cpp
@@ -91,6 +91,10 @@
   pthread_mutex_destroy(&javaObjectsLock);
 }
 
+void WebScriptSessionHandler::disconnectDetectedImpl() {
+  crashHandler->crash(__PRETTY_FUNCTION__, "Server disconnect detected");
+}
+
 void WebScriptSessionHandler::fatalError(HostChannel& channel,
     const std::string& message) {
   // TODO: better way of reporting error?
@@ -269,48 +273,53 @@
    */
   Debug::log(Debug::Debugging) << "Java method " << dispatchId << " invoked" << Debug::flush;
 
-  /*
-   * If a JS function is evaluated without an meaningful this object or the global
-   * object is implicitly used as the this object, we'll assume that the
-   * Java-derived method is static, and send a null this object to the server
-   */
-  Value thisValue;
-  if (JSValueIsEqual(contextRef, thisObject, JSContextGetGlobalObject(contextRef), NULL)) {
-    thisValue = Value();
-    thisValue.setNull();
-  } else {
-    makeValue(thisValue, thisObject);
-  }
-
-  // Argument conversion is straightforward
-  Value args[argumentCount];
-  for (int i = 0; i < argumentCount; i++) {
-    makeValue(args[i], arguments[i]);
-  }
-
-  if (!InvokeMessage::send(*channel, thisValue, dispatchId,
-                           argumentCount, args)) {
-    initiateAutodestructSequence(__PRETTY_FUNCTION__, "Unable to send invocation message");
-    *exception = makeException("Unable to send invocation message");
-    return JSValueMakeUndefined(contextRef);
-  }
-
-  scoped_ptr<ReturnMessage> ret(channel->reactToMessagesWhileWaitingForReturn(sessionHandler));
-
-  if (!ret.get()) {
-    initiateAutodestructSequence(__PRETTY_FUNCTION__, "Unable to receive return message");
-    *exception = makeException("Unable to receive return message");
-    return JSValueMakeUndefined(contextRef);
-  }
-
-  Value v = ret->getReturnValue();
-
   JSValueRef toReturn;
-  if (ret->isException()) {
-    *exception = makeValueRef(v);
-    toReturn = JSValueMakeUndefined(contextRef);
+  if (crashHandler->hasCrashed()) {
+    Debug::log(Debug::Debugging) << "Not executing method since we have crashed" << Debug::flush;
+    toReturn =  JSValueMakeUndefined(contextRef);
   } else {
-    toReturn = makeValueRef(v);
+    /*
+     * If a JS function is evaluated without an meaningful this object or the global
+     * object is implicitly used as the this object, we'll assume that the
+     * Java-derived method is static, and send a null this object to the server
+     */
+    Value thisValue;
+    if (JSValueIsEqual(contextRef, thisObject, JSContextGetGlobalObject(contextRef), NULL)) {
+      thisValue = Value();
+      thisValue.setNull();
+    } else {
+      makeValue(thisValue, thisObject);
+    }
+
+    // Argument conversion is straightforward
+    Value args[argumentCount];
+    for (int i = 0; i < argumentCount; i++) {
+      makeValue(args[i], arguments[i]);
+    }
+
+    if (!InvokeMessage::send(*channel, thisValue, dispatchId,
+                             argumentCount, args)) {
+      initiateAutodestructSequence(__PRETTY_FUNCTION__, "Unable to send invocation message");
+      *exception = makeException("Unable to send invocation message");
+      return JSValueMakeUndefined(contextRef);
+    }
+
+    scoped_ptr<ReturnMessage> ret(channel->reactToMessagesWhileWaitingForReturn(sessionHandler));
+
+    if (!ret.get()) {
+      initiateAutodestructSequence(__PRETTY_FUNCTION__, "Unable to receive return message");
+      *exception = makeException("Unable to receive return message");
+      return JSValueMakeUndefined(contextRef);
+    }
+
+    Value v = ret->getReturnValue();
+
+    if (ret->isException()) {
+      *exception = makeValueRef(v);
+      toReturn = JSValueMakeUndefined(contextRef);
+    } else {
+      toReturn = makeValueRef(v);
+    }
   }
 
   JSValueRef makeResultArguments[] = {JSValueMakeBoolean(contextRef, false), toReturn};
@@ -334,6 +343,11 @@
 JSValueRef WebScriptSessionHandler::javaObjectGetPropertyImpl (TrackingDataRef tracker, JSObjectRef object,
                                                                JSStringRef propertyName, JSValueRef* exception) {
   *exception = NULL;
+  
+  if (crashHandler->hasCrashed()) {
+    Debug::log(Debug::Debugging) << "Not executing since we have crashed" << Debug::flush;
+    return JSValueMakeUndefined(contextRef);
+  }
 
   // Convert the name
   int maxLength = JSStringGetMaximumUTF8CStringSize(propertyName);
@@ -403,6 +417,12 @@
 bool WebScriptSessionHandler::javaObjectSetPropertyImpl (TrackingDataRef tracker, JSObjectRef object,
                                                          JSStringRef propertyName, JSValueRef jsValue,
                                                          JSValueRef* exception) {
+
+  if (crashHandler->hasCrashed()) {
+    Debug::log(Debug::Debugging) << "Not executing since we have crashed" << Debug::flush;
+    return true;
+  }
+
   int maxLength = JSStringGetMaximumUTF8CStringSize(propertyName);
   scoped_array<char> propertyNameChars(new char[maxLength]);
   JSStringGetUTF8CString(propertyName, propertyNameChars.get(), maxLength);
diff --git a/plugins/webkit/Core/WebScriptSessionHandler.h b/plugins/webkit/Core/WebScriptSessionHandler.h
index 486f523..5e05385 100644
--- a/plugins/webkit/Core/WebScriptSessionHandler.h
+++ b/plugins/webkit/Core/WebScriptSessionHandler.h
@@ -25,6 +25,7 @@
 class CrashHandler {
 public:
   virtual void crash(const char* functionName, const char* message) = 0;
+  virtual bool hasCrashed() = 0;
 };
 typedef CrashHandler* CrashHandlerRef;
 
@@ -88,6 +89,7 @@
   JSValueRef makeException(const char* message);
 
 protected:
+  virtual void disconnectDetectedImpl();
   virtual void fatalError(HostChannel& channel, const std::string& message);
   virtual void freeValue(HostChannel& channel, int idCount, const int* ids);
   virtual void loadJsni(HostChannel& channel, const std::string& js);
diff --git a/plugins/webkit/Plugin/OophmWebScriptObject.mm b/plugins/webkit/Plugin/OophmWebScriptObject.mm
index ad06685..f40522a 100644
--- a/plugins/webkit/Plugin/OophmWebScriptObject.mm
+++ b/plugins/webkit/Plugin/OophmWebScriptObject.mm
@@ -19,7 +19,6 @@
 #import <WebKit/WebKit.h>
 #import "BrowserChannel.h"
 #import "Debug.h"
-#import "GTMStackTrace.h"
 #import "GTMSystemVersion.h"
 #import "NSMutableString+HtmlReplacement.h"
 #import "LoadModuleMessage.h"
@@ -41,6 +40,7 @@
     NSString* str = [NSString stringWithFormat:@"%s\n\n%s", message, functionName];
     [obj crashWithMessage:str];
   }
+  virtual bool hasCrashed();
 private:
   OophmWebScriptObject* const obj;
 };
@@ -48,6 +48,7 @@
 @interface OophmWebScriptObject (Private)
 + (void)logAndThrowString: (NSString*)message;
 - (void)addAllowedHost: (NSString*)host;
+- (BOOL)hasCrashed;
 - (void)connectAlertDidEnd: (NSAlert*)alert
                 returnCode: (int)returnCode
                contextInfo: (void*)contextInfo;
@@ -59,6 +60,11 @@
 	
 @end
 
+// This is declared here so that we can access the category method
+bool PluginCrashHandler::hasCrashed() {
+  return [obj hasCrashed] ? true : false;
+}
+
 @implementation OophmWebScriptObject
 + (void)initialize {
   // Add the plugin's bundle name to the user defaults search path
@@ -188,7 +194,27 @@
     return;
   }
   self->_hasCrashed = YES;
+  
+#ifdef GWT_DEBUGDISABLE
+  // We'll call out to the JS support function
+  JSGlobalContextRef contextRef = self->_contextRef;
+  JSStringRef disconnectedName = JSStringCreateWithUTF8CString("__gwt_disconnected");
+  JSValueRef disconnected = JSObjectGetProperty(contextRef, JSContextGetGlobalObject(contextRef), disconnectedName, NULL);
+  JSStringRelease(disconnectedName);
+  
+  if (JSValueIsObject(contextRef, disconnected)) {
+    // Found hosted.html's crash support
+    JSObjectRef disconnectedFunction = JSValueToObject(contextRef, disconnected, NULL);
+    JSValueRef exception = NULL;
+    JSObjectCallAsFunction(contextRef, disconnectedFunction, JSContextGetGlobalObject(contextRef), 0, NULL, &exception);
+    if (!exception) {
+      // Couldn't invoke the crash handler.
+      return;
+    }
+  }
+#endif //GWT_DEBUGDISABLE
 
+  // Use a simple crash page built into the bundle
   NSBundle* oophmBundle = [NSBundle bundleForClass:[self class]];
   NSString* path = [oophmBundle pathForResource:@"crash" ofType:@"html"];
   NSMutableString* crashPage = [NSMutableString stringWithContentsOfFile:path];
@@ -266,6 +292,10 @@
   [shared synchronize];
 }
 
+- (BOOL)hasCrashed{
+  return self->_hasCrashed;
+}
+
 - (void)connectAlertDidEnd:(NSAlert *)alert
                 returnCode:(int)returnCode
                contextInfo:(void *)contextInfo {