<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/plugin_service_impl.h"

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/path_service.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/resource_context.h"
#include "content/public/common/content_switches.h"
#include "content/test/test_browser_thread.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "webkit/plugins/npapi/plugin_list.h"

using content::BrowserThread;

namespace {

const char kNPAPITestPluginMimeType[] = "application/vnd.npapi-test";

void OpenChannel(PluginProcessHost::Client* client) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  // Start opening the channel
  PluginServiceImpl::GetInstance()->OpenChannelToNpapiPlugin(
      0, 0, GURL(), GURL(), kNPAPITestPluginMimeType, client);
}

// Mock up of the Client and the Listener classes that would supply the
// communication channel with the plugin.
class MockPluginProcessHostClient : public PluginProcessHost::Client,
                                    public IPC::Channel::Listener {
 public:
  MockPluginProcessHostClient(content::ResourceContext* context)
      : context_(context),
        channel_(NULL),
        set_plugin_info_called_(false) {
  }

  virtual ~MockPluginProcessHostClient() {
    if (channel_)
      BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, channel_);
  }

  // Client implementation.
  virtual int ID() OVERRIDE { return 42; }
  virtual bool OffTheRecord() OVERRIDE { return false; }
  virtual content::ResourceContext* GetResourceContext() OVERRIDE {
    return context_;
  }
  virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE {}
  virtual void OnSentPluginChannelRequest() OVERRIDE {}

  virtual void OnChannelOpened(const IPC::ChannelHandle& handle) OVERRIDE {
    ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
    ASSERT_TRUE(set_plugin_info_called_);
    ASSERT_TRUE(!channel_);
    channel_ = new IPC::Channel(handle, IPC::Channel::MODE_CLIENT, this);
    ASSERT_TRUE(channel_->Connect());
  }

  void SetPluginInfo(const webkit::WebPluginInfo& info) OVERRIDE {
    ASSERT_TRUE(info.mime_types.size());
    ASSERT_EQ(kNPAPITestPluginMimeType, info.mime_types[0].mime_type);
    set_plugin_info_called_ = true;
  }

  MOCK_METHOD0(OnError, void());

  // Listener implementation.
  MOCK_METHOD1(OnMessageReceived, bool(const IPC::Message& message));
  void OnChannelConnected(int32 peer_pid) OVERRIDE {
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                            MessageLoop::QuitClosure());
  }
  MOCK_METHOD0(OnChannelError, void());
  MOCK_METHOD0(OnChannelDenied, void());
  MOCK_METHOD0(OnChannelListenError, void());

 private:
  content::ResourceContext* context_;
  IPC::Channel* channel_;
  bool set_plugin_info_called_;
  DISALLOW_COPY_AND_ASSIGN(MockPluginProcessHostClient);
};

class PluginServiceTest : public InProcessBrowserTest {
 public:
  PluginServiceTest() : InProcessBrowserTest() { }

  virtual void SetUpCommandLine(CommandLine* command_line) {
#ifdef OS_MACOSX
    FilePath browser_directory;
    PathService::Get(base::DIR_MODULE, &browser_directory);
    command_line->AppendSwitchPath(switches::kExtraPluginDir,
                                   browser_directory.AppendASCII("plugins"));
#endif
  }
};

// Try to open a channel to the test plugin. Minimal plugin process spawning
// test for the PluginService interface.
IN_PROC_BROWSER_TEST_F(PluginServiceTest, OpenChannelToPlugin) {
  ::testing::StrictMock<MockPluginProcessHostClient> mock_client(
      browser()->profile()->GetResourceContext());
  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      base::Bind(&OpenChannel, &mock_client));
  ui_test_utils::RunMessageLoop();
}

// A strict mock that fails if any of the methods are called. They shouldn't be
// called since the request should get canceled before then.
class MockCanceledPluginServiceClient : public PluginProcessHost::Client {
 public:
  MockCanceledPluginServiceClient(content::ResourceContext* context)
      : context_(context),
        get_resource_context_called_(false) {
  }

  virtual ~MockCanceledPluginServiceClient() {}

  // Client implementation.
  MOCK_METHOD0(ID, int());
  virtual content::ResourceContext* GetResourceContext() OVERRIDE {
    get_resource_context_called_ = true;
    return context_;
  }
  MOCK_METHOD0(OffTheRecord, bool());
  MOCK_METHOD1(OnFoundPluginProcessHost, void(PluginProcessHost* host));
  MOCK_METHOD0(OnSentPluginChannelRequest, void());
  MOCK_METHOD1(OnChannelOpened, void(const IPC::ChannelHandle& handle));
  MOCK_METHOD1(SetPluginInfo, void(const webkit::WebPluginInfo& info));
  MOCK_METHOD0(OnError, void());

  bool get_resource_context_called() const {
    return get_resource_context_called_;
  }

 private:
  content::ResourceContext* context_;
  bool get_resource_context_called_;

  DISALLOW_COPY_AND_ASSIGN(MockCanceledPluginServiceClient);
};

void QuitUIMessageLoopFromIOThread() {
  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                          MessageLoop::QuitClosure());
}

void OpenChannelAndThenCancel(PluginProcessHost::Client* client) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  // Start opening the channel
  PluginServiceImpl::GetInstance()->OpenChannelToNpapiPlugin(
      0, 0, GURL(), GURL(), kNPAPITestPluginMimeType, client);
  // Immediately cancel it. This is guaranteed to work since PluginService needs
  // to consult its filter on the FILE thread.
  PluginServiceImpl::GetInstance()->CancelOpenChannelToNpapiPlugin(client);
  // Before we terminate the test, add a roundtrip through the FILE thread to
  // make sure that it's had a chance to post back to the IO thread. Then signal
  // the UI thread to stop and exit the test.
  BrowserThread::PostTaskAndReply(
      BrowserThread::FILE, FROM_HERE,
      base::Bind(&base::DoNothing),
      base::Bind(&QuitUIMessageLoopFromIOThread));
}

// Should not attempt to open a channel, since it should be canceled early on.
IN_PROC_BROWSER_TEST_F(PluginServiceTest, CancelOpenChannelToPluginService) {
  ::testing::StrictMock<MockCanceledPluginServiceClient> mock_client(
      browser()->profile()->GetResourceContext());
  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
                          base::Bind(OpenChannelAndThenCancel, &mock_client));
  ui_test_utils::RunMessageLoop();
  EXPECT_TRUE(mock_client.get_resource_context_called());
}

class MockCanceledBeforeSentPluginProcessHostClient
    : public MockCanceledPluginServiceClient {
 public:
  MockCanceledBeforeSentPluginProcessHostClient(
      content::ResourceContext* context)
      : MockCanceledPluginServiceClient(context),
        set_plugin_info_called_(false),
        on_found_plugin_process_host_called_(false),
        host_(NULL) {}

  virtual ~MockCanceledBeforeSentPluginProcessHostClient() {}

  // Client implementation.
  virtual void SetPluginInfo(const webkit::WebPluginInfo& info) OVERRIDE {
    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    ASSERT_TRUE(info.mime_types.size());
    ASSERT_EQ(kNPAPITestPluginMimeType, info.mime_types[0].mime_type);
    set_plugin_info_called_ = true;
  }
  virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE {
    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    set_on_found_plugin_process_host_called();
    set_host(host);
    // This gets called right before we request the plugin<=>renderer channel,
    // so we have to post a task to cancel it.
    MessageLoop::current()->PostTask(
        FROM_HERE,
        base::Bind(&PluginProcessHost::CancelPendingRequest,
                   base::Unretained(host), this));
    MessageLoop::current()->PostTask(
        FROM_HERE,
        base::Bind(&QuitUIMessageLoopFromIOThread));
  }

  bool set_plugin_info_called() const {
    return set_plugin_info_called_;
  }

  bool on_found_plugin_process_host_called() const {
    return on_found_plugin_process_host_called_;
  }

 protected:
  void set_on_found_plugin_process_host_called() {
    on_found_plugin_process_host_called_ = true;
  }
  void set_host(PluginProcessHost* host) {
    host_ = host;
  }

  PluginProcessHost* host() const { return host_; }

 private:
  bool set_plugin_info_called_;
  bool on_found_plugin_process_host_called_;
  PluginProcessHost* host_;

  DISALLOW_COPY_AND_ASSIGN(MockCanceledBeforeSentPluginProcessHostClient);
};

IN_PROC_BROWSER_TEST_F(
    PluginServiceTest, CancelBeforeSentOpenChannelToPluginProcessHost) {
  ::testing::StrictMock<MockCanceledBeforeSentPluginProcessHostClient>
      mock_client(browser()->profile()->GetResourceContext());
  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      base::Bind(&OpenChannel, &mock_client));
  ui_test_utils::RunMessageLoop();
  EXPECT_TRUE(mock_client.get_resource_context_called());
  EXPECT_TRUE(mock_client.set_plugin_info_called());
  EXPECT_TRUE(mock_client.on_found_plugin_process_host_called());
}

class MockCanceledAfterSentPluginProcessHostClient
    : public MockCanceledBeforeSentPluginProcessHostClient {
 public:
  MockCanceledAfterSentPluginProcessHostClient(
      content::ResourceContext* context)
      : MockCanceledBeforeSentPluginProcessHostClient(context),
        on_sent_plugin_channel_request_called_(false) {}
  virtual ~MockCanceledAfterSentPluginProcessHostClient() {}

  // Client implementation.

  virtual int ID() OVERRIDE { return 42; }
  virtual bool OffTheRecord() OVERRIDE { return false; }

  // We override this guy again since we don't want to cancel yet.
  virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE {
    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    set_on_found_plugin_process_host_called();
    set_host(host);
  }

  virtual void OnSentPluginChannelRequest() OVERRIDE {
    on_sent_plugin_channel_request_called_ = true;
    host()->CancelSentRequest(this);
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                            MessageLoop::QuitClosure());
  }

  bool on_sent_plugin_channel_request_called() const {
    return on_sent_plugin_channel_request_called_;
  }

 private:
  bool on_sent_plugin_channel_request_called_;

  DISALLOW_COPY_AND_ASSIGN(MockCanceledAfterSentPluginProcessHostClient);
};

// Should not attempt to open a channel, since it should be canceled early on.
IN_PROC_BROWSER_TEST_F(
    PluginServiceTest, CancelAfterSentOpenChannelToPluginProcessHost) {
  ::testing::StrictMock<MockCanceledAfterSentPluginProcessHostClient>
      mock_client(browser()->profile()->GetResourceContext());
  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      base::Bind(&OpenChannel, &mock_client));
  ui_test_utils::RunMessageLoop();
  EXPECT_TRUE(mock_client.get_resource_context_called());
  EXPECT_TRUE(mock_client.set_plugin_info_called());
  EXPECT_TRUE(mock_client.on_found_plugin_process_host_called());
  EXPECT_TRUE(mock_client.on_sent_plugin_channel_request_called());
}

}  // namespace
<commit_msg>Quit message loop on error in PluginServiceTest, to avoid a timeout.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/plugin_service_impl.h"

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/path_service.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/resource_context.h"
#include "content/public/common/content_switches.h"
#include "content/test/test_browser_thread.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "webkit/plugins/npapi/plugin_list.h"

using content::BrowserThread;

namespace {

const char kNPAPITestPluginMimeType[] = "application/vnd.npapi-test";

void OpenChannel(PluginProcessHost::Client* client) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  // Start opening the channel
  PluginServiceImpl::GetInstance()->OpenChannelToNpapiPlugin(
      0, 0, GURL(), GURL(), kNPAPITestPluginMimeType, client);
}

// Mock up of the Client and the Listener classes that would supply the
// communication channel with the plugin.
class MockPluginProcessHostClient : public PluginProcessHost::Client,
                                    public IPC::Channel::Listener {
 public:
  MockPluginProcessHostClient(content::ResourceContext* context)
      : context_(context),
        channel_(NULL),
        set_plugin_info_called_(false) {
  }

  virtual ~MockPluginProcessHostClient() {
    if (channel_)
      BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, channel_);
  }

  // PluginProcessHost::Client implementation.
  virtual int ID() OVERRIDE { return 42; }
  virtual bool OffTheRecord() OVERRIDE { return false; }
  virtual content::ResourceContext* GetResourceContext() OVERRIDE {
    return context_;
  }
  virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE {}
  virtual void OnSentPluginChannelRequest() OVERRIDE {}

  virtual void OnChannelOpened(const IPC::ChannelHandle& handle) OVERRIDE {
    ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
    ASSERT_TRUE(set_plugin_info_called_);
    ASSERT_TRUE(!channel_);
    channel_ = new IPC::Channel(handle, IPC::Channel::MODE_CLIENT, this);
    ASSERT_TRUE(channel_->Connect());
  }

  virtual void SetPluginInfo(const webkit::WebPluginInfo& info) OVERRIDE {
    ASSERT_TRUE(info.mime_types.size());
    ASSERT_EQ(kNPAPITestPluginMimeType, info.mime_types[0].mime_type);
    set_plugin_info_called_ = true;
  }

  virtual void OnError() OVERRIDE {
    Fail();
  }

  // IPC::Channel::Listener implementation.
  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
    Fail();
    return false;
  }
  virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
    QuitMessageLoop();
  }
  virtual void OnChannelError() OVERRIDE {
    Fail();
  }
#if defined(OS_POSIX)
  virtual void OnChannelDenied() OVERRIDE {
    Fail();
  }
  virtual void OnChannelListenError() OVERRIDE {
    Fail();
  }
#endif

 private:
  void Fail() {
    FAIL();
    QuitMessageLoop();
  }

  void QuitMessageLoop() {
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                            MessageLoop::QuitClosure());
  }

  content::ResourceContext* context_;
  IPC::Channel* channel_;
  bool set_plugin_info_called_;
  DISALLOW_COPY_AND_ASSIGN(MockPluginProcessHostClient);
};

class PluginServiceTest : public InProcessBrowserTest {
 public:
  PluginServiceTest() : InProcessBrowserTest() { }

  virtual void SetUpCommandLine(CommandLine* command_line) {
#ifdef OS_MACOSX
    FilePath browser_directory;
    PathService::Get(base::DIR_MODULE, &browser_directory);
    command_line->AppendSwitchPath(switches::kExtraPluginDir,
                                   browser_directory.AppendASCII("plugins"));
#endif
  }
};

// Try to open a channel to the test plugin. Minimal plugin process spawning
// test for the PluginService interface.
IN_PROC_BROWSER_TEST_F(PluginServiceTest, OpenChannelToPlugin) {
  MockPluginProcessHostClient mock_client(
      browser()->profile()->GetResourceContext());
  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      base::Bind(&OpenChannel, &mock_client));
  ui_test_utils::RunMessageLoop();
}

// A strict mock that fails if any of the methods are called. They shouldn't be
// called since the request should get canceled before then.
class MockCanceledPluginServiceClient : public PluginProcessHost::Client {
 public:
  MockCanceledPluginServiceClient(content::ResourceContext* context)
      : context_(context),
        get_resource_context_called_(false) {
  }

  virtual ~MockCanceledPluginServiceClient() {}

  // Client implementation.
  MOCK_METHOD0(ID, int());
  virtual content::ResourceContext* GetResourceContext() OVERRIDE {
    get_resource_context_called_ = true;
    return context_;
  }
  MOCK_METHOD0(OffTheRecord, bool());
  MOCK_METHOD1(OnFoundPluginProcessHost, void(PluginProcessHost* host));
  MOCK_METHOD0(OnSentPluginChannelRequest, void());
  MOCK_METHOD1(OnChannelOpened, void(const IPC::ChannelHandle& handle));
  MOCK_METHOD1(SetPluginInfo, void(const webkit::WebPluginInfo& info));
  MOCK_METHOD0(OnError, void());

  bool get_resource_context_called() const {
    return get_resource_context_called_;
  }

 private:
  content::ResourceContext* context_;
  bool get_resource_context_called_;

  DISALLOW_COPY_AND_ASSIGN(MockCanceledPluginServiceClient);
};

void QuitUIMessageLoopFromIOThread() {
  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                          MessageLoop::QuitClosure());
}

void OpenChannelAndThenCancel(PluginProcessHost::Client* client) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  // Start opening the channel
  PluginServiceImpl::GetInstance()->OpenChannelToNpapiPlugin(
      0, 0, GURL(), GURL(), kNPAPITestPluginMimeType, client);
  // Immediately cancel it. This is guaranteed to work since PluginService needs
  // to consult its filter on the FILE thread.
  PluginServiceImpl::GetInstance()->CancelOpenChannelToNpapiPlugin(client);
  // Before we terminate the test, add a roundtrip through the FILE thread to
  // make sure that it's had a chance to post back to the IO thread. Then signal
  // the UI thread to stop and exit the test.
  BrowserThread::PostTaskAndReply(
      BrowserThread::FILE, FROM_HERE,
      base::Bind(&base::DoNothing),
      base::Bind(&QuitUIMessageLoopFromIOThread));
}

// Should not attempt to open a channel, since it should be canceled early on.
IN_PROC_BROWSER_TEST_F(PluginServiceTest, CancelOpenChannelToPluginService) {
  ::testing::StrictMock<MockCanceledPluginServiceClient> mock_client(
      browser()->profile()->GetResourceContext());
  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
                          base::Bind(OpenChannelAndThenCancel, &mock_client));
  ui_test_utils::RunMessageLoop();
  EXPECT_TRUE(mock_client.get_resource_context_called());
}

class MockCanceledBeforeSentPluginProcessHostClient
    : public MockCanceledPluginServiceClient {
 public:
  MockCanceledBeforeSentPluginProcessHostClient(
      content::ResourceContext* context)
      : MockCanceledPluginServiceClient(context),
        set_plugin_info_called_(false),
        on_found_plugin_process_host_called_(false),
        host_(NULL) {}

  virtual ~MockCanceledBeforeSentPluginProcessHostClient() {}

  // Client implementation.
  virtual void SetPluginInfo(const webkit::WebPluginInfo& info) OVERRIDE {
    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    ASSERT_TRUE(info.mime_types.size());
    ASSERT_EQ(kNPAPITestPluginMimeType, info.mime_types[0].mime_type);
    set_plugin_info_called_ = true;
  }
  virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE {
    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    set_on_found_plugin_process_host_called();
    set_host(host);
    // This gets called right before we request the plugin<=>renderer channel,
    // so we have to post a task to cancel it.
    MessageLoop::current()->PostTask(
        FROM_HERE,
        base::Bind(&PluginProcessHost::CancelPendingRequest,
                   base::Unretained(host), this));
    MessageLoop::current()->PostTask(
        FROM_HERE,
        base::Bind(&QuitUIMessageLoopFromIOThread));
  }

  bool set_plugin_info_called() const {
    return set_plugin_info_called_;
  }

  bool on_found_plugin_process_host_called() const {
    return on_found_plugin_process_host_called_;
  }

 protected:
  void set_on_found_plugin_process_host_called() {
    on_found_plugin_process_host_called_ = true;
  }
  void set_host(PluginProcessHost* host) {
    host_ = host;
  }

  PluginProcessHost* host() const { return host_; }

 private:
  bool set_plugin_info_called_;
  bool on_found_plugin_process_host_called_;
  PluginProcessHost* host_;

  DISALLOW_COPY_AND_ASSIGN(MockCanceledBeforeSentPluginProcessHostClient);
};

IN_PROC_BROWSER_TEST_F(
    PluginServiceTest, CancelBeforeSentOpenChannelToPluginProcessHost) {
  ::testing::StrictMock<MockCanceledBeforeSentPluginProcessHostClient>
      mock_client(browser()->profile()->GetResourceContext());
  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      base::Bind(&OpenChannel, &mock_client));
  ui_test_utils::RunMessageLoop();
  EXPECT_TRUE(mock_client.get_resource_context_called());
  EXPECT_TRUE(mock_client.set_plugin_info_called());
  EXPECT_TRUE(mock_client.on_found_plugin_process_host_called());
}

class MockCanceledAfterSentPluginProcessHostClient
    : public MockCanceledBeforeSentPluginProcessHostClient {
 public:
  MockCanceledAfterSentPluginProcessHostClient(
      content::ResourceContext* context)
      : MockCanceledBeforeSentPluginProcessHostClient(context),
        on_sent_plugin_channel_request_called_(false) {}
  virtual ~MockCanceledAfterSentPluginProcessHostClient() {}

  // Client implementation.

  virtual int ID() OVERRIDE { return 42; }
  virtual bool OffTheRecord() OVERRIDE { return false; }

  // We override this guy again since we don't want to cancel yet.
  virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE {
    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    set_on_found_plugin_process_host_called();
    set_host(host);
  }

  virtual void OnSentPluginChannelRequest() OVERRIDE {
    on_sent_plugin_channel_request_called_ = true;
    host()->CancelSentRequest(this);
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                            MessageLoop::QuitClosure());
  }

  bool on_sent_plugin_channel_request_called() const {
    return on_sent_plugin_channel_request_called_;
  }

 private:
  bool on_sent_plugin_channel_request_called_;

  DISALLOW_COPY_AND_ASSIGN(MockCanceledAfterSentPluginProcessHostClient);
};

// Should not attempt to open a channel, since it should be canceled early on.
IN_PROC_BROWSER_TEST_F(
    PluginServiceTest, CancelAfterSentOpenChannelToPluginProcessHost) {
  ::testing::StrictMock<MockCanceledAfterSentPluginProcessHostClient>
      mock_client(browser()->profile()->GetResourceContext());
  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      base::Bind(&OpenChannel, &mock_client));
  ui_test_utils::RunMessageLoop();
  EXPECT_TRUE(mock_client.get_resource_context_called());
  EXPECT_TRUE(mock_client.set_plugin_info_called());
  EXPECT_TRUE(mock_client.on_found_plugin_process_host_called());
  EXPECT_TRUE(mock_client.on_sent_plugin_channel_request_called());
}

}  // namespace
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Portions based heavily on:
// third_party/WebKit/Source/WebKit/chromium/public/gtk/WebInputEventFactory.cpp
//
/*
 * Copyright (C) 2006-2011 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * 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.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "content/browser/renderer_host/web_input_event_aura.h"

#include <cstdlib>
#include <X11/Xlib.h>

#include "base/event_types.h"
#include "base/logging.h"
#include "ui/aura/event.h"
#include "ui/base/events.h"
#include "ui/base/keycodes/keyboard_codes.h"
#include "ui/base/keycodes/keyboard_code_conversion_x.h"

namespace content {

// chromium WebKit does not provide a WebInputEventFactory for X11, so we have
// to do the work here ourselves.

namespace {

// This matches Firefox behavior.
const int kPixelsPerTick = 53;

int EventFlagsToWebEventModifiers(int flags) {
  int modifiers = 0;
  if (flags & ui::EF_SHIFT_DOWN)
    modifiers |= WebKit::WebInputEvent::ShiftKey;
  if (flags & ui::EF_CONTROL_DOWN)
    modifiers |= WebKit::WebInputEvent::ControlKey;
  if (flags & ui::EF_ALT_DOWN)
    modifiers |= WebKit::WebInputEvent::AltKey;
  // TODO(beng): MetaKey/META_MASK
  if (flags & ui::EF_LEFT_MOUSE_BUTTON)
    modifiers |= WebKit::WebInputEvent::LeftButtonDown;
  if (flags & ui::EF_MIDDLE_MOUSE_BUTTON)
    modifiers |= WebKit::WebInputEvent::MiddleButtonDown;
  if (flags & ui::EF_RIGHT_MOUSE_BUTTON)
    modifiers |= WebKit::WebInputEvent::RightButtonDown;
  if (flags & ui::EF_CAPS_LOCK_DOWN)
    modifiers |= WebKit::WebInputEvent::CapsLockOn;
  return modifiers;
}

int XStateToWebEventModifiers(unsigned int state) {
  int modifiers = 0;
  if (state & ShiftMask)
    modifiers |= WebKit::WebInputEvent::ShiftKey;
  if (state & ControlMask)
    modifiers |= WebKit::WebInputEvent::ControlKey;
  if (state & Mod1Mask)
    modifiers |= WebKit::WebInputEvent::AltKey;
  // TODO(beng): MetaKey/META_MASK
  if (state & Button1Mask)
    modifiers |= WebKit::WebInputEvent::LeftButtonDown;
  if (state & Button2Mask)
    modifiers |= WebKit::WebInputEvent::MiddleButtonDown;
  if (state & Button3Mask)
    modifiers |= WebKit::WebInputEvent::RightButtonDown;
  if (state & LockMask)
    modifiers |= WebKit::WebInputEvent::CapsLockOn;
  if (state & Mod2Mask)
    modifiers |= WebKit::WebInputEvent::NumLockOn;
  return modifiers;
}

int XKeyEventToWindowsKeyCode(XKeyEvent* event) {
  return ui::KeyboardCodeFromXKeyEvent((XEvent*)event);
}

// From
// third_party/WebKit/Source/WebKit/chromium/src/gtk/WebInputEventFactory.cpp:
WebKit::WebUChar GetControlCharacter(int windows_key_code, bool shift) {
  if (windows_key_code >= ui::VKEY_A &&
    windows_key_code <= ui::VKEY_Z) {
    // ctrl-A ~ ctrl-Z map to \x01 ~ \x1A
    return windows_key_code - ui::VKEY_A + 1;
  }
  if (shift) {
    // following graphics chars require shift key to input.
    switch (windows_key_code) {
      // ctrl-@ maps to \x00 (Null byte)
      case ui::VKEY_2:
        return 0;
      // ctrl-^ maps to \x1E (Record separator, Information separator two)
      case ui::VKEY_6:
        return 0x1E;
      // ctrl-_ maps to \x1F (Unit separator, Information separator one)
      case ui::VKEY_OEM_MINUS:
        return 0x1F;
      // Returns 0 for all other keys to avoid inputting unexpected chars.
      default:
        break;
    }
  } else {
    switch (windows_key_code) {
      // ctrl-[ maps to \x1B (Escape)
      case ui::VKEY_OEM_4:
        return 0x1B;
      // ctrl-\ maps to \x1C (File separator, Information separator four)
      case ui::VKEY_OEM_5:
        return 0x1C;
      // ctrl-] maps to \x1D (Group separator, Information separator three)
      case ui::VKEY_OEM_6:
        return 0x1D;
      // ctrl-Enter maps to \x0A (Line feed)
      case ui::VKEY_RETURN:
        return 0x0A;
      // Returns 0 for all other keys to avoid inputting unexpected chars.
      default:
        break;
    }
  }
  return 0;
}

WebKit::WebTouchPoint::State TouchPointStateFromEvent(
    const aura::TouchEvent* event) {
  switch (event->type()) {
    case ui::ET_TOUCH_PRESSED:
      return WebKit::WebTouchPoint::StatePressed;
    case ui::ET_TOUCH_RELEASED:
      return WebKit::WebTouchPoint::StateReleased;
    case ui::ET_TOUCH_MOVED:
      return WebKit::WebTouchPoint::StateMoved;
    case ui::ET_TOUCH_CANCELLED:
      return WebKit::WebTouchPoint::StateCancelled;
    default:
      return WebKit::WebTouchPoint::StateUndefined;
  }
}

WebKit::WebInputEvent::Type TouchEventTypeFromEvent(
    const aura::TouchEvent* event) {
  switch (event->type()) {
    case ui::ET_TOUCH_PRESSED:
      return WebKit::WebInputEvent::TouchStart;
    case ui::ET_TOUCH_RELEASED:
      return WebKit::WebInputEvent::TouchEnd;
    case ui::ET_TOUCH_MOVED:
      return WebKit::WebInputEvent::TouchMove;
    case ui::ET_TOUCH_CANCELLED:
      return WebKit::WebInputEvent::TouchCancel;
    default:
      return WebKit::WebInputEvent::Undefined;
  }
}

}  // namespace

WebKit::WebMouseEvent MakeWebMouseEventFromAuraEvent(aura::MouseEvent* event) {
  WebKit::WebMouseEvent webkit_event;

  webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
  webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();

  webkit_event.button = WebKit::WebMouseEvent::ButtonNone;
  if (event->flags() & ui::EF_LEFT_MOUSE_BUTTON)
    webkit_event.button = WebKit::WebMouseEvent::ButtonLeft;
  if (event->flags() & ui::EF_MIDDLE_MOUSE_BUTTON)
    webkit_event.button = WebKit::WebMouseEvent::ButtonMiddle;
  if (event->flags() & ui::EF_RIGHT_MOUSE_BUTTON)
    webkit_event.button = WebKit::WebMouseEvent::ButtonRight;

  switch (event->type()) {
    case ui::ET_MOUSE_PRESSED:
      webkit_event.type = WebKit::WebInputEvent::MouseDown;
      webkit_event.clickCount = event->GetClickCount();
      break;
    case ui::ET_MOUSE_RELEASED:
      webkit_event.type = WebKit::WebInputEvent::MouseUp;
      break;
    case ui::ET_MOUSE_ENTERED:
    case ui::ET_MOUSE_EXITED:
    case ui::ET_MOUSE_MOVED:
    case ui::ET_MOUSE_DRAGGED:
      webkit_event.type = WebKit::WebInputEvent::MouseMove;
      break;
    default:
      NOTIMPLEMENTED() << "Received unexpected event: " << event->type();
      break;
  }

  return webkit_event;
}

WebKit::WebMouseWheelEvent MakeWebMouseWheelEventFromAuraEvent(
    aura::MouseEvent* event) {
  WebKit::WebMouseWheelEvent webkit_event;

  webkit_event.type = WebKit::WebInputEvent::MouseWheel;
  webkit_event.button = WebKit::WebMouseEvent::ButtonNone;
  webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
  webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();
  webkit_event.deltaY = ui::GetMouseWheelOffset(event->native_event());
  webkit_event.wheelTicksY = webkit_event.deltaY / kPixelsPerTick;

  return webkit_event;
}

WebKit::WebMouseWheelEvent MakeWebMouseWheelEventFromAuraEvent(
    aura::ScrollEvent* event) {
  WebKit::WebMouseWheelEvent webkit_event;

  webkit_event.type = WebKit::WebInputEvent::MouseWheel;
  webkit_event.button = WebKit::WebMouseEvent::ButtonNone;
  webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
  webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();
  webkit_event.hasPreciseScrollingDeltas = true;
  webkit_event.deltaX = event->x_offset();
  webkit_event.wheelTicksX = webkit_event.deltaX / kPixelsPerTick;
  webkit_event.deltaY = event->y_offset();
  webkit_event.wheelTicksY = webkit_event.deltaY / kPixelsPerTick;

  return webkit_event;
}

WebKit::WebKeyboardEvent MakeWebKeyboardEventFromAuraEvent(
    aura::KeyEvent* event) {
  base::NativeEvent native_event = event->native_event();
  WebKit::WebKeyboardEvent webkit_event;
  XKeyEvent* native_key_event = &native_event->xkey;

  webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();
  webkit_event.modifiers = XStateToWebEventModifiers(native_key_event->state);

  switch (native_event->type) {
    case KeyPress:
      webkit_event.type = event->is_char() ? WebKit::WebInputEvent::Char :
          WebKit::WebInputEvent::RawKeyDown;
      break;
    case KeyRelease:
      webkit_event.type = WebKit::WebInputEvent::KeyUp;
      break;
    default:
      NOTREACHED();
  }

  if (webkit_event.modifiers & WebKit::WebInputEvent::AltKey)
    webkit_event.isSystemKey = true;

  webkit_event.windowsKeyCode = XKeyEventToWindowsKeyCode(native_key_event);
  webkit_event.nativeKeyCode = native_key_event->keycode;

  if (webkit_event.windowsKeyCode == ui::VKEY_RETURN)
    webkit_event.unmodifiedText[0] = '\r';
  else
    webkit_event.unmodifiedText[0] = ui::GetCharacterFromXEvent(native_event);

  if (webkit_event.modifiers & WebKit::WebInputEvent::ControlKey) {
    webkit_event.text[0] =
        GetControlCharacter(
            webkit_event.windowsKeyCode,
            webkit_event.modifiers & WebKit::WebInputEvent::ShiftKey);
  } else {
    webkit_event.text[0] = webkit_event.unmodifiedText[0];
  }

  webkit_event.setKeyIdentifierFromWindowsKeyCode();

  // TODO: IsAutoRepeat/IsKeyPad?

  return webkit_event;
}

WebKit::WebGestureEvent MakeWebGestureEventFromAuraEvent(
    aura::GestureEvent* event) {
  WebKit::WebGestureEvent gesture_event;

  switch (event->type()) {
    case ui::ET_GESTURE_TAP:
      gesture_event.type = WebKit::WebInputEvent::GestureTap;
      break;
    case ui::ET_GESTURE_TAP_DOWN:
      gesture_event.type = WebKit::WebInputEvent::GestureTapDown;
      break;
    case ui::ET_GESTURE_DOUBLE_TAP:
      gesture_event.type = WebKit::WebInputEvent::GestureDoubleTap;
      break;
    case ui::ET_GESTURE_SCROLL_BEGIN:
      gesture_event.type = WebKit::WebInputEvent::GestureScrollBegin;
      break;
    case ui::ET_GESTURE_SCROLL_UPDATE:
      gesture_event.type = WebKit::WebInputEvent::GestureScrollUpdate;
      break;
    case ui::ET_GESTURE_SCROLL_END:
      gesture_event.type = WebKit::WebInputEvent::GestureScrollEnd;
      break;
    default:
      NOTREACHED() << "Unknown gesture type: " << event->type();
  }

  gesture_event.deltaX = event->delta_x();
  gesture_event.deltaY = event->delta_y();

  return gesture_event;
}

WebKit::WebTouchPoint* UpdateWebTouchEventFromAuraEvent(
    aura::TouchEvent* event, WebKit::WebTouchEvent* web_event) {
  WebKit::WebTouchPoint* point = NULL;
  switch (event->type()) {
    case ui::ET_TOUCH_PRESSED:
      // Add a new touch point.
      if (web_event->touchesLength < WebKit::WebTouchEvent::touchesLengthCap) {
        point = &web_event->touches[web_event->touchesLength++];
        point->id = event->touch_id();
      }
      break;
    case ui::ET_TOUCH_RELEASED:
    case ui::ET_TOUCH_CANCELLED:
    case ui::ET_TOUCH_MOVED: {
      // The touch point should have been added to the event from an earlier
      // _PRESSED event. So find that.
      // At the moment, only a maximum of 4 touch-points are allowed. So a
      // simple loop should be sufficient.
      for (unsigned i = 0; i < web_event->touchesLength; ++i) {
        point = web_event->touches + i;
        if (point->id == event->touch_id())
          break;
        point = NULL;
      }
      break;
    }
    default:
      DLOG(WARNING) << "Unknown touch event " << event->type();
      break;
  }

  if (!point)
    return NULL;

  point->radiusX = event->radius_x();
  point->radiusY = event->radius_y();
  point->rotationAngle = event->rotation_angle();
  point->force = event->force();

  // Update the location and state of the point.
  point->state = TouchPointStateFromEvent(event);
  if (point->state == WebKit::WebTouchPoint::StateMoved) {
    // It is possible for badly written touch drivers to emit Move events even
    // when the touch location hasn't changed. In such cases, consume the event
    // and pretend nothing happened.
    if (point->position.x == event->x() && point->position.y == event->y())
      return NULL;
  }
  point->position.x = event->x();
  point->position.y = event->y();

  // TODO(sad): Convert to screen coordinates.
  point->screenPosition.x = point->position.x;
  point->screenPosition.y = point->position.y;

  // Mark the rest of the points as stationary.
  for (unsigned i = 0; i < web_event->touchesLength; ++i) {
    WebKit::WebTouchPoint* iter = web_event->touches + i;
    if (iter != point)
      iter->state = WebKit::WebTouchPoint::StateStationary;
  }

  // Update the type of the touch event.
  web_event->type = TouchEventTypeFromEvent(event);
  web_event->timeStampSeconds = event->time_stamp().InSecondsF();
  web_event->modifiers = EventFlagsToWebEventModifiers(event->flags());

  return point;
}

}  // namespace content
<commit_msg>aura: Send correct screen position for touch-points to webkit.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Portions based heavily on:
// third_party/WebKit/Source/WebKit/chromium/public/gtk/WebInputEventFactory.cpp
//
/*
 * Copyright (C) 2006-2011 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * 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.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "content/browser/renderer_host/web_input_event_aura.h"

#include <cstdlib>
#include <X11/Xlib.h>

#include "base/event_types.h"
#include "base/logging.h"
#include "ui/aura/event.h"
#include "ui/base/events.h"
#include "ui/base/keycodes/keyboard_codes.h"
#include "ui/base/keycodes/keyboard_code_conversion_x.h"

namespace content {

// chromium WebKit does not provide a WebInputEventFactory for X11, so we have
// to do the work here ourselves.

namespace {

// This matches Firefox behavior.
const int kPixelsPerTick = 53;

int EventFlagsToWebEventModifiers(int flags) {
  int modifiers = 0;
  if (flags & ui::EF_SHIFT_DOWN)
    modifiers |= WebKit::WebInputEvent::ShiftKey;
  if (flags & ui::EF_CONTROL_DOWN)
    modifiers |= WebKit::WebInputEvent::ControlKey;
  if (flags & ui::EF_ALT_DOWN)
    modifiers |= WebKit::WebInputEvent::AltKey;
  // TODO(beng): MetaKey/META_MASK
  if (flags & ui::EF_LEFT_MOUSE_BUTTON)
    modifiers |= WebKit::WebInputEvent::LeftButtonDown;
  if (flags & ui::EF_MIDDLE_MOUSE_BUTTON)
    modifiers |= WebKit::WebInputEvent::MiddleButtonDown;
  if (flags & ui::EF_RIGHT_MOUSE_BUTTON)
    modifiers |= WebKit::WebInputEvent::RightButtonDown;
  if (flags & ui::EF_CAPS_LOCK_DOWN)
    modifiers |= WebKit::WebInputEvent::CapsLockOn;
  return modifiers;
}

int XStateToWebEventModifiers(unsigned int state) {
  int modifiers = 0;
  if (state & ShiftMask)
    modifiers |= WebKit::WebInputEvent::ShiftKey;
  if (state & ControlMask)
    modifiers |= WebKit::WebInputEvent::ControlKey;
  if (state & Mod1Mask)
    modifiers |= WebKit::WebInputEvent::AltKey;
  // TODO(beng): MetaKey/META_MASK
  if (state & Button1Mask)
    modifiers |= WebKit::WebInputEvent::LeftButtonDown;
  if (state & Button2Mask)
    modifiers |= WebKit::WebInputEvent::MiddleButtonDown;
  if (state & Button3Mask)
    modifiers |= WebKit::WebInputEvent::RightButtonDown;
  if (state & LockMask)
    modifiers |= WebKit::WebInputEvent::CapsLockOn;
  if (state & Mod2Mask)
    modifiers |= WebKit::WebInputEvent::NumLockOn;
  return modifiers;
}

int XKeyEventToWindowsKeyCode(XKeyEvent* event) {
  return ui::KeyboardCodeFromXKeyEvent((XEvent*)event);
}

// From
// third_party/WebKit/Source/WebKit/chromium/src/gtk/WebInputEventFactory.cpp:
WebKit::WebUChar GetControlCharacter(int windows_key_code, bool shift) {
  if (windows_key_code >= ui::VKEY_A &&
    windows_key_code <= ui::VKEY_Z) {
    // ctrl-A ~ ctrl-Z map to \x01 ~ \x1A
    return windows_key_code - ui::VKEY_A + 1;
  }
  if (shift) {
    // following graphics chars require shift key to input.
    switch (windows_key_code) {
      // ctrl-@ maps to \x00 (Null byte)
      case ui::VKEY_2:
        return 0;
      // ctrl-^ maps to \x1E (Record separator, Information separator two)
      case ui::VKEY_6:
        return 0x1E;
      // ctrl-_ maps to \x1F (Unit separator, Information separator one)
      case ui::VKEY_OEM_MINUS:
        return 0x1F;
      // Returns 0 for all other keys to avoid inputting unexpected chars.
      default:
        break;
    }
  } else {
    switch (windows_key_code) {
      // ctrl-[ maps to \x1B (Escape)
      case ui::VKEY_OEM_4:
        return 0x1B;
      // ctrl-\ maps to \x1C (File separator, Information separator four)
      case ui::VKEY_OEM_5:
        return 0x1C;
      // ctrl-] maps to \x1D (Group separator, Information separator three)
      case ui::VKEY_OEM_6:
        return 0x1D;
      // ctrl-Enter maps to \x0A (Line feed)
      case ui::VKEY_RETURN:
        return 0x0A;
      // Returns 0 for all other keys to avoid inputting unexpected chars.
      default:
        break;
    }
  }
  return 0;
}

WebKit::WebTouchPoint::State TouchPointStateFromEvent(
    const aura::TouchEvent* event) {
  switch (event->type()) {
    case ui::ET_TOUCH_PRESSED:
      return WebKit::WebTouchPoint::StatePressed;
    case ui::ET_TOUCH_RELEASED:
      return WebKit::WebTouchPoint::StateReleased;
    case ui::ET_TOUCH_MOVED:
      return WebKit::WebTouchPoint::StateMoved;
    case ui::ET_TOUCH_CANCELLED:
      return WebKit::WebTouchPoint::StateCancelled;
    default:
      return WebKit::WebTouchPoint::StateUndefined;
  }
}

WebKit::WebInputEvent::Type TouchEventTypeFromEvent(
    const aura::TouchEvent* event) {
  switch (event->type()) {
    case ui::ET_TOUCH_PRESSED:
      return WebKit::WebInputEvent::TouchStart;
    case ui::ET_TOUCH_RELEASED:
      return WebKit::WebInputEvent::TouchEnd;
    case ui::ET_TOUCH_MOVED:
      return WebKit::WebInputEvent::TouchMove;
    case ui::ET_TOUCH_CANCELLED:
      return WebKit::WebInputEvent::TouchCancel;
    default:
      return WebKit::WebInputEvent::Undefined;
  }
}

}  // namespace

WebKit::WebMouseEvent MakeWebMouseEventFromAuraEvent(aura::MouseEvent* event) {
  WebKit::WebMouseEvent webkit_event;

  webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
  webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();

  webkit_event.button = WebKit::WebMouseEvent::ButtonNone;
  if (event->flags() & ui::EF_LEFT_MOUSE_BUTTON)
    webkit_event.button = WebKit::WebMouseEvent::ButtonLeft;
  if (event->flags() & ui::EF_MIDDLE_MOUSE_BUTTON)
    webkit_event.button = WebKit::WebMouseEvent::ButtonMiddle;
  if (event->flags() & ui::EF_RIGHT_MOUSE_BUTTON)
    webkit_event.button = WebKit::WebMouseEvent::ButtonRight;

  switch (event->type()) {
    case ui::ET_MOUSE_PRESSED:
      webkit_event.type = WebKit::WebInputEvent::MouseDown;
      webkit_event.clickCount = event->GetClickCount();
      break;
    case ui::ET_MOUSE_RELEASED:
      webkit_event.type = WebKit::WebInputEvent::MouseUp;
      break;
    case ui::ET_MOUSE_ENTERED:
    case ui::ET_MOUSE_EXITED:
    case ui::ET_MOUSE_MOVED:
    case ui::ET_MOUSE_DRAGGED:
      webkit_event.type = WebKit::WebInputEvent::MouseMove;
      break;
    default:
      NOTIMPLEMENTED() << "Received unexpected event: " << event->type();
      break;
  }

  return webkit_event;
}

WebKit::WebMouseWheelEvent MakeWebMouseWheelEventFromAuraEvent(
    aura::MouseEvent* event) {
  WebKit::WebMouseWheelEvent webkit_event;

  webkit_event.type = WebKit::WebInputEvent::MouseWheel;
  webkit_event.button = WebKit::WebMouseEvent::ButtonNone;
  webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
  webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();
  webkit_event.deltaY = ui::GetMouseWheelOffset(event->native_event());
  webkit_event.wheelTicksY = webkit_event.deltaY / kPixelsPerTick;

  return webkit_event;
}

WebKit::WebMouseWheelEvent MakeWebMouseWheelEventFromAuraEvent(
    aura::ScrollEvent* event) {
  WebKit::WebMouseWheelEvent webkit_event;

  webkit_event.type = WebKit::WebInputEvent::MouseWheel;
  webkit_event.button = WebKit::WebMouseEvent::ButtonNone;
  webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
  webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();
  webkit_event.hasPreciseScrollingDeltas = true;
  webkit_event.deltaX = event->x_offset();
  webkit_event.wheelTicksX = webkit_event.deltaX / kPixelsPerTick;
  webkit_event.deltaY = event->y_offset();
  webkit_event.wheelTicksY = webkit_event.deltaY / kPixelsPerTick;

  return webkit_event;
}

WebKit::WebKeyboardEvent MakeWebKeyboardEventFromAuraEvent(
    aura::KeyEvent* event) {
  base::NativeEvent native_event = event->native_event();
  WebKit::WebKeyboardEvent webkit_event;
  XKeyEvent* native_key_event = &native_event->xkey;

  webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();
  webkit_event.modifiers = XStateToWebEventModifiers(native_key_event->state);

  switch (native_event->type) {
    case KeyPress:
      webkit_event.type = event->is_char() ? WebKit::WebInputEvent::Char :
          WebKit::WebInputEvent::RawKeyDown;
      break;
    case KeyRelease:
      webkit_event.type = WebKit::WebInputEvent::KeyUp;
      break;
    default:
      NOTREACHED();
  }

  if (webkit_event.modifiers & WebKit::WebInputEvent::AltKey)
    webkit_event.isSystemKey = true;

  webkit_event.windowsKeyCode = XKeyEventToWindowsKeyCode(native_key_event);
  webkit_event.nativeKeyCode = native_key_event->keycode;

  if (webkit_event.windowsKeyCode == ui::VKEY_RETURN)
    webkit_event.unmodifiedText[0] = '\r';
  else
    webkit_event.unmodifiedText[0] = ui::GetCharacterFromXEvent(native_event);

  if (webkit_event.modifiers & WebKit::WebInputEvent::ControlKey) {
    webkit_event.text[0] =
        GetControlCharacter(
            webkit_event.windowsKeyCode,
            webkit_event.modifiers & WebKit::WebInputEvent::ShiftKey);
  } else {
    webkit_event.text[0] = webkit_event.unmodifiedText[0];
  }

  webkit_event.setKeyIdentifierFromWindowsKeyCode();

  // TODO: IsAutoRepeat/IsKeyPad?

  return webkit_event;
}

WebKit::WebGestureEvent MakeWebGestureEventFromAuraEvent(
    aura::GestureEvent* event) {
  WebKit::WebGestureEvent gesture_event;

  switch (event->type()) {
    case ui::ET_GESTURE_TAP:
      gesture_event.type = WebKit::WebInputEvent::GestureTap;
      break;
    case ui::ET_GESTURE_TAP_DOWN:
      gesture_event.type = WebKit::WebInputEvent::GestureTapDown;
      break;
    case ui::ET_GESTURE_DOUBLE_TAP:
      gesture_event.type = WebKit::WebInputEvent::GestureDoubleTap;
      break;
    case ui::ET_GESTURE_SCROLL_BEGIN:
      gesture_event.type = WebKit::WebInputEvent::GestureScrollBegin;
      break;
    case ui::ET_GESTURE_SCROLL_UPDATE:
      gesture_event.type = WebKit::WebInputEvent::GestureScrollUpdate;
      break;
    case ui::ET_GESTURE_SCROLL_END:
      gesture_event.type = WebKit::WebInputEvent::GestureScrollEnd;
      break;
    default:
      NOTREACHED() << "Unknown gesture type: " << event->type();
  }

  gesture_event.deltaX = event->delta_x();
  gesture_event.deltaY = event->delta_y();

  return gesture_event;
}

WebKit::WebTouchPoint* UpdateWebTouchEventFromAuraEvent(
    aura::TouchEvent* event, WebKit::WebTouchEvent* web_event) {
  WebKit::WebTouchPoint* point = NULL;
  switch (event->type()) {
    case ui::ET_TOUCH_PRESSED:
      // Add a new touch point.
      if (web_event->touchesLength < WebKit::WebTouchEvent::touchesLengthCap) {
        point = &web_event->touches[web_event->touchesLength++];
        point->id = event->touch_id();
      }
      break;
    case ui::ET_TOUCH_RELEASED:
    case ui::ET_TOUCH_CANCELLED:
    case ui::ET_TOUCH_MOVED: {
      // The touch point should have been added to the event from an earlier
      // _PRESSED event. So find that.
      // At the moment, only a maximum of 4 touch-points are allowed. So a
      // simple loop should be sufficient.
      for (unsigned i = 0; i < web_event->touchesLength; ++i) {
        point = web_event->touches + i;
        if (point->id == event->touch_id())
          break;
        point = NULL;
      }
      break;
    }
    default:
      DLOG(WARNING) << "Unknown touch event " << event->type();
      break;
  }

  if (!point)
    return NULL;

  point->radiusX = event->radius_x();
  point->radiusY = event->radius_y();
  point->rotationAngle = event->rotation_angle();
  point->force = event->force();

  // Update the location and state of the point.
  point->state = TouchPointStateFromEvent(event);
  if (point->state == WebKit::WebTouchPoint::StateMoved) {
    // It is possible for badly written touch drivers to emit Move events even
    // when the touch location hasn't changed. In such cases, consume the event
    // and pretend nothing happened.
    if (point->position.x == event->x() && point->position.y == event->y())
      return NULL;
  }
  point->position.x = event->x();
  point->position.y = event->y();

  const gfx::Point root_point = event->root_location();
  point->screenPosition.x = root_point.x();
  point->screenPosition.y = root_point.y();

  // Mark the rest of the points as stationary.
  for (unsigned i = 0; i < web_event->touchesLength; ++i) {
    WebKit::WebTouchPoint* iter = web_event->touches + i;
    if (iter != point)
      iter->state = WebKit::WebTouchPoint::StateStationary;
  }

  // Update the type of the touch event.
  web_event->type = TouchEventTypeFromEvent(event);
  web_event->timeStampSeconds = event->time_stamp().InSecondsF();
  web_event->modifiers = EventFlagsToWebEventModifiers(event->flags());

  return point;
}

}  // namespace content
<|endoftext|>


<commit_before>/*

DAcase2.c

This program connects to the DAQ data source passed as argument
and populates local "./result.txt" file with the ids of events received
during the run.

The program exits when being asked to shut down (daqDA_checkshutdown)
or End of Run event.

Messages on stdout are exported to DAQ log system.

contact: alice-datesupport@cern.ch

*/

#include "event.h"
#include "monitor.h"
extern "C" {
#include "daqDA.h"
}

#include <stdio.h>
#include <stdlib.h>

#include "AliRawReader.h"
#include "AliRawReaderDate.h"
#include "AliPHOSCalibHistoProducer.h"

/* Main routine
      Arguments:
      1- monitoring data source
*/
int main(int argc, char **argv) {

  int status;

  if (argc!=2) {
    printf("Wrong number of arguments\n");
    return -1;
  }

  /* open result file */
  FILE *fp=NULL;
  fp=fopen("./result.txt","a");
  if (fp==NULL) {
    printf("Failed to open file\n");
    return -1;
  }

  /* define data source : this is argument 1 */
  status=monitorSetDataSource( argv[1] );
  if (status!=0) {
    printf("monitorSetDataSource() failed : %s\n",monitorDecodeError(status));
    return -1;
  }

  /* declare monitoring program */
  status=monitorDeclareMp( __FILE__ );
  if (status!=0) {
    printf("monitorDeclareMp() failed : %s\n",monitorDecodeError(status));
    return -1;
  }

  /* define wait event timeout - 1s max */
  monitorSetNowait();
  monitorSetNoWaitNetworkTimeout(1000);

  /* log start of process */
  printf("DA example case2 monitoring program started\n");

  /* init some counters */
  int nevents_physics=0;
  int nevents_total=0;

  AliPHOSCalibHistoProducer hp;
  hp.SetOldRCUFormat(kTRUE);
  hp.SetUpdatingRate(500);

  /* main loop (infinite) */
  for(;;) {
    struct eventHeaderStruct *event;
    eventTypeType eventT;

    /* check shutdown condition */
    if (daqDA_checkShutdown()) {break;}

    /* get next event (blocking call until timeout) */
    status=monitorGetEventDynamic((void **)&event);
    if (status==MON_ERR_EOF) {
      printf ("End of File detected\n");
      break; /* end of monitoring file has been reached */
    }

    if (status!=0) {
      printf("monitorGetEventDynamic() failed : %s\n",monitorDecodeError(status));
      break;
    }

    /* retry if got no event */
    if (event==NULL) {
      continue;
    }

    /* use event - here, just write event id to result file */
    eventT=event->eventType;

    if (eventT==PHYSICS_EVENT) {
      fprintf(fp,"Run #%lu, event size: %lu, BC:%u, Orbit:%u, Period:%u\n",
	  (unsigned long)event->eventRunNb,
        (unsigned long)event->eventSize,
        EVENT_ID_GET_BUNCH_CROSSING(event->eventId),
        EVENT_ID_GET_ORBIT(event->eventId),
        EVENT_ID_GET_PERIOD(event->eventId)
      );

      AliRawReader *rawReader = new AliRawReaderDate((void*)event);

      hp.SetRawReader(rawReader);
      hp.Run();

      nevents_physics++;
    }
    nevents_total++;

    /* free resources */
    free(event);

    /* exit when last event received, no need to wait for TERM signal */
    if (eventT==END_OF_RUN) {
      printf("EOR event detected\n");
      break;
    }
  }

  /* write report */
  fprintf(fp,"Run #%s, received %d physics events out of %d\n",getenv("DATE_RUN_NUMBER"),nevents_physics,nevents_total);

  /* close result file */
  fclose(fp);

  return status;
}
<commit_msg>Updated version of the DA (Boris)<commit_after>/*

DAcase2.c

This program connects to the DAQ data source passed as argument
and populates local "./result.txt" file with the ids of events received
during the run.

The program exits when being asked to shut down (daqDA_checkshutdown)
or End of Run event.

Messages on stdout are exported to DAQ log system.

contact: alice-datesupport@cern.ch

*/

#include "event.h"
#include "monitor.h"
extern "C" {
#include "daqDA.h"
}

#include <stdio.h>
#include <stdlib.h>

#include "AliRawReader.h"
#include "AliRawReaderDate.h"
#include "AliPHOSCalibHistoProducer.h"
#include "AliPHOSRawDecoder.h"

/* Main routine
      Arguments:
      1- monitoring data source
*/
int main(int argc, char **argv) {

  int status;

  if (argc!=2) {
    printf("Wrong number of arguments\n");
    return -1;
  }

  /* open result file */
  FILE *fp=NULL;
  fp=fopen("./result.txt","a");
  if (fp==NULL) {
    printf("Failed to open file\n");
    return -1;
  }

  /* define data source : this is argument 1 */
  status=monitorSetDataSource( argv[1] );
  if (status!=0) {
    printf("monitorSetDataSource() failed : %s\n",monitorDecodeError(status));
    return -1;
  }

  /* declare monitoring program */
  status=monitorDeclareMp( __FILE__ );
  if (status!=0) {
    printf("monitorDeclareMp() failed : %s\n",monitorDecodeError(status));
    return -1;
  }

  /* define wait event timeout - 1s max */
  monitorSetNowait();
  monitorSetNoWaitNetworkTimeout(1000);

  /* log start of process */
  printf("DA example case2 monitoring program started\n");

  /* init some counters */
  int nevents_physics=0;
  int nevents_total=0;

  AliRawReader *rawReader = NULL;

  AliPHOSCalibHistoProducer hp(200,0.,200.);
  hp.SetOldRCUFormat(kTRUE);
  hp.SetUpdatingRate(200000);

  /* main loop (infinite) */
  for(;;) {
    struct eventHeaderStruct *event;
    eventTypeType eventT;

    /* check shutdown condition */
    if (daqDA_checkShutdown()) {break;}

    /* get next event (blocking call until timeout) */
    status=monitorGetEventDynamic((void **)&event);
    if (status==MON_ERR_EOF) {
      printf ("End of File detected\n");
      break; /* end of monitoring file has been reached */
    }

    if (status!=0) {
      printf("monitorGetEventDynamic() failed : %s\n",monitorDecodeError(status));
      break;
    }

    /* retry if got no event */
    if (event==NULL) {
      continue;
    }

    /* use event - here, just write event id to result file */
    eventT=event->eventType;

    if (eventT==PHYSICS_EVENT) {
      fprintf(fp,"Run #%lu, event size: %lu, BC:%u, Orbit:%u, Period:%u\n",
	  (unsigned long)event->eventRunNb,
        (unsigned long)event->eventSize,
        EVENT_ID_GET_BUNCH_CROSSING(event->eventId),
        EVENT_ID_GET_ORBIT(event->eventId),
        EVENT_ID_GET_PERIOD(event->eventId)
      );

      rawReader = new AliRawReaderDate((void*)event);
      AliPHOSRawDecoder dc(rawReader);
      dc.SubtractPedestals(kTRUE);
      hp.SetRawDecoder(&dc);
      hp.Run();

      nevents_physics++;
    }
    nevents_total++;

    /* free resources */
    free(event);

    /* exit when last event received, no need to wait for TERM signal */
    if (eventT==END_OF_RUN) {
      printf("EOR event detected\n");
      break;
    }
  }

  /* write report */
  fprintf(fp,"Run #%s, received %d physics events out of %d\n",getenv("DATE_RUN_NUMBER"),nevents_physics,nevents_total);

  /* close result file */
  fclose(fp);

  return status;
}
<|endoftext|>


<commit_before>// @(#)root/thread:$Id$
// Author: Fons Rademakers   02/07/97

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TPosixThread                                                         //
//                                                                      //
// This class provides an interface to the posix thread routines.       //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TPosixThread.h"

ClassImp(TPosixThread)

//______________________________________________________________________________
Int_t TPosixThread::Run(TThread *th)
{
   // Create a pthread.

   int det;
   pthread_t id;
   pthread_attr_t *attr = new pthread_attr_t;

   pthread_attr_init(attr);

   // Set detach state
   det = (th->fDetached) ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE;

   pthread_attr_setdetachstate(attr, det);
   int ierr = pthread_create(&id, attr, &TThread::Function, th);
   if (!ierr) th->fId = (Long_t) id;

   pthread_attr_destroy(attr);
   delete attr;

   return ierr;
}

//______________________________________________________________________________
Int_t TPosixThread::Join(TThread *th, void **ret)
{
   // Join  suspends  the  execution  of the calling thread until the
   // thread identified by th terminates, either by  calling  pthread_exit
   // or by being cancelled.

   return pthread_join((pthread_t) th->fId, ret);
}

//______________________________________________________________________________
Int_t TPosixThread::Exit(void *ret)
{
   // Terminates the execution of the calling thread.

   pthread_exit(ret);
   return 0;
}

//______________________________________________________________________________
Int_t TPosixThread::Kill(TThread *th)
{
   // Cancellation is the mechanism by which a thread can terminate the
   // execution of another thread.

   return pthread_cancel((pthread_t) th->fId);
}

//______________________________________________________________________________
Int_t TPosixThread::SetCancelOff()
{
   // Turn off the cancellation state of the calling thread.

   return pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0);
}

//______________________________________________________________________________
Int_t TPosixThread::SetCancelOn()
{
   // Turn on the cancellation state of the calling thread.

   return pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
}

//______________________________________________________________________________
Int_t TPosixThread::SetCancelAsynchronous()
{
   // Set the cancellation response type of the calling thread to
   // asynchronous, i.e. cancel as soon as the cancellation request
   // is received.

   return pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
}

//______________________________________________________________________________
Int_t TPosixThread::SetCancelDeferred()
{
   // Set the cancellation response type of the calling thread to
   // deferred, i.e. cancel only at next cancellation point.

   return pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, 0);
}

//______________________________________________________________________________
Int_t TPosixThread::CancelPoint()
{
   // Introduce an explicit cancellation point.

   int istate;
   pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &istate);
   pthread_testcancel();
   pthread_setcancelstate(istate, 0);

   return 0;
}

//______________________________________________________________________________
Int_t TPosixThread::CleanUpPush(void **main, void *free, void *arg)
{
   // Add thread cleanup function.

   // pthread_cleanup_push(free, arg);
   if (!free) Error("CleanUpPush", "cleanup rountine = 0");
   new TPosixThreadCleanUp(main, free, arg);
   return 0;
}

//______________________________________________________________________________
Int_t TPosixThread::CleanUpPop(void **main,Int_t exe)
{
   // Pop thread cleanup function from stack.

   //  pthread_cleanup_pop(exe); // happy pthread future

   if (!main || !*main) return 1;
   TPosixThreadCleanUp *l = (TPosixThreadCleanUp*)(*main);
   if (!l->fRoutine) Error("CleanUpPop", "cleanup routine = 0");
   if (exe && l->fRoutine) ((void (*)(void*))(l->fRoutine))(l->fArgument);
   *main = l->fNext;  delete l;
   return 0;
}

//______________________________________________________________________________
Int_t TPosixThread::CleanUp(void **main)
{
   // Default thread cleanup routine.

   if (gDebug > 0)
      Info("Cleanup", "cleanup 0x%lx", (Long_t)*main);
   while (!CleanUpPop(main, 1)) { }
   return 0;
}

//______________________________________________________________________________
Long_t TPosixThread::SelfId()
{
   // Return the thread identifier for the calling thread.

   return (Long_t) pthread_self();
}

//   Clean Up section. PTHREAD implementations of cleanup after cancel are
//   too different and often too bad. Temporary I invent my own bicycle.
//                                                              V.Perev.

//______________________________________________________________________________
TPosixThreadCleanUp::TPosixThreadCleanUp(void **main, void *routine, void *arg)
{
   //cleanup function
   fNext = (TPosixThreadCleanUp*)*main;
   fRoutine = routine; fArgument = arg;
   *main  = this;
}
<commit_msg>document return codes.<commit_after>// @(#)root/thread:$Id$
// Author: Fons Rademakers   02/07/97

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TPosixThread                                                         //
//                                                                      //
// This class provides an interface to the posix thread routines.       //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TPosixThread.h"

ClassImp(TPosixThread)

//______________________________________________________________________________
Int_t TPosixThread::Run(TThread *th)
{
   // Create a pthread. Returns 0 on success, otherwise an error number will
   // be returned.

   int det;
   pthread_t id;
   pthread_attr_t *attr = new pthread_attr_t;

   pthread_attr_init(attr);

   // Set detach state
   det = (th->fDetached) ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE;

   pthread_attr_setdetachstate(attr, det);
   int ierr = pthread_create(&id, attr, &TThread::Function, th);
   if (!ierr) th->fId = (Long_t) id;

   pthread_attr_destroy(attr);
   delete attr;

   return ierr;
}

//______________________________________________________________________________
Int_t TPosixThread::Join(TThread *th, void **ret)
{
   // Join  suspends  the  execution  of the calling thread until the
   // thread identified by th terminates, either by  calling  pthread_exit
   // or by being cancelled. Returns 0 on success, otherwise an error number will
   // be returned.

   return pthread_join((pthread_t) th->fId, ret);
}

//______________________________________________________________________________
Int_t TPosixThread::Exit(void *ret)
{
   // Terminates the execution of the calling thread. Return 0.

   pthread_exit(ret);
   return 0;
}

//______________________________________________________________________________
Int_t TPosixThread::Kill(TThread *th)
{
   // Cancellation is the mechanism by which a thread can terminate the
   // execution of another thread. Returns 0 on success, otherwise an error
   // number will be returned.

   return pthread_cancel((pthread_t) th->fId);
}

//______________________________________________________________________________
Int_t TPosixThread::SetCancelOff()
{
   // Turn off the cancellation state of the calling thread. Returns 0 on
   // success, otherwise an error number will be returned.

   return pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0);
}

//______________________________________________________________________________
Int_t TPosixThread::SetCancelOn()
{
   // Turn on the cancellation state of the calling thread. Returns 0 on
   // success, otherwise an error number will be returned.

   return pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
}

//______________________________________________________________________________
Int_t TPosixThread::SetCancelAsynchronous()
{
   // Set the cancellation response type of the calling thread to
   // asynchronous, i.e. cancel as soon as the cancellation request
   // is received.

   return pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
}

//______________________________________________________________________________
Int_t TPosixThread::SetCancelDeferred()
{
   // Set the cancellation response type of the calling thread to
   // deferred, i.e. cancel only at next cancellation point.
   // Returns 0 on success, otherwise an error number will be returned.

   return pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, 0);
}

//______________________________________________________________________________
Int_t TPosixThread::CancelPoint()
{
   // Introduce an explicit cancellation point. Returns 0.

   int istate;
   pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &istate);
   pthread_testcancel();
   pthread_setcancelstate(istate, 0);

   return 0;
}

//______________________________________________________________________________
Int_t TPosixThread::CleanUpPush(void **main, void *free, void *arg)
{
   // Add thread cleanup function.

   // pthread_cleanup_push(free, arg);
   if (!free) Error("CleanUpPush", "cleanup rountine = 0");
   new TPosixThreadCleanUp(main, free, arg);
   return 0;
}

//______________________________________________________________________________
Int_t TPosixThread::CleanUpPop(void **main,Int_t exe)
{
   // Pop thread cleanup function from stack.

   //  pthread_cleanup_pop(exe); // happy pthread future

   if (!main || !*main) return 1;
   TPosixThreadCleanUp *l = (TPosixThreadCleanUp*)(*main);
   if (!l->fRoutine) Error("CleanUpPop", "cleanup routine = 0");
   if (exe && l->fRoutine) ((void (*)(void*))(l->fRoutine))(l->fArgument);
   *main = l->fNext;  delete l;
   return 0;
}

//______________________________________________________________________________
Int_t TPosixThread::CleanUp(void **main)
{
   // Default thread cleanup routine.

   if (gDebug > 0)
      Info("Cleanup", "cleanup 0x%lx", (Long_t)*main);
   while (!CleanUpPop(main, 1)) { }
   return 0;
}

//______________________________________________________________________________
Long_t TPosixThread::SelfId()
{
   // Return the thread identifier for the calling thread.

   return (Long_t) pthread_self();
}

//   Clean Up section. PTHREAD implementations of cleanup after cancel are
//   too different and often too bad. Temporary I invent my own bicycle.
//                                                              V.Perev.

//______________________________________________________________________________
TPosixThreadCleanUp::TPosixThreadCleanUp(void **main, void *routine, void *arg)
{
   //cleanup function
   fNext = (TPosixThreadCleanUp*)*main;
   fRoutine = routine; fArgument = arg;
   *main  = this;
}
<|endoftext|>


<commit_before>/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include <sys/mman.h>
#include <limits.h>
#include <unistd.h>
#undef __USE_XOPEN
#include <signal.h>

#include "open/platform_types.h"
#include "port_crash_handler.h"
#include "port_malloc.h"
#include "stack_dump.h"
#include "../linux/include/gdb_crash_handler.h"
#include "signals_internal.h"
#include "port_thread_internal.h"

#define FLAG_CORE ((port_crash_handler_get_flags() & PORT_CRASH_DUMP_PROCESS_CORE) != 0)
#define FLAG_DBG  ((port_crash_handler_get_flags() & PORT_CRASH_CALL_DEBUGGER) != 0)

bool is_stack_overflow(port_tls_data_t* tlsdata, void* fault_addr)
{
    if (!tlsdata || !fault_addr)
        return false;

    if (tlsdata->guard_page_addr)
    {
        return (fault_addr >= tlsdata->guard_page_addr &&
                (size_t)fault_addr < (size_t)tlsdata->guard_page_addr
                                                + tlsdata->guard_page_size);
    }

    size_t stack_top =
        (size_t)tlsdata->stack_addr - tlsdata->stack_size + tlsdata->guard_page_size;

    // Determine that fault is beyond stack top
    return ((size_t)fault_addr < stack_top &&
            (size_t)fault_addr > stack_top - tlsdata->stack_size);
}

static void c_handler(Registers* pregs, size_t signum, void* fault_addr)
{ // this exception handler is executed *after* OS signal handler returned
    int result;
    port_tls_data_t* tlsdata = get_private_tls_data();

    switch ((int)signum)
    {
    case SIGSEGV:
        if (tlsdata->restore_guard_page)
        {
            // Now it's safe to disable alternative stack
            set_alt_stack(tlsdata, FALSE);
            result = port_process_signal(PORT_SIGNAL_STACK_OVERFLOW, pregs, fault_addr, FALSE);
        }
        else
            result = port_process_signal(PORT_SIGNAL_GPF, pregs, fault_addr, FALSE);
        break;
    case SIGFPE:
        result = port_process_signal(PORT_SIGNAL_ARITHMETIC, pregs, fault_addr, FALSE);
        break;
    case SIGTRAP:
        // Correct return address
        pregs->set_ip((void*)((POINTER_SIZE_INT)pregs->get_ip() - 1));
        result = port_process_signal(PORT_SIGNAL_BREAKPOINT, pregs, fault_addr, FALSE);
        break;
    case SIGINT:
        result = port_process_signal(PORT_SIGNAL_CTRL_C, pregs, fault_addr, FALSE);
        break;
    case SIGQUIT:
        result = port_process_signal(PORT_SIGNAL_QUIT, pregs, fault_addr, FALSE);
        break;
    case SIGABRT:
        result = port_process_signal(PORT_SIGNAL_ABORT, NULL, fault_addr, FALSE);
        break;
    default:
        result = port_process_signal(PORT_SIGNAL_UNKNOWN, pregs, fault_addr, TRUE);
    }

    if (result == 0)
    {
        // Restore guard page if needed
        if (tlsdata->restore_guard_page)
        {
            port_thread_restore_guard_page();
            tlsdata->restore_guard_page = FALSE;

            if (port_thread_detach_temporary() == 0)
                STD_FREE(tlsdata);
        }
        return;
    }

    // We've got a crash
    if (signum == SIGSEGV)
    {
        port_thread_restore_guard_page(); // To catch SO again
        tlsdata->restore_guard_page = FALSE;
    }

    if (result > 0) // invoke debugger
    { // Prepare second catch of signal to attach GDB from signal handler
        //assert(tlsdata); // Should be attached - provided by general_signal_handler
        tlsdata->debugger = TRUE;
        return; // To produce signal again
    }

    // result < 0 - exit process
    if (FLAG_CORE)
    { // Return to the same place to produce the same crash and generate core
        signal(signum, SIG_DFL); // setup default handler
        return;
    }

    // No core needed - simply terminate
    _exit(-1);
}

static void general_signal_handler(int signum, siginfo_t* info, void* context)
{
    Registers regs;

    if (!context)
        return;

    // Convert OS context to Registers
    port_thread_context_to_regs(&regs, (ucontext_t*)context);
    void* fault_addr = info ? info->si_addr : NULL;

    // Check if SIGSEGV is produced by port_read/write_memory
    port_tls_data_t* tlsdata = get_private_tls_data();
    if (tlsdata && tlsdata->violation_flag)
    {
        tlsdata->violation_flag = 0;
        regs.set_ip(tlsdata->restart_address);
        return;
    }

    if (!tlsdata) // Tread is not attached - attach thread temporarily
    {
        int res;
        tlsdata = (port_tls_data_t*)STD_MALLOC(sizeof(port_tls_data_t));

        if (tlsdata) // Try to attach the thread
            res = port_thread_attach_local(tlsdata, TRUE, TRUE, 0);

        if (!tlsdata || res != 0)
        { // Can't process correctly; perform default actions
            if (FLAG_DBG)
            {
                bool result = gdb_crash_handler(&regs);
                _exit(-1); // Exit process if not sucessful...
            }

            if (FLAG_CORE &&
                signum != SIGABRT) // SIGABRT can't be rethrown
            {
                signal(signum, SIG_DFL); // setup default handler
                return;
            }

            _exit(-1);
        }

        // SIGSEGV can represent SO which can't be processed out of signal handler
        if (signum == SIGSEGV && // This can occur only when a user set an alternative stack
            is_stack_overflow(tlsdata, fault_addr))
        {
            int result = port_process_signal(PORT_SIGNAL_STACK_OVERFLOW, &regs, fault_addr, FALSE);

            if (result == 0)
            {
                if (port_thread_detach_temporary() == 0)
                    STD_FREE(tlsdata);
                return;
            }

            if (result > 0)
                tlsdata->debugger = TRUE;
            else
            {
                if (FLAG_CORE)
                { // Rethrow crash to generate core
                    signal(signum, SIG_DFL); // setup default handler
                    return;
                }
                _exit(-1);
            }
        }
    }

    if (tlsdata->debugger)
    {
        bool result = gdb_crash_handler(&regs);
        _exit(-1); // Exit process if not sucessful...
    }

    if (signum == SIGABRT && // SIGABRT can't be trown again from c_handler
        FLAG_DBG)
    { // So attaching GDB right here
        bool result = gdb_crash_handler(&regs);
        _exit(-1); // Exit process if not sucessful...
    }

    if (signum == SIGSEGV &&
        is_stack_overflow(tlsdata, fault_addr))
    {
        // Second SO while previous SO is not processed yet - is GPF
        if (tlsdata->restore_guard_page)
            tlsdata->restore_guard_page = FALSE;
        else
        { // To process signal on protected stack area
            port_thread_clear_guard_page();
            // Note: the call above does not disable alternative stack
            // It can't be made while we are on alternative stack
            // Alt stack will be disabled explicitly in c_handler()
            tlsdata->restore_guard_page = TRUE;
        }
    }

    // Prepare registers for transfering control out of signal handler
    void* callback = (void*)&c_handler;

    port_set_longjump_regs(callback, &regs, 3,
                            &regs, (void*)(size_t)signum, fault_addr);

    // Convert prepared Registers back to OS context
    port_thread_regs_to_context((ucontext_t*)context, &regs);
    // Return from signal handler to go to C handler
}

struct sig_reg
{
    int signal;
    port_sigtype port_sig;
    int flags;
    bool set_up;
};

static sig_reg signals_used[] =
{
    { SIGTRAP, PORT_SIGNAL_BREAKPOINT, SA_SIGINFO, false },
    { SIGSEGV, PORT_SIGNAL_GPF,        SA_SIGINFO | SA_ONSTACK, false },
    { SIGFPE,  PORT_SIGNAL_ARITHMETIC, SA_SIGINFO, false },
    { SIGINT,  PORT_SIGNAL_CTRL_C,     SA_SIGINFO, false },
    { SIGQUIT, PORT_SIGNAL_QUIT,       SA_SIGINFO, false },
    { SIGABRT, PORT_SIGNAL_ABORT,      SA_SIGINFO, false }
};

static struct sigaction old_actions[sizeof(signals_used)/sizeof(signals_used[0])];

static void restore_signals()
{
    for (size_t i = 0; i < sizeof(signals_used)/sizeof(signals_used[0]); i++)
    {
        if (!signals_used[i].set_up)
            continue;

        signals_used[i].set_up = false;
        sigaction(signals_used[i].signal, &old_actions[i], NULL);
    }
}

int initialize_signals()
{
    struct sigaction sa;

    for (size_t i = 0; i < sizeof(signals_used)/sizeof(signals_used[0]); i++)
    {
        if (!sd_is_handler_registered(signals_used[i].port_sig) &&
            signals_used[i].signal != SIGSEGV) // Sigsegv is needed for port_memaccess
            continue;

        sigemptyset(&sa.sa_mask);
        sa.sa_flags = signals_used[i].flags;
        sa.sa_sigaction = &general_signal_handler;

        if (0 != sigaction(signals_used[i].signal, &sa, &old_actions[i]))
        {
            restore_signals();
            return -1;
        }

        signals_used[i].set_up = true;
    }

    // Prepare gdb crash handler
    if (!init_gdb_crash_handler())
    {
        restore_signals();
        return -1;
    }

    return 0;

} //initialize_signals

int shutdown_signals()
{
    cleanup_gdb_crash_handler();
    restore_signals();
    return 0;
} //shutdown_signals

void sig_process_crash_flags_change(unsigned added, unsigned removed)
{
// Still empty on Linux
}
<commit_msg>Applied patch for "[#HARMONY-6132] [drlvm][build] SSLSocketImplTest breaks in Fedora since hy.no.sig removal".<commit_after>/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include <sys/mman.h>
#include <limits.h>
#include <unistd.h>
#undef __USE_XOPEN
#include <signal.h>

#include "open/platform_types.h"
#include "port_crash_handler.h"
#include "port_malloc.h"
#include "stack_dump.h"
#include "../linux/include/gdb_crash_handler.h"
#include "signals_internal.h"
#include "port_thread_internal.h"

#define FLAG_CORE ((port_crash_handler_get_flags() & PORT_CRASH_DUMP_PROCESS_CORE) != 0)
#define FLAG_DBG  ((port_crash_handler_get_flags() & PORT_CRASH_CALL_DEBUGGER) != 0)

bool is_stack_overflow(port_tls_data_t* tlsdata, void* fault_addr)
{
    if (!tlsdata || !fault_addr)
        return false;

    if (tlsdata->guard_page_addr)
    {
        return (fault_addr >= tlsdata->guard_page_addr &&
                (size_t)fault_addr < (size_t)tlsdata->guard_page_addr
                                                + tlsdata->guard_page_size);
    }

    size_t stack_top =
        (size_t)tlsdata->stack_addr - tlsdata->stack_size + tlsdata->guard_page_size;

    // Determine that fault is beyond stack top
    return ((size_t)fault_addr < stack_top &&
            (size_t)fault_addr > stack_top - tlsdata->stack_size);
}

static void c_handler(Registers* pregs, size_t signum, void* fault_addr)
{ // this exception handler is executed *after* OS signal handler returned
    int result;
    port_tls_data_t* tlsdata = get_private_tls_data();

    switch ((int)signum)
    {
    case SIGSEGV:
        if (tlsdata->restore_guard_page)
        {
            // Now it's safe to disable alternative stack
            set_alt_stack(tlsdata, FALSE);
            result = port_process_signal(PORT_SIGNAL_STACK_OVERFLOW, pregs, fault_addr, FALSE);
        }
        else
            result = port_process_signal(PORT_SIGNAL_GPF, pregs, fault_addr, FALSE);
        break;
    case SIGFPE:
        result = port_process_signal(PORT_SIGNAL_ARITHMETIC, pregs, fault_addr, FALSE);
        break;
    case SIGTRAP:
        // Correct return address
        pregs->set_ip((void*)((POINTER_SIZE_INT)pregs->get_ip() - 1));
        result = port_process_signal(PORT_SIGNAL_BREAKPOINT, pregs, fault_addr, FALSE);
        break;
    case SIGINT:
        result = port_process_signal(PORT_SIGNAL_CTRL_C, pregs, fault_addr, FALSE);
        break;
    case SIGQUIT:
        result = port_process_signal(PORT_SIGNAL_QUIT, pregs, fault_addr, FALSE);
        break;
    case SIGABRT:
        result = port_process_signal(PORT_SIGNAL_ABORT, NULL, fault_addr, FALSE);
        break;
    default:
        result = port_process_signal(PORT_SIGNAL_UNKNOWN, pregs, fault_addr, TRUE);
    }

    if (result == 0)
    {
        // Restore guard page if needed
        if (tlsdata->restore_guard_page)
        {
            port_thread_restore_guard_page();
            tlsdata->restore_guard_page = FALSE;

            if (port_thread_detach_temporary() == 0)
                STD_FREE(tlsdata);
        }
        return;
    }

    // We've got a crash
    if (signum == SIGSEGV)
    {
        port_thread_restore_guard_page(); // To catch SO again
        tlsdata->restore_guard_page = FALSE;
    }

    if (result > 0) // invoke debugger
    { // Prepare second catch of signal to attach GDB from signal handler
        //assert(tlsdata); // Should be attached - provided by general_signal_handler
        tlsdata->debugger = TRUE;
        return; // To produce signal again
    }

    // result < 0 - exit process
    if (FLAG_CORE)
    { // Return to the same place to produce the same crash and generate core
        signal(signum, SIG_DFL); // setup default handler
        return;
    }

    // No core needed - simply terminate
    _exit(-1);
}

static void general_signal_handler(int signum, siginfo_t* info, void* context)
{
    Registers regs;

    if (!context)
        return;

    // Convert OS context to Registers
    port_thread_context_to_regs(&regs, (ucontext_t*)context);
    void* fault_addr = info ? info->si_addr : NULL;

    // Check if SIGSEGV is produced by port_read/write_memory
    port_tls_data_t* tlsdata = get_private_tls_data();
    if (tlsdata && tlsdata->violation_flag)
    {
        tlsdata->violation_flag = 0;
        regs.set_ip(tlsdata->restart_address);
        return;
    }

    if (!tlsdata) // Tread is not attached - attach thread temporarily
    {
        int res;
        tlsdata = (port_tls_data_t*)STD_MALLOC(sizeof(port_tls_data_t));

        if (tlsdata) // Try to attach the thread
            res = port_thread_attach_local(tlsdata, TRUE, TRUE, 0);

        if (!tlsdata || res != 0)
        { // Can't process correctly; perform default actions
            if (FLAG_DBG)
            {
                bool result = gdb_crash_handler(&regs);
                _exit(-1); // Exit process if not sucessful...
            }

            if (FLAG_CORE &&
                signum != SIGABRT) // SIGABRT can't be rethrown
            {
                signal(signum, SIG_DFL); // setup default handler
                return;
            }

            _exit(-1);
        }

        // SIGSEGV can represent SO which can't be processed out of signal handler
        if (signum == SIGSEGV && // This can occur only when a user set an alternative stack
            is_stack_overflow(tlsdata, fault_addr))
        {
            int result = port_process_signal(PORT_SIGNAL_STACK_OVERFLOW, &regs, fault_addr, FALSE);

            if (result == 0)
            {
                if (port_thread_detach_temporary() == 0)
                    STD_FREE(tlsdata);
                return;
            }

            if (result > 0)
                tlsdata->debugger = TRUE;
            else
            {
                if (FLAG_CORE)
                { // Rethrow crash to generate core
                    signal(signum, SIG_DFL); // setup default handler
                    return;
                }
                _exit(-1);
            }
        }
    }

    if (tlsdata->debugger)
    {
        bool result = gdb_crash_handler(&regs);
        _exit(-1); // Exit process if not sucessful...
    }

    if (signum == SIGABRT && // SIGABRT can't be trown again from c_handler
        FLAG_DBG)
    { // So attaching GDB right here
        bool result = gdb_crash_handler(&regs);
        _exit(-1); // Exit process if not sucessful...
    }

    if (signum == SIGSEGV &&
        is_stack_overflow(tlsdata, fault_addr))
    {
        // Second SO while previous SO is not processed yet - is GPF
        if (tlsdata->restore_guard_page)
            tlsdata->restore_guard_page = FALSE;
        else
        { // To process signal on protected stack area
            port_thread_clear_guard_page();
            // Note: the call above does not disable alternative stack
            // It can't be made while we are on alternative stack
            // Alt stack will be disabled explicitly in c_handler()
            tlsdata->restore_guard_page = TRUE;
        }
    }

    // Prepare registers for transfering control out of signal handler
    void* callback = (void*)&c_handler;

    port_set_longjump_regs(callback, &regs, 3,
                            &regs, (void*)(size_t)signum, fault_addr);

    // Convert prepared Registers back to OS context
    port_thread_regs_to_context((ucontext_t*)context, &regs);
    // Return from signal handler to go to C handler
}

struct sig_reg
{
    int signal;
    port_sigtype port_sig;
    int flags;
    bool set_up;
};

static sig_reg signals_used[] =
{
    { SIGTRAP, PORT_SIGNAL_BREAKPOINT, SA_SIGINFO, false },
    { SIGSEGV, PORT_SIGNAL_GPF,        SA_SIGINFO | SA_ONSTACK, false },
    { SIGFPE,  PORT_SIGNAL_ARITHMETIC, SA_SIGINFO, false },
    { SIGINT,  PORT_SIGNAL_CTRL_C,     SA_SIGINFO, false },
    { SIGQUIT, PORT_SIGNAL_QUIT,       SA_SIGINFO, false },
    { SIGABRT, PORT_SIGNAL_ABORT,      SA_SIGINFO, false }
};

static struct sigaction old_actions[sizeof(signals_used)/sizeof(signals_used[0])];

// For signals that must change their default behavior
struct sig_redef
{
    int             signal;
    sighandler_t    handler;
    bool            set_up;
};

static sig_redef signals_other[] =
{
    { SIGPIPE, SIG_IGN, false }
};

static sighandler_t old_handlers[sizeof(signals_other)/sizeof(signals_other[0])];

static void restore_signals()
{
    for (size_t i = 0; i < sizeof(signals_used)/sizeof(signals_used[0]); i++)
    {
        if (!signals_used[i].set_up)
            continue;

        signals_used[i].set_up = false;
        sigaction(signals_used[i].signal, &old_actions[i], NULL);
    }
    for (size_t j = 0; j < sizeof(signals_other)/sizeof(signals_other[0]); j++)
    {
        if (!signals_other[j].set_up)
            continue;

        signals_other[j].set_up = false;
        signal(signals_other[j].signal, old_handlers[j]);
    }
}

int initialize_signals()
{
    struct sigaction sa;

    for (size_t i = 0; i < sizeof(signals_used)/sizeof(signals_used[0]); i++)
    {
        if (!sd_is_handler_registered(signals_used[i].port_sig) &&
            signals_used[i].signal != SIGSEGV) // Sigsegv is needed for port_memaccess
            continue;

        sigemptyset(&sa.sa_mask);
        sa.sa_flags = signals_used[i].flags;
        sa.sa_sigaction = &general_signal_handler;

        if (0 != sigaction(signals_used[i].signal, &sa, &old_actions[i]))
        {
            restore_signals();
            return -1;
        }

        signals_used[i].set_up = true;
    }

    for (size_t j = 0; j < sizeof(signals_other)/sizeof(signals_other[0]); j++)
    {
        old_handlers[j] = signal(signals_other[j].signal, signals_other[j].handler);
        if (old_handlers[j] == SIG_ERR)
        {
            restore_signals();
            return -1;
        }
        signals_other[j].set_up = true;
    }

    // Prepare gdb crash handler
    if (!init_gdb_crash_handler())
    {
        restore_signals();
        return -1;
    }

    return 0;

} //initialize_signals

int shutdown_signals()
{
    cleanup_gdb_crash_handler();
    restore_signals();
    return 0;
} //shutdown_signals

void sig_process_crash_flags_change(unsigned added, unsigned removed)
{
// Still empty on Linux
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/renderer/pepper/pepper_platform_image_2d_impl.h"

#include "build/build_config.h"
#include "content/common/view_messages.h"
#include "content/renderer/render_thread_impl.h"
#include "ui/surface/transport_dib.h"

namespace content {

PepperPlatformImage2DImpl::PepperPlatformImage2DImpl(int width,
                                                     int height,
                                                     TransportDIB* dib)
    : width_(width),
      height_(height),
      dib_(dib) {
}

// On Mac, we have to tell the browser to free the transport DIB.
PepperPlatformImage2DImpl::~PepperPlatformImage2DImpl() {
#if defined(OS_MACOSX)
  if (dib_.get()) {
    RenderThreadImpl::current()->Send(
        new ViewHostMsg_FreeTransportDIB(dib_->id()));
  }
#endif
}

// static
PepperPlatformImage2DImpl* PepperPlatformImage2DImpl::Create(int width,
                                                             int height) {
  uint32 buffer_size = width * height * 4;

  // Allocate the transport DIB and the PlatformCanvas pointing to it.
#if defined(OS_MACOSX)
  // On the Mac, shared memory has to be created in the browser in order to
  // work in the sandbox.  Do this by sending a message to the browser
  // requesting a TransportDIB (see also
  // chrome/renderer/webplugin_delegate_proxy.cc, method
  // WebPluginDelegateProxy::CreateBitmap() for similar code). The TransportDIB
  // is cached in the browser, and is freed (in typical cases) by the
  // PepperPlatformImage2DImpl's destructor.
  TransportDIB::Handle dib_handle;
  IPC::Message* msg = new ViewHostMsg_AllocTransportDIB(buffer_size,
                                                        true,
                                                        &dib_handle);
  if (!RenderThreadImpl::current()->Send(msg))
    return NULL;
  if (!TransportDIB::is_valid_handle(dib_handle))
    return NULL;

  TransportDIB* dib = TransportDIB::Map(dib_handle);
#else
  static int next_dib_id = 0;
  TransportDIB* dib = TransportDIB::Create(buffer_size, next_dib_id++);
  if (!dib)
    return NULL;
#endif

  return new PepperPlatformImage2DImpl(width, height, dib);
}

skia::PlatformCanvas* PepperPlatformImage2DImpl::Map() {
  return dib_->GetPlatformCanvas(width_, height_);
}

intptr_t PepperPlatformImage2DImpl::GetSharedMemoryHandle(
    uint32* byte_count) const {
  *byte_count = dib_->size();
#if defined(OS_WIN)
  return reinterpret_cast<intptr_t>(dib_->handle());
#elif defined(OS_MACOSX) || defined(OS_ANDROID)
  return static_cast<intptr_t>(dib_->handle().fd);
#elif defined(OS_POSIX)
  return static_cast<intptr_t>(dib_->handle());
#endif
}

TransportDIB* PepperPlatformImage2DImpl::GetTransportDIB() const {
  return dib_.get();
}

}  // namespace content
<commit_msg>PepperPlatformImage2DImpl: don't immediately map shared memory<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/renderer/pepper/pepper_platform_image_2d_impl.h"

#include "build/build_config.h"
#include "content/common/view_messages.h"
#include "content/renderer/render_thread_impl.h"
#include "ui/surface/transport_dib.h"

namespace content {

PepperPlatformImage2DImpl::PepperPlatformImage2DImpl(int width,
                                                     int height,
                                                     TransportDIB* dib)
    : width_(width),
      height_(height),
      dib_(dib) {
}

// On Mac, we have to tell the browser to free the transport DIB.
PepperPlatformImage2DImpl::~PepperPlatformImage2DImpl() {
#if defined(OS_MACOSX)
  if (dib_.get()) {
    RenderThreadImpl::current()->Send(
        new ViewHostMsg_FreeTransportDIB(dib_->id()));
  }
#endif
}

// static
PepperPlatformImage2DImpl* PepperPlatformImage2DImpl::Create(int width,
                                                             int height) {
  uint32 buffer_size = width * height * 4;

  // Allocate the transport DIB and the PlatformCanvas pointing to it.
#if defined(OS_MACOSX)
  // On the Mac, shared memory has to be created in the browser in order to
  // work in the sandbox.  Do this by sending a message to the browser
  // requesting a TransportDIB (see also
  // chrome/renderer/webplugin_delegate_proxy.cc, method
  // WebPluginDelegateProxy::CreateBitmap() for similar code). The TransportDIB
  // is cached in the browser, and is freed (in typical cases) by the
  // PepperPlatformImage2DImpl's destructor.
  TransportDIB::Handle dib_handle;
  IPC::Message* msg = new ViewHostMsg_AllocTransportDIB(buffer_size,
                                                        true,
                                                        &dib_handle);
  if (!RenderThreadImpl::current()->Send(msg))
    return NULL;
  if (!TransportDIB::is_valid_handle(dib_handle))
    return NULL;

  TransportDIB* dib = TransportDIB::CreateWithHandle(dib_handle);
#else
  static int next_dib_id = 0;
  TransportDIB* dib = TransportDIB::Create(buffer_size, next_dib_id++);
  if (!dib)
    return NULL;
#endif

  return new PepperPlatformImage2DImpl(width, height, dib);
}

skia::PlatformCanvas* PepperPlatformImage2DImpl::Map() {
  return dib_->GetPlatformCanvas(width_, height_);
}

intptr_t PepperPlatformImage2DImpl::GetSharedMemoryHandle(
    uint32* byte_count) const {
  *byte_count = dib_->size();
#if defined(OS_WIN)
  return reinterpret_cast<intptr_t>(dib_->handle());
#elif defined(OS_MACOSX) || defined(OS_ANDROID)
  return static_cast<intptr_t>(dib_->handle().fd);
#elif defined(OS_POSIX)
  return static_cast<intptr_t>(dib_->handle());
#endif
}

TransportDIB* PepperPlatformImage2DImpl::GetTransportDIB() const {
  return dib_.get();
}

}  // namespace content
<|endoftext|>