Fix PPB_Flash_MessageLoop.

This CL suspends script callbacks and resource loads while running nested message loop using PPB_Flash_MessageLoop.

BUG=569496

Review URL: https://codereview.chromium.org/1559113002

Cr-Commit-Position: refs/heads/master@{#374529}
(cherry picked from commit dd77c2a41c72589d929db0592565125ca629fb2c)

Review URL: https://codereview.chromium.org/1691513004 .

Cr-Commit-Position: refs/branch-heads/2623@{#365}
Cr-Branched-From: 92d77538a86529ca35f9220bd3cd512cbea1f086-refs/heads/master@{#369907}
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc
index 53375146..1ced08f 100644
--- a/chrome/test/ppapi/ppapi_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -1105,6 +1105,7 @@
   RunTest( \
       LIST_TEST(FlashMessageLoop_Basics) \
       LIST_TEST(FlashMessageLoop_RunWithoutQuit) \
+      LIST_TEST(FlashMessageLoop_SuspendScriptCallbackWhileRunning) \
   )
 
 #if defined(OS_LINUX)  // Disabled due to flakiness http://crbug.com/316925
diff --git a/content/renderer/pepper/ppb_flash_message_loop_impl.cc b/content/renderer/pepper/ppb_flash_message_loop_impl.cc
index b64abe6..89ac5add 100644
--- a/content/renderer/pepper/ppb_flash_message_loop_impl.cc
+++ b/content/renderer/pepper/ppb_flash_message_loop_impl.cc
@@ -7,6 +7,7 @@
 #include "base/callback.h"
 #include "base/message_loop/message_loop.h"
 #include "ppapi/c/pp_errors.h"
+#include "third_party/WebKit/public/web/WebView.h"
 
 using ppapi::thunk::PPB_Flash_MessageLoop_API;
 
@@ -87,7 +88,11 @@
   {
     base::MessageLoop::ScopedNestableTaskAllower allow(
         base::MessageLoop::current());
+    blink::WebView::willEnterModalLoop();
+
     base::MessageLoop::current()->Run();
+
+    blink::WebView::didExitModalLoop();
   }
   // Don't access data members of the class below.
 
diff --git a/ppapi/tests/test_flash_message_loop.cc b/ppapi/tests/test_flash_message_loop.cc
index e7cb3186..2043cbeb11c 100644
--- a/ppapi/tests/test_flash_message_loop.cc
+++ b/ppapi/tests/test_flash_message_loop.cc
@@ -5,27 +5,97 @@
 #include "ppapi/tests/test_flash_message_loop.h"
 
 #include "ppapi/c/pp_macros.h"
+#include "ppapi/c/ppb_var.h"
 #include "ppapi/cpp/core.h"
+#include "ppapi/cpp/dev/scriptable_object_deprecated.h"
 #include "ppapi/cpp/logging.h"
 #include "ppapi/cpp/module.h"
 #include "ppapi/cpp/private/flash_message_loop.h"
 #include "ppapi/tests/testing_instance.h"
 
+namespace {
+
+const char kDidRunScriptCallback[] = "DidRunScriptCallback";
+
+}  // namespace
+
+class TestFlashMessageLoop::InstanceSO
+    : public pp::deprecated::ScriptableObject {
+ public:
+  explicit InstanceSO(TestFlashMessageLoop* owner) : owner_(owner) {}
+
+  ~InstanceSO() override {
+    if (owner_)
+      owner_->clear_instance_so();
+  }
+
+  // pp::deprecated::ScriptableObject overrides.
+  bool HasMethod(const pp::Var& name, pp::Var* exception) override {
+    if (!name.is_string())
+      return false;
+    return name.AsString() == kDidRunScriptCallback;
+  }
+
+  pp::Var Call(const pp::Var& method_name,
+               const std::vector<pp::Var>& args,
+               pp::Var* exception) override {
+    if (!method_name.is_string())
+      return false;
+    std::string name = method_name.AsString();
+
+    if (name == kDidRunScriptCallback) {
+      if (args.size() != 0) {
+        *exception = pp::Var("Bad argument to DidRunScriptCallback()");
+      } else if (owner_) {
+        owner_->DidRunScriptCallback();
+      }
+    } else {
+      *exception = pp::Var("Bad function call");
+    }
+
+    return pp::Var();
+  }
+
+  void clear_owner() { owner_ = nullptr; }
+
+ private:
+  TestFlashMessageLoop* owner_;
+};
+
 REGISTER_TEST_CASE(FlashMessageLoop);
 
 TestFlashMessageLoop::TestFlashMessageLoop(TestingInstance* instance)
     : TestCase(instance),
-      message_loop_(NULL),
-      callback_factory_(this) {
-}
+      message_loop_(nullptr),
+      instance_so_(nullptr),
+      suspend_script_callback_result_(false),
+      callback_factory_(this) {}
 
 TestFlashMessageLoop::~TestFlashMessageLoop() {
   PP_DCHECK(!message_loop_);
+
+  ResetTestObject();
+  if (instance_so_)
+    instance_so_->clear_owner();
 }
 
 void TestFlashMessageLoop::RunTests(const std::string& filter) {
   RUN_TEST(Basics, filter);
   RUN_TEST(RunWithoutQuit, filter);
+  RUN_TEST(SuspendScriptCallbackWhileRunning, filter);
+}
+
+void TestFlashMessageLoop::DidRunScriptCallback() {
+  // Script callbacks are not supposed to run while the Flash message loop is
+  // running.
+  if (message_loop_)
+    suspend_script_callback_result_ = false;
+}
+
+pp::deprecated::ScriptableObject* TestFlashMessageLoop::CreateTestObject() {
+  if (!instance_so_)
+    instance_so_ = new InstanceSO(this);
+  return instance_so_;
 }
 
 std::string TestFlashMessageLoop::TestBasics() {
@@ -38,7 +108,7 @@
 
   ASSERT_TRUE(message_loop_);
   delete message_loop_;
-  message_loop_ = NULL;
+  message_loop_ = nullptr;
 
   ASSERT_EQ(PP_OK, result);
   PASS();
@@ -54,7 +124,7 @@
 
   if (message_loop_) {
     delete message_loop_;
-    message_loop_ = NULL;
+    message_loop_ = nullptr;
     ASSERT_TRUE(false);
   }
 
@@ -62,6 +132,41 @@
   PASS();
 }
 
+std::string TestFlashMessageLoop::TestSuspendScriptCallbackWhileRunning() {
+  suspend_script_callback_result_ = true;
+  message_loop_ = new pp::flash::MessageLoop(instance_);
+
+  pp::CompletionCallback callback = callback_factory_.NewCallback(
+      &TestFlashMessageLoop::TestSuspendScriptCallbackTask);
+  pp::Module::Get()->core()->CallOnMainThread(0, callback);
+  message_loop_->Run();
+
+  ASSERT_TRUE(message_loop_);
+  delete message_loop_;
+  message_loop_ = nullptr;
+
+  ASSERT_TRUE(suspend_script_callback_result_);
+  PASS();
+}
+
+void TestFlashMessageLoop::TestSuspendScriptCallbackTask(int32_t unused) {
+  pp::Var exception;
+  pp::Var rev = instance_->ExecuteScript(
+      "(function() {"
+      "  function delayedHandler() {"
+      "    document.getElementById('plugin').DidRunScriptCallback();"
+      "  }"
+      "  setTimeout(delayedHandler, 1);"
+      "})()",
+      &exception);
+  if (!exception.is_undefined())
+    suspend_script_callback_result_ = false;
+
+  pp::CompletionCallback callback =
+      callback_factory_.NewCallback(&TestFlashMessageLoop::QuitMessageLoopTask);
+  pp::Module::Get()->core()->CallOnMainThread(500, callback);
+}
+
 void TestFlashMessageLoop::QuitMessageLoopTask(int32_t unused) {
   if (message_loop_)
     message_loop_->Quit();
@@ -72,7 +177,7 @@
 void TestFlashMessageLoop::DestroyMessageLoopResourceTask(int32_t unused) {
   if (message_loop_) {
     delete message_loop_;
-    message_loop_ = NULL;
+    message_loop_ = nullptr;
   } else {
     PP_NOTREACHED();
   }
diff --git a/ppapi/tests/test_flash_message_loop.h b/ppapi/tests/test_flash_message_loop.h
index b284eedd..31b27916 100644
--- a/ppapi/tests/test_flash_message_loop.h
+++ b/ppapi/tests/test_flash_message_loop.h
@@ -20,19 +20,37 @@
 class TestFlashMessageLoop : public TestCase {
  public:
   explicit TestFlashMessageLoop(TestingInstance* instance);
-  virtual ~TestFlashMessageLoop();
+  ~TestFlashMessageLoop() override;
 
   // TestCase implementation.
-  virtual void RunTests(const std::string& filter);
+  void RunTests(const std::string& filter) override;
+
+  void clear_instance_so() { instance_so_ = nullptr; }
+
+  void DidRunScriptCallback();
 
  private:
+  // ScriptableObject implementation.
+  class InstanceSO;
+
+  // TestCase protected overrides.
+  pp::deprecated::ScriptableObject* CreateTestObject() override;
+
   std::string TestBasics();
   std::string TestRunWithoutQuit();
+  std::string TestSuspendScriptCallbackWhileRunning();
 
+  void TestSuspendScriptCallbackTask(int32_t unused);
   void QuitMessageLoopTask(int32_t unused);
   void DestroyMessageLoopResourceTask(int32_t unused);
 
   pp::flash::MessageLoop* message_loop_;
+
+  // The scriptable object and result storage for the
+  // SuspendScriptCallbackWhileRunning test.
+  InstanceSO* instance_so_;
+  bool suspend_script_callback_result_;
+
   pp::CompletionCallbackFactory<TestFlashMessageLoop> callback_factory_;
 };