Base* DispatcherHost::GetApiObject(int id) {

// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "content/nw/src/shell_content_browser_client.h"

#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/file_util.h"
#include "base/string_util.h"
#include "base/threading/thread_restrictions.h"
#include "base/values.h"
#include "content/public/browser/browser_url_handler.h"
#include "content/nw/src/browser/printing/printing_message_filter.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/resource_dispatcher_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/renderer_preferences.h"
#include "content/nw/src/api/dispatcher_host.h"
#include "content/nw/src/common/shell_switches.h"
#include "content/nw/src/browser/printing/print_job_manager.h"
#include "content/nw/src/browser/shell_devtools_delegate.h"
#include "content/nw/src/browser/shell_resource_dispatcher_host_delegate.h"
#include "content/nw/src/media/media_internals.h"
#include "content/nw/src/nw_package.h"
#include "content/nw/src/nw_shell.h"
#include "content/nw/src/nw_version.h"
#include "content/nw/src/shell_browser_context.h"
#include "content/nw/src/shell_browser_main_parts.h"
#include "geolocation/shell_access_token_store.h"
#include "googleurl/src/gurl.h"
#include "webkit/glue/webpreferences.h"
#include "webkit/user_agent/user_agent_util.h"
#include "ui/base/l10n/l10n_util.h"
#include "webkit/plugins/npapi/plugin_list.h"

namespace content {

ShellContentBrowserClient::ShellContentBrowserClient()
    : shell_browser_main_parts_(NULL) {
}

ShellContentBrowserClient::~ShellContentBrowserClient() {
}

BrowserMainParts* ShellContentBrowserClient::CreateBrowserMainParts(
    const MainFunctionParams& parameters) {
  shell_browser_main_parts_ = new ShellBrowserMainParts(parameters);
  return shell_browser_main_parts_;
}

WebContentsViewPort* ShellContentBrowserClient::OverrideCreateWebContentsView(
      WebContents* web_contents,
      RenderViewHostDelegateView** render_view_host_delegate_view) {
  std::string user_agent, rules;
  nw::Package* package = shell_browser_main_parts()->package();
  content::RendererPreferences* prefs = web_contents->GetMutableRendererPrefs();
  if (package->root()->GetString(switches::kmUserAgent, &user_agent)) {
    std::string name, version;
    package->root()->GetString(switches::kmName, &name);
    package->root()->GetString("version", &version);
    ReplaceSubstringsAfterOffset(&user_agent, 0, "%name", name);
    ReplaceSubstringsAfterOffset(&user_agent, 0, "%ver", version);
    ReplaceSubstringsAfterOffset(&user_agent, 0, "%nwver", NW_VERSION_STRING);
    ReplaceSubstringsAfterOffset(&user_agent, 0, "%webkit_ver", webkit_glue::GetWebKitVersion());
    ReplaceSubstringsAfterOffset(&user_agent, 0, "%osinfo", webkit_glue::BuildOSInfo());
    prefs->user_agent_override = user_agent;
  }
  if (package->root()->GetString(switches::kmRemotePages, &rules))
      prefs->nw_remote_page_rules = rules;
  return NULL;
}

void ShellContentBrowserClient::RenderViewHostCreated(
    RenderViewHost* render_view_host) {
  new api::DispatcherHost(render_view_host);
}

std::string ShellContentBrowserClient::GetApplicationLocale() {
  return l10n_util::GetApplicationLocale("en-US");
}

void ShellContentBrowserClient::AppendExtraCommandLineSwitches(
    CommandLine* command_line,
    int child_process_id) {
  if (command_line->GetSwitchValueASCII("type") != "renderer")
    return;
  if (child_process_id > 0) {
    content::RenderProcessHost* rph =
      content::RenderProcessHost::FromID(child_process_id);

    content::RenderProcessHost::RenderWidgetHostsIterator iter(
      rph->GetRenderWidgetHostsIterator());
    for (; !iter.IsAtEnd(); iter.Advance()) {
      const content::RenderWidgetHost* widget = iter.GetCurrentValue();
      DCHECK(widget);
      if (!widget || !widget->IsRenderView())
        continue;

      content::RenderViewHost* host = content::RenderViewHost::From(
        const_cast<content::RenderWidgetHost*>(widget));
      content::Shell* shell = content::Shell::FromRenderViewHost(host);
      if (shell && (shell->is_devtools() || !shell->nodejs()))
        return;
    }
  }
  nw::Package* package = shell_browser_main_parts()->package();
  if (package && package->GetUseNode()) {
    // Allow node.js
    command_line->AppendSwitch(switches::kNodejs);

    // Set cwd
    command_line->AppendSwitchPath(switches::kWorkingDirectory,
                                   package->path());

    // Check if we have 'node-main'.
    std::string node_main;
    if (package->root()->GetString(switches::kNodeMain, &node_main))
      command_line->AppendSwitchASCII(switches::kNodeMain, node_main);

    std::string snapshot_path;
    if (package->root()->GetString(switches::kSnapshot, &snapshot_path))
      command_line->AppendSwitchASCII(switches::kSnapshot, snapshot_path);
  }

  // without the switch, the destructor of the shell object will
  // shutdown renderwidgethost (RenderWidgetHostImpl::Shutdown) and
  // destory rph immediately. Then the channel error msg is caught by
  // SuicideOnChannelErrorFilter and the renderer is killed
  // immediately
#if defined(OS_POSIX)
  command_line->AppendSwitch(switches::kChildCleanExit);
#endif
}

void ShellContentBrowserClient::ResourceDispatcherHostCreated() {
  resource_dispatcher_host_delegate_.reset(
      new ShellResourceDispatcherHostDelegate());
  ResourceDispatcherHost::Get()->SetDelegate(
      resource_dispatcher_host_delegate_.get());
}

std::string ShellContentBrowserClient::GetDefaultDownloadName() {
  return "download";
}

MediaObserver* ShellContentBrowserClient::GetMediaObserver() {
  return MediaInternals::GetInstance();
}

void ShellContentBrowserClient::BrowserURLHandlerCreated(
    BrowserURLHandler* handler) {
}

ShellBrowserContext* ShellContentBrowserClient::browser_context() {
  return shell_browser_main_parts_->browser_context();
}

ShellBrowserContext*
    ShellContentBrowserClient::off_the_record_browser_context() {
  return shell_browser_main_parts_->off_the_record_browser_context();
}

AccessTokenStore* ShellContentBrowserClient::CreateAccessTokenStore() {
  return new ShellAccessTokenStore(browser_context()->GetRequestContext());
}

void ShellContentBrowserClient::OverrideWebkitPrefs(
      RenderViewHost* render_view_host,
      const GURL& url,
      webkit_glue::WebPreferences* prefs) {
  nw::Package* package = shell_browser_main_parts()->package();

  // Disable web security.
  prefs->dom_paste_enabled = true;
  prefs->javascript_can_access_clipboard = true;
  prefs->web_security_enabled = false;
  prefs->allow_file_access_from_file_urls = true;

  // Open experimental features.
  prefs->css_sticky_position_enabled = true;
  prefs->css_shaders_enabled = true;
  prefs->css_variables_enabled = true;

  // Disable plugins and cache by default.
  prefs->plugins_enabled = false;
  prefs->java_enabled = false;
  prefs->uses_page_cache = false;

  base::DictionaryValue* webkit;
  if (package->root()->GetDictionary(switches::kmWebkit, &webkit)) {
    webkit->GetBoolean(switches::kmJava, &prefs->java_enabled);
    webkit->GetBoolean(switches::kmPlugin, &prefs->plugins_enabled);
    webkit->GetBoolean(switches::kmPageCache, &prefs->uses_page_cache);
    FilePath plugins_dir = package->path();
    //PathService::Get(base::DIR_CURRENT, &plugins_dir);
    plugins_dir = plugins_dir.AppendASCII("plugins");

    webkit::npapi::PluginList::Singleton()->AddExtraPluginDir(plugins_dir);
  }
}

bool ShellContentBrowserClient::ShouldTryToUseExistingProcessHost(
      BrowserContext* browser_context, const GURL& url) {
  ShellBrowserContext* shell_browser_context =
    static_cast<ShellBrowserContext*>(browser_context);
  if (shell_browser_context->pinning_renderer())
    return true;
  else
    return false;
}

bool ShellContentBrowserClient::IsSuitableHost(RenderProcessHost* process_host,
                                          const GURL& site_url) {
  return true;
}

net::URLRequestContextGetter* ShellContentBrowserClient::CreateRequestContext(
    BrowserContext* content_browser_context,
    scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
        blob_protocol_handler,
    scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
        file_system_protocol_handler,
    scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
        developer_protocol_handler,
    scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
        chrome_protocol_handler,
    scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
        chrome_devtools_protocol_handler) {
  ShellBrowserContext* shell_browser_context =
      ShellBrowserContextForBrowserContext(content_browser_context);
  return shell_browser_context->CreateRequestContext(
      blob_protocol_handler.Pass(), file_system_protocol_handler.Pass(),
      developer_protocol_handler.Pass(), chrome_protocol_handler.Pass(),
      chrome_devtools_protocol_handler.Pass());
}

net::URLRequestContextGetter*
ShellContentBrowserClient::CreateRequestContextForStoragePartition(
    BrowserContext* content_browser_context,
    const base::FilePath& partition_path,
    bool in_memory,
    scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
        blob_protocol_handler,
    scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
        file_system_protocol_handler,
    scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
        developer_protocol_handler,
    scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
        chrome_protocol_handler,
    scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
        chrome_devtools_protocol_handler) {
  ShellBrowserContext* shell_browser_context =
      ShellBrowserContextForBrowserContext(content_browser_context);
  return shell_browser_context->CreateRequestContextForStoragePartition(
      partition_path, in_memory, blob_protocol_handler.Pass(),
      file_system_protocol_handler.Pass(),
      developer_protocol_handler.Pass(), chrome_protocol_handler.Pass(),
      chrome_devtools_protocol_handler.Pass());
}

ShellBrowserContext*
ShellContentBrowserClient::ShellBrowserContextForBrowserContext(
    BrowserContext* content_browser_context) {
  if (content_browser_context == browser_context())
    return browser_context();
  DCHECK_EQ(content_browser_context, off_the_record_browser_context());
  return off_the_record_browser_context();
}

printing::PrintJobManager* ShellContentBrowserClient::print_job_manager() {
  return shell_browser_main_parts_->print_job_manager();
}

void ShellContentBrowserClient::RenderProcessHostCreated(
    RenderProcessHost* host) {
  int id = host->GetID();
#if defined(ENABLE_PRINTING)
  host->GetChannel()->AddFilter(new PrintingMessageFilter(id));
#endif
}
}  // namespace content


keep keep keep keep replace keep keep keep


// 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/nw/src/common/print_messages.h"

#include "base/basictypes.h"
#include "base/string16.h"
#include "ui/gfx/size.h"

PrintMsg_Print_Params::PrintMsg_Print_Params()
  : page_size(),
    content_size(),
    printable_area(),
    margin_top(0),
    margin_left(0),
    dpi(0),
    min_shrink(0),
    max_shrink(0),
    desired_dpi(0),
    document_cookie(0),
    selection_only(false),
    supports_alpha_blend(false),
    preview_ui_id(-1),
    preview_request_id(0),
    is_first_request(false),
    print_scaling_option(WebKit::WebPrintScalingOptionSourceSize),
    print_to_pdf(false),
    display_header_footer(false),
    date(),
    title(),
    url(),
    should_print_backgrounds(false) {
}

PrintMsg_Print_Params::~PrintMsg_Print_Params() {}

void PrintMsg_Print_Params::Reset() {
  page_size = gfx::Size();
  content_size = gfx::Size();
  printable_area = gfx::Rect();
  margin_top = 0;
  margin_left = 0;
  dpi = 0;
  min_shrink = 0;
  max_shrink = 0;
  desired_dpi = 0;
  document_cookie = 0;
  selection_only = false;
  supports_alpha_blend = false;
  preview_ui_id = -1;
  preview_request_id = 0;
  is_first_request = false;
  print_scaling_option = WebKit::WebPrintScalingOptionSourceSize;
  print_to_pdf = false;
  display_header_footer = false;
  date = string16();
  title = string16();
  url = string16();
  should_print_backgrounds = false;
}

PrintMsg_PrintPages_Params::PrintMsg_PrintPages_Params()
  : pages() {
}

PrintMsg_PrintPages_Params::~PrintMsg_PrintPages_Params() {}

void PrintMsg_PrintPages_Params::Reset() {
  params.Reset();
  pages = std::vector<int>();
}

PrintHostMsg_RequestPrintPreview_Params::
    PrintHostMsg_RequestPrintPreview_Params()
    : is_modifiable(false),
      webnode_only(false),
      has_selection(false),
      selection_only(false) {
}

PrintHostMsg_RequestPrintPreview_Params::
    ~PrintHostMsg_RequestPrintPreview_Params() {}


// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "content/nw/src/api/menu/menu.h"

#include "base/message_loop.h"
#include "base/mac/scoped_sending_event.h"
#include "base/values.h"
#import <Cocoa/Cocoa.h>
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
#include "content/nw/src/api/menuitem/menuitem.h"
#include "content/nw/src/browser/native_window_mac.h"
#include "content/nw/src/nw_shell.h"

namespace api {

void Menu::Create(const base::DictionaryValue& option) {
  menu_ = [[NSMenu alloc] initWithTitle:@"NW Menu"];
  [menu_ setAutoenablesItems:NO];

  std::string type;
  if (option.GetString("type", &type) && type == "menubar") {
    // Preserve the apple menu.
    [menu_ addItem:[[[NSMenuItem alloc]
        initWithTitle:@"" action:nil keyEquivalent:@""] autorelease]];
  }
}

void Menu::Destroy() {
  [menu_ release];
}

void Menu::Append(MenuItem* menu_item) {
  [menu_ addItem:menu_item->menu_item_];
}

void Menu::Insert(MenuItem* menu_item, int pos) {
  [menu_ insertItem:menu_item->menu_item_ atIndex:pos];
}

void Menu::Remove(MenuItem* menu_item, int pos) {
  [menu_ removeItem:menu_item->menu_item_];
}

void Menu::Popup(int x, int y, content::Shell* shell) {
  // Fake out a context menu event for our menu
  NSWindow* window =
       static_cast<nw::NativeWindowCocoa*>(shell->window())->window();
  NSEvent* currentEvent = [NSApp currentEvent];
  NSView* web_view = shell->web_contents()->GetView()->GetNativeView();
  NSPoint position = { x, web_view.bounds.size.height - y };
  NSTimeInterval eventTime = [currentEvent timestamp];
  NSEvent* clickEvent = [NSEvent mouseEventWithType:NSRightMouseDown
                                           location:position
                                      modifierFlags:NSRightMouseDownMask
                                          timestamp:eventTime
                                       windowNumber:[window windowNumber]
                                            context:nil
                                        eventNumber:0
                                         clickCount:1
                                           pressure:1.0];

  {
    // Make sure events can be pumped while the menu is up.
    MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());

    // One of the events that could be pumped is |window.close()|.
    // User-initiated event-tracking loops protect against this by
    // setting flags in -[CrApplication sendEvent:], but since
    // web-content menus are initiated by IPC message the setup has to
    // be done manually.
    base::mac::ScopedSendingEvent sendingEventScoper;

    // Show the menu.
    [NSMenu popUpContextMenu:menu_
                   withEvent:clickEvent
                     forView:web_view];
  }
}

}  // namespace api


api::App::Call(shell, method, arguments, result);

// 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.

#ifndef CONTENT_SHELL_SHELL_CONTENT_BROWSER_CLIENT_H_
#define CONTENT_SHELL_SHELL_CONTENT_BROWSER_CLIENT_H_

#include <string>
#include <map>

#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/web_contents_view.h"

namespace printing {
class PrintJobManager;
}

namespace content {

class ShellBrowserContext;
class ShellBrowserMainParts;
class ShellResourceDispatcherHostDelegate;

class ShellContentBrowserClient : public ContentBrowserClient {
 public:
  ShellContentBrowserClient();
  virtual ~ShellContentBrowserClient();

  // ContentBrowserClient overrides.
  virtual BrowserMainParts* CreateBrowserMainParts(
      const MainFunctionParams& parameters) OVERRIDE;
  virtual void RenderViewHostCreated(
      RenderViewHost* render_view_host) OVERRIDE;
  virtual WebContentsViewPort* OverrideCreateWebContentsView(
      WebContents* web_contents,
      RenderViewHostDelegateView** render_view_host_delegate_view) OVERRIDE;
  virtual std::string GetApplicationLocale() OVERRIDE;
  virtual void AppendExtraCommandLineSwitches(CommandLine* command_line,
                                              int child_process_id) OVERRIDE;
  virtual void ResourceDispatcherHostCreated() OVERRIDE;
  virtual AccessTokenStore* CreateAccessTokenStore() OVERRIDE;
  virtual void OverrideWebkitPrefs(
      RenderViewHost* render_view_host,
      const GURL& url,
      webkit_glue::WebPreferences* prefs) OVERRIDE;
  virtual std::string GetDefaultDownloadName() OVERRIDE;
  virtual MediaObserver* GetMediaObserver() OVERRIDE;
  virtual void BrowserURLHandlerCreated(BrowserURLHandler* handler) OVERRIDE;
  virtual bool ShouldTryToUseExistingProcessHost(
      BrowserContext* browser_context, const GURL& url) OVERRIDE;
  virtual bool IsSuitableHost(RenderProcessHost* process_host,
                              const GURL& site_url) OVERRIDE;
  ShellBrowserContext* browser_context();
  ShellBrowserContext* off_the_record_browser_context();
  ShellResourceDispatcherHostDelegate* resource_dispatcher_host_delegate() {
    return resource_dispatcher_host_delegate_.get();
  }
  ShellBrowserMainParts* shell_browser_main_parts() {
    return shell_browser_main_parts_;
  }
  virtual printing::PrintJobManager* print_job_manager();
  virtual void RenderProcessHostCreated(RenderProcessHost* host) OVERRIDE;
  virtual net::URLRequestContextGetter* CreateRequestContext(
      BrowserContext* browser_context,
      scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
          blob_protocol_handler,
      scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
          file_system_protocol_handler,
      scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
          developer_protocol_handler,
      scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
          chrome_protocol_handler,
      scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
          chrome_devtools_protocol_handler) OVERRIDE;
  virtual net::URLRequestContextGetter* CreateRequestContextForStoragePartition(
      BrowserContext* browser_context,
      const base::FilePath& partition_path,
      bool in_memory,
      scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
          blob_protocol_handler,
      scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
          file_system_protocol_handler,
      scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
          developer_protocol_handler,
      scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
          chrome_protocol_handler,
      scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
          chrome_devtools_protocol_handler) OVERRIDE;

 private:
  ShellBrowserContext* ShellBrowserContextForBrowserContext(
      BrowserContext* content_browser_context);
  scoped_ptr<ShellResourceDispatcherHostDelegate>
      resource_dispatcher_host_delegate_;

  ShellBrowserMainParts* shell_browser_main_parts_;
};

}  // namespace content

#endif  // CONTENT_SHELL_SHELL_CONTENT_BROWSER_CLIENT_H_


// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "content/nw/src/api/clipboard/clipboard.h"

#include "base/values.h"
#include "base/utf_string_conversions.h"
#include "base/string16.h"
#include "content/nw/src/api/dispatcher_host.h"
#include "ui/base/clipboard/clipboard.h"

namespace api {

Clipboard::Clipboard(int id,
           DispatcherHost* dispatcher_host,
           const base::DictionaryValue& option)
    : Base(id, dispatcher_host, option) {
}

Clipboard::~Clipboard() {
}

void Clipboard::Call(const std::string& method,
                     const base::ListValue& arguments) {
  if (method == "Set") {
    std::string text, type;
    arguments.GetString(0, &text);
    arguments.GetString(1, &type);
    SetText(text);
  } else if (method == "Clear") {
    Clear();
  } else {
    NOTREACHED() << "Invalid call to Clipboard method:" << method
                 << " arguments:" << arguments;
  }
}

void Clipboard::CallSync(const std::string& method,
                         const base::ListValue& arguments,
                         base::ListValue* result) {
  if (method == "Get") {
    result->AppendString(GetText());
  } else {
    NOTREACHED() << "Invalid call to Clipboard method:" << method
                 << " arguments:" << arguments;
  }
}

void Clipboard::SetText(std::string& text) {
  ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
  ui::Clipboard::ObjectMap map;
  map[ui::Clipboard::CBF_TEXT].push_back(
      std::vector<char>(text.begin(), text.end()));
  clipboard->WriteObjects(ui::Clipboard::BUFFER_STANDARD, map, NULL);
}

std::string Clipboard::GetText() {
  ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
  string16 text;
  clipboard->ReadText(ui::Clipboard::BUFFER_STANDARD, &text);
  return UTF16ToUTF8(text);
}

void Clipboard::Clear() {
  ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
  clipboard->Clear(ui::Clipboard::BUFFER_STANDARD);
}

}  // namespace api


// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#import "content/nw/src/api/menuitem/menuitem_delegate_mac.h"

#include "base/values.h"
#include "content/nw/src/api/dispatcher_host.h"
#include "content/nw/src/api/menuitem/menuitem.h"

@implementation MenuItemDelegate

-(id)initWithMenuItem: (api::MenuItem*)item {
  if ([super init]) {
    menu_item_ = item;
  }

  return self;
}

-(void)invoke: (id)sender {
  menu_item_->OnClick();

  // Send event.
  base::ListValue args;
  menu_item_->dispatcher_host()->SendEvent(menu_item_, "click", args);
}

@end


var path = require('path');
var app_test = require('./nw_test_app');

describe('Plugin', function() {
  describe('flash', function(){
    it('should not crash', function(done) {
      var result = false;

      var child = app_test.createChildProcess({
        execPath: process.execPath,
        appPath: path.join('app_tests', 'plugin', 'flash'),
        end: function(data, app) {
          done();
          result = true;
          app.kill();
        }
      });

      setTimeout(function(){
        if (!result) {
          done('nw crash.');
          child.removeConnection();
        }
      }, 1000);

    })
  })
})


NOTREACHED() << "Calling unknown method " << method << " of class " << type;

void DispatcherHost::OnUncaughtException(const std::string& err) {

shell->PrintCriticalError("Uncaught node.js Error", err);

void DispatcherHost::OnGetShellId(int* id) {

keep keep keep keep keep replace keep keep keep keep keep


// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "content/nw/src/api/menu/menu.h"

#include "base/values.h"
#include "content/nw/src/api/dispatcher_host.h"
#include "content/nw/src/api/menuitem/menuitem.h"
#include "content/nw/src/browser/native_window_win.h"
#include "content/nw/src/nw_shell.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
#include "skia/ext/image_operations.h"
#include "ui/gfx/gdi_util.h"
#include "ui/gfx/icon_util.h"
#include "ui/views/controls/menu/menu_2.h"
#include "ui/views/widget/widget.h"

namespace {

HBITMAP GetNativeBitmapFromSkBitmap(const SkBitmap& bitmap) {
  int width = bitmap.width();
  int height = bitmap.height();

  BITMAPV4HEADER native_bitmap_header;
  gfx::CreateBitmapV4Header(width, height, &native_bitmap_header);

  HDC dc = ::GetDC(NULL);
  void* bits;
  HBITMAP native_bitmap = ::CreateDIBSection(dc,
      reinterpret_cast<BITMAPINFO*>(&native_bitmap_header),
      DIB_RGB_COLORS,
      &bits,
      NULL,
      0);
  DCHECK(native_bitmap);
  ::ReleaseDC(NULL, dc);
  bitmap.copyPixelsTo(bits, width * height * 4, width * 4);
  return native_bitmap;
}

} // namespace

namespace ui {

NwMenuModel::NwMenuModel(Delegate* delegate) : SimpleMenuModel(delegate) {
}

bool NwMenuModel::HasIcons() const {
  // Always return false, see the comment about |NwMenuModel|.
  return false;
}

} // namespace ui

namespace api {

// The width of the icon for the menuitem
static const int kIconWidth = 16;
// The height of the icon for the menuitem
static const int kIconHeight = 16;

void Menu::Create(const base::DictionaryValue& option) {
  is_menu_modified_ = true;
  menu_delegate_.reset(new MenuDelegate(dispatcher_host()));
  menu_model_.reset(new ui::NwMenuModel(menu_delegate_.get()));
  menu_.reset(new views::NativeMenuWin(menu_model_.get(), NULL));

  std::string type;
  if (option.GetString("type", &type) && type == "menubar")
    menu_->set_is_popup_menu(false);
}

void Menu::Destroy() {
  for (size_t index = 0; index < icon_bitmaps_.size(); ++index) {
    ::DeleteObject(icon_bitmaps_[index]);
  }
}

void Menu::Append(MenuItem* menu_item) {
  if (menu_item->submenu_)
    menu_model_->AddSubMenu(menu_item->id(), menu_item->label_,
                            menu_item->submenu_->menu_model_.get());
  else if (menu_item->type_ == "normal")
    menu_model_->AddItem(menu_item->id(), menu_item->label_);
  else if (menu_item->type_ == "checkbox")
    menu_model_->AddCheckItem(menu_item->id(), menu_item->label_);
  else if (menu_item->type_ == "separator")
    menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);

  is_menu_modified_ = true;
}

void Menu::Insert(MenuItem* menu_item, int pos) {
  if (menu_item->submenu_)
    menu_model_->InsertSubMenuAt(pos, menu_item->id(), menu_item->label_,
                                 menu_item->submenu_->menu_model_.get());
  else if (menu_item->type_ == "normal")
    menu_model_->InsertItemAt(pos, menu_item->id(), menu_item->label_);
  else if (menu_item->type_ == "checkbox")
    menu_model_->InsertCheckItemAt(pos, menu_item->id(), menu_item->label_);
  else if (menu_item->type_ == "separator")
    menu_model_->InsertSeparatorAt(pos, ui::NORMAL_SEPARATOR);

  is_menu_modified_ = true;
}

void Menu::Remove(MenuItem* menu_item, int pos) {
  menu_model_->RemoveAt(pos);
  is_menu_modified_ = true;
}

void Menu::Popup(int x, int y, content::Shell* shell) {
  Rebuild();

  // Map point from document to screen.
  POINT screen_point = { x, y };
  ClientToScreen(shell->web_contents()->GetView()->GetNativeView(),
                 &screen_point);

  menu_->RunMenuAt(gfx::Point(screen_point.x, screen_point.y),
                   views::Menu2::ALIGN_TOPLEFT);
}

void Menu::Rebuild(const HMENU *parent_menu) {
  if (is_menu_modified_) {
    // Refresh menu before show.
    menu_->Rebuild(NULL);
    menu_->UpdateStates();
    for (size_t index = 0; index < icon_bitmaps_.size(); ++index) {
      ::DeleteObject(icon_bitmaps_[index]);
    }
    icon_bitmaps_.clear();

    HMENU native_menu = parent_menu == NULL ?
        menu_->GetNativeMenu() : *parent_menu;

    for (int model_index = 0;
         model_index < menu_model_->GetItemCount();
         ++model_index) {
      int command_id = menu_model_->GetCommandIdAt(model_index);

      if (menu_model_->GetTypeAt(model_index) == ui::MenuModel::TYPE_COMMAND ||
          menu_model_->GetTypeAt(model_index) == ui::MenuModel::TYPE_SUBMENU) {
        gfx::Image icon;
        menu_model_->GetIconAt(model_index, &icon);
        if (!icon.IsEmpty()) {
          SkBitmap resized_bitmap =
              skia::ImageOperations::Resize(*icon.ToSkBitmap(),
                                            skia::ImageOperations::RESIZE_GOOD,
                                            kIconWidth,
                                            kIconHeight);
          HBITMAP icon_bitmap = GetNativeBitmapFromSkBitmap(resized_bitmap);
          ::SetMenuItemBitmaps(native_menu, command_id, MF_BYCOMMAND,
                               icon_bitmap, icon_bitmap);
          icon_bitmaps_.push_back(icon_bitmap);
        }
      }

      MenuItem* item = dispatcher_host()->GetApiObject<MenuItem>(command_id);
      if (item != NULL && item->submenu_) {
        item->submenu_->Rebuild(&native_menu);
      }
    }

    is_menu_modified_ = false;
  }
}

}  // namespace api


// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "content/nw/src/browser/shell_resource_context.h"

#include "content/nw/src/net/shell_url_request_context_getter.h"

namespace content {

ShellResourceContext::ShellResourceContext(
    ShellURLRequestContextGetter* getter)
    : getter_(getter) {
}

ShellResourceContext::~ShellResourceContext() {
}

net::HostResolver* ShellResourceContext::GetHostResolver() {
  return getter_->host_resolver();
}

net::URLRequestContext* ShellResourceContext::GetRequestContext() {
  return getter_->GetURLRequestContext();
}

}  // namespace content


The pid of main page is:

The pid of new-instance page is:


keep keep keep keep keep replace keep keep keep keep

// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "content/nw/src/api/dispatcher_host.h"

#include "base/logging.h"
#include "base/values.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/nw/src/api/api_messages.h"
#include "content/nw/src/api/app/app.h"
#include "content/nw/src/api/base/base.h"
#include "content/nw/src/api/clipboard/clipboard.h"
#include "content/nw/src/api/menu/menu.h"
#include "content/nw/src/api/menuitem/menuitem.h"
#include "content/nw/src/api/shell/shell.h"
#include "content/nw/src/api/tray/tray.h"
#include "content/nw/src/api/window/window.h"
#include "content/nw/src/common/shell_switches.h"
#include "content/nw/src/shell_browser_context.h"
#include "content/nw/src/nw_shell.h"
#include "content/public/browser/render_process_host.h"

using content::WebContents;
using content::ShellBrowserContext;

namespace api {

DispatcherHost::DispatcherHost(content::RenderViewHost* render_view_host)
    : content::RenderViewHostObserver(render_view_host) {
}

DispatcherHost::~DispatcherHost() {
}

Base* DispatcherHost::GetApiObject(int id) {
  return objects_registry_.Lookup(id);
}

void DispatcherHost::SendEvent(Base* object,
                               const std::string& event,
                               const base::ListValue& arguments) {
  Send(new ShellViewMsg_Object_On_Event(
       routing_id(), object->id(), event, arguments));
}

bool DispatcherHost::Send(IPC::Message* message) {
  return content::RenderViewHostObserver::Send(message);
}

bool DispatcherHost::OnMessageReceived(const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(DispatcherHost, message)
    IPC_MESSAGE_HANDLER(ShellViewHostMsg_Allocate_Object, OnAllocateObject)
    IPC_MESSAGE_HANDLER(ShellViewHostMsg_Deallocate_Object, OnDeallocateObject)
    IPC_MESSAGE_HANDLER(ShellViewHostMsg_Call_Object_Method, OnCallObjectMethod)
    IPC_MESSAGE_HANDLER(ShellViewHostMsg_Call_Object_Method_Sync,
                        OnCallObjectMethodSync)
    IPC_MESSAGE_HANDLER(ShellViewHostMsg_Call_Static_Method, OnCallStaticMethod)
    IPC_MESSAGE_HANDLER(ShellViewHostMsg_Call_Static_Method_Sync,
                        OnCallStaticMethodSync)
    IPC_MESSAGE_HANDLER(ShellViewHostMsg_UncaughtException,
                        OnUncaughtException);
    IPC_MESSAGE_HANDLER(ShellViewHostMsg_GetShellId, OnGetShellId);
    IPC_MESSAGE_HANDLER(ShellViewHostMsg_CreateShell, OnCreateShell);
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()

  return handled;
}

void DispatcherHost::OnAllocateObject(int object_id,
                                      const std::string& type,
                                      const base::DictionaryValue& option) {
  DVLOG(1) << "OnAllocateObject: object_id:" << object_id
             << " type:" << type
             << " option:" << option;

  if (type == "Menu") {
    objects_registry_.AddWithID(new Menu(object_id, this, option), object_id);
  } else if (type == "MenuItem") {
    objects_registry_.AddWithID(
        new MenuItem(object_id, this, option), object_id);
  } else if (type == "Tray") {
    objects_registry_.AddWithID(new Tray(object_id, this, option), object_id);
  } else if (type == "Clipboard") {
    objects_registry_.AddWithID(
        new Clipboard(object_id, this, option), object_id);
  } else if (type == "Window") {
    objects_registry_.AddWithID(new Window(object_id, this, option), object_id);
  } else {
    LOG(ERROR) << "Allocate an object of unknow type: " << type;
    objects_registry_.AddWithID(new Base(object_id, this, option), object_id);
  }
}

void DispatcherHost::OnDeallocateObject(int object_id) {
  DLOG(INFO) << "OnDeallocateObject: object_id:" << object_id;
  objects_registry_.Remove(object_id);
}

void DispatcherHost::OnCallObjectMethod(
    int object_id,
    const std::string& type,
    const std::string& method,
    const base::ListValue& arguments) {
  DLOG(INFO) << "OnCallObjectMethod: object_id:" << object_id
             << " type:" << type
             << " method:" << method
             << " arguments:" << arguments;

  Base* object = GetApiObject(object_id);
  DCHECK(object) << "Unknown object: " << object_id;
  object->Call(method, arguments);
}

void DispatcherHost::OnCallObjectMethodSync(
    int object_id,
    const std::string& type,
    const std::string& method,
    const base::ListValue& arguments,
    base::ListValue* result) {
  DLOG(INFO) << "OnCallObjectMethodSync: object_id:" << object_id
             << " type:" << type
             << " method:" << method
             << " arguments:" << arguments;

  Base* object = GetApiObject(object_id);
  DCHECK(object) << "Unknown object: " << object_id;
  object->CallSync(method, arguments, result);
}

void DispatcherHost::OnCallStaticMethod(
    const std::string& type,
    const std::string& method,
    const base::ListValue& arguments) {
  DLOG(INFO) << "OnCallStaticMethod: "
             << " type:" << type
             << " method:" << method
             << " arguments:" << arguments;

  if (type == "Shell") {
    api::Shell::Call(method, arguments);
    return;
  } else if (type == "App") {
    api::App::Call(method, arguments);
    return;
  }

  NOTREACHED() << "Calling unknown method " << method << " of class " << type;
}

void DispatcherHost::OnCallStaticMethodSync(
    const std::string& type,
    const std::string& method,
    const base::ListValue& arguments,
    base::ListValue* result) {
  DLOG(INFO) << "OnCallStaticMethodSync: "
             << " type:" << type
             << " method:" << method
             << " arguments:" << arguments;

  if (type == "App") {
    content::Shell* shell =
        content::Shell::FromRenderViewHost(render_view_host());
    api::App::Call(shell, method, arguments, result);
    return;
  }

  NOTREACHED() << "Calling unknown method " << method << " of class " << type;
}

void DispatcherHost::OnUncaughtException(const std::string& err) {
  content::Shell* shell =
      content::Shell::FromRenderViewHost(render_view_host());
  shell->PrintCriticalError("Uncaught node.js Error", err);
}

void DispatcherHost::OnGetShellId(int* id) {
  content::Shell* shell =
      content::Shell::FromRenderViewHost(render_view_host());
  *id = shell->id();
}

void DispatcherHost::OnCreateShell(const std::string& url,
                                   const base::DictionaryValue& manifest,
                                   int* routing_id) {
  WebContents* base_web_contents =
      content::Shell::FromRenderViewHost(render_view_host())->web_contents();
  ShellBrowserContext* browser_context =
      static_cast<ShellBrowserContext*>(base_web_contents->GetBrowserContext());
  scoped_ptr<base::DictionaryValue> new_manifest(manifest.DeepCopy());
  bool new_renderer = false;
  if (new_manifest->GetBoolean(switches::kmNewInstance,
                               &new_renderer) && new_renderer)
    browser_context->set_pinning_renderer(false);

  WebContents::CreateParams create_params(browser_context,
                                          new_renderer ? NULL : base_web_contents->GetSiteInstance());

  WebContents* web_contents = content::WebContentsImpl::CreateWithOpener(
      create_params,
      static_cast<content::WebContentsImpl*>(base_web_contents));
  new content::Shell(web_contents, new_manifest.get());
  web_contents->GetController().LoadURL(
      GURL(url),
      content::Referrer(),
      content::PAGE_TRANSITION_TYPED,
      std::string());

  if (new_renderer)
    browser_context->set_pinning_renderer(true);

  *routing_id = web_contents->GetRoutingID();
}

}  // namespace api


// 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/nw/src/browser/printing/printing_message_filter.h"

#include <string>

#include "base/bind.h"
#include "base/process_util.h"
//#include "chrome/browser/browser_process.h"
#include "content/nw/src/browser/printing/printer_query.h"
#include "content/nw/src/browser/printing/print_job_manager.h"
//#include "chrome/browser/profiles/profile.h"
//#include "chrome/browser/profiles/profile_io_data.h"
//#include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
#include "content/nw/src/common/print_messages.h"
#include "content/nw/src/shell_content_browser_client.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"

#if defined(OS_CHROMEOS)
#include <fcntl.h>

#include <map>

#include "base/file_util.h"
#include "base/lazy_instance.h"
#include "chrome/browser/printing/print_dialog_cloud.h"
#endif

using content::BrowserThread;

namespace {

#if defined(OS_CHROMEOS)
typedef std::map<int, base::FilePath> SequenceToPathMap;

struct PrintingSequencePathMap {
  SequenceToPathMap map;
  int sequence;
};

// No locking, only access on the FILE thread.
static base::LazyInstance<PrintingSequencePathMap>
    g_printing_file_descriptor_map = LAZY_INSTANCE_INITIALIZER;
#endif

void RenderParamsFromPrintSettings(const printing::PrintSettings& settings,
                                   PrintMsg_Print_Params* params) {
  params->page_size = settings.page_setup_device_units().physical_size();
  params->content_size.SetSize(
      settings.page_setup_device_units().content_area().width(),
      settings.page_setup_device_units().content_area().height());
  params->printable_area.SetRect(
      settings.page_setup_device_units().printable_area().x(),
      settings.page_setup_device_units().printable_area().y(),
      settings.page_setup_device_units().printable_area().width(),
      settings.page_setup_device_units().printable_area().height());
  params->margin_top = settings.page_setup_device_units().content_area().y();
  params->margin_left = settings.page_setup_device_units().content_area().x();
  params->dpi = settings.dpi();
  // Currently hardcoded at 1.25. See PrintSettings' constructor.
  params->min_shrink = settings.min_shrink;
  // Currently hardcoded at 2.0. See PrintSettings' constructor.
  params->max_shrink = settings.max_shrink;
  // Currently hardcoded at 72dpi. See PrintSettings' constructor.
  params->desired_dpi = settings.desired_dpi;
  // Always use an invalid cookie.
  params->document_cookie = 0;
  params->selection_only = settings.selection_only;
  params->supports_alpha_blend = settings.supports_alpha_blend();
  params->should_print_backgrounds = settings.should_print_backgrounds;
  params->display_header_footer = settings.display_header_footer;
  params->date = settings.date;
  params->title = settings.title;
  params->url = settings.url;
}

}  // namespace

PrintingMessageFilter::PrintingMessageFilter(int render_process_id)
  : print_job_manager_(NULL),
      render_process_id_(render_process_id) {
  content::ShellContentBrowserClient* browser_client =
    static_cast<content::ShellContentBrowserClient*>(content::GetContentClient()->browser());
  print_job_manager_ = browser_client->print_job_manager();
}

PrintingMessageFilter::~PrintingMessageFilter() {
}

void PrintingMessageFilter::OverrideThreadForMessage(
    const IPC::Message& message, BrowserThread::ID* thread) {
#if defined(OS_CHROMEOS)
  if (message.type() == PrintHostMsg_AllocateTempFileForPrinting::ID ||
      message.type() == PrintHostMsg_TempFileForPrintingWritten::ID) {
    *thread = BrowserThread::FILE;
  }
#endif
}

bool PrintingMessageFilter::OnMessageReceived(const IPC::Message& message,
                                              bool* message_was_ok) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP_EX(PrintingMessageFilter, message, *message_was_ok)
#if defined(OS_WIN)
    IPC_MESSAGE_HANDLER(PrintHostMsg_DuplicateSection, OnDuplicateSection)
#endif
#if defined(OS_CHROMEOS)
    IPC_MESSAGE_HANDLER(PrintHostMsg_AllocateTempFileForPrinting,
                        OnAllocateTempFileForPrinting)
    IPC_MESSAGE_HANDLER(PrintHostMsg_TempFileForPrintingWritten,
                        OnTempFileForPrintingWritten)
#endif
    IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_GetDefaultPrintSettings,
                                    OnGetDefaultPrintSettings)
    IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_ScriptedPrint, OnScriptedPrint)
    IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_UpdatePrintSettings,
                                    OnUpdatePrintSettings)
    IPC_MESSAGE_HANDLER(PrintHostMsg_CheckForCancel, OnCheckForCancel)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

#if defined(OS_WIN)
void PrintingMessageFilter::OnDuplicateSection(
    base::SharedMemoryHandle renderer_handle,
    base::SharedMemoryHandle* browser_handle) {
  // Duplicate the handle in this process right now so the memory is kept alive
  // (even if it is not mapped)
  base::SharedMemory shared_buf(renderer_handle, true, peer_handle());
  shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), browser_handle);
}
#endif

#if defined(OS_CHROMEOS)
void PrintingMessageFilter::OnAllocateTempFileForPrinting(
    base::FileDescriptor* temp_file_fd, int* sequence_number) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  temp_file_fd->fd = *sequence_number = -1;
  temp_file_fd->auto_close = false;

  SequenceToPathMap* map = &g_printing_file_descriptor_map.Get().map;
  *sequence_number = g_printing_file_descriptor_map.Get().sequence++;

  base::FilePath path;
  if (file_util::CreateTemporaryFile(&path)) {
    int fd = open(path.value().c_str(), O_WRONLY);
    if (fd >= 0) {
      SequenceToPathMap::iterator it = map->find(*sequence_number);
      if (it != map->end()) {
        NOTREACHED() << "Sequence number already in use. seq=" <<
            *sequence_number;
      } else {
        (*map)[*sequence_number] = path;
        temp_file_fd->fd = fd;
        temp_file_fd->auto_close = true;
      }
    }
  }
}

void PrintingMessageFilter::OnTempFileForPrintingWritten(int render_view_id,
                                                         int sequence_number) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  SequenceToPathMap* map = &g_printing_file_descriptor_map.Get().map;
  SequenceToPathMap::iterator it = map->find(sequence_number);
  if (it == map->end()) {
    NOTREACHED() << "Got a sequence that we didn't pass to the "
                    "renderer: " << sequence_number;
    return;
  }
  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&PrintingMessageFilter::CreatePrintDialogForFile,
                 this, render_view_id, it->second));

  // Erase the entry in the map.
  map->erase(it);
}

void PrintingMessageFilter::CreatePrintDialogForFile(
    int render_view_id,
    const base::FilePath& path) {
  content::WebContents* wc = GetWebContentsForRenderView(render_view_id);
  print_dialog_cloud::CreatePrintDialogForFile(
      wc->GetBrowserContext(),
      wc->GetView()->GetTopLevelNativeWindow(),
      path,
      string16(),
      string16(),
      std::string("application/pdf"),
      false);
}
#endif  // defined(OS_CHROMEOS)

content::WebContents* PrintingMessageFilter::GetWebContentsForRenderView(
    int render_view_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  content::RenderViewHost* view = content::RenderViewHost::FromID(
      render_process_id_, render_view_id);
  return content::WebContents::FromRenderViewHost(view);
}

struct PrintingMessageFilter::GetPrintSettingsForRenderViewParams {
  printing::PrinterQuery::GetSettingsAskParam ask_user_for_settings;
  int expected_page_count;
  bool has_selection;
  printing::MarginType margin_type;
};

void PrintingMessageFilter::GetPrintSettingsForRenderView(
    int render_view_id,
    GetPrintSettingsForRenderViewParams params,
    const base::Closure& callback,
    scoped_refptr<printing::PrinterQuery> printer_query) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  content::WebContents* wc = GetWebContentsForRenderView(render_view_id);

  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      base::Bind(&printing::PrinterQuery::GetSettings, printer_query,
                 params.ask_user_for_settings, wc->GetView()->GetNativeView(),
                 params.expected_page_count, params.has_selection,
                 params.margin_type, callback));
}

void PrintingMessageFilter::OnGetDefaultPrintSettings(IPC::Message* reply_msg) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  scoped_refptr<printing::PrinterQuery> printer_query;
#if 0
  if (!profile_io_data_->printing_enabled()->GetValue()) {
    // Reply with NULL query.
    OnGetDefaultPrintSettingsReply(printer_query, reply_msg);
    return;
  }
#endif
  print_job_manager_->PopPrinterQuery(0, &printer_query);
  if (!printer_query.get()) {
    printer_query = new printing::PrinterQuery;
    printer_query->SetWorkerDestination(print_job_manager_->destination());
  }

  // Loads default settings. This is asynchronous, only the IPC message sender
  // will hang until the settings are retrieved.
  GetPrintSettingsForRenderViewParams params;
  params.ask_user_for_settings = printing::PrinterQuery::DEFAULTS;
  params.expected_page_count = 0;
  params.has_selection = false;
  params.margin_type = printing::DEFAULT_MARGINS;
  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&PrintingMessageFilter::GetPrintSettingsForRenderView, this,
          reply_msg->routing_id(), params,
          base::Bind(&PrintingMessageFilter::OnGetDefaultPrintSettingsReply,
              this, printer_query, reply_msg),
          printer_query));
}

void PrintingMessageFilter::OnGetDefaultPrintSettingsReply(
    scoped_refptr<printing::PrinterQuery> printer_query,
    IPC::Message* reply_msg) {
  PrintMsg_Print_Params params;
  if (!printer_query.get() ||
      printer_query->last_status() != printing::PrintingContext::OK) {
    params.Reset();
  } else {
    RenderParamsFromPrintSettings(printer_query->settings(), &params);
    params.document_cookie = printer_query->cookie();
  }
  PrintHostMsg_GetDefaultPrintSettings::WriteReplyParams(reply_msg, params);
  Send(reply_msg);
  // If printing was enabled.
  if (printer_query.get()) {
    // If user hasn't cancelled.
    if (printer_query->cookie() && printer_query->settings().dpi()) {
      print_job_manager_->QueuePrinterQuery(printer_query.get());
    } else {
      printer_query->StopWorker();
    }
  }
}

void PrintingMessageFilter::OnScriptedPrint(
    const PrintHostMsg_ScriptedPrint_Params& params,
    IPC::Message* reply_msg) {
  scoped_refptr<printing::PrinterQuery> printer_query;
  print_job_manager_->PopPrinterQuery(params.cookie, &printer_query);
  if (!printer_query.get()) {
    printer_query = new printing::PrinterQuery;
    printer_query->SetWorkerDestination(print_job_manager_->destination());
  }
  GetPrintSettingsForRenderViewParams settings_params;
  settings_params.ask_user_for_settings = printing::PrinterQuery::ASK_USER;
  settings_params.expected_page_count = params.expected_pages_count;
  settings_params.has_selection = params.has_selection;
  settings_params.margin_type = params.margin_type;

  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&PrintingMessageFilter::GetPrintSettingsForRenderView, this,
                 reply_msg->routing_id(), settings_params,
                 base::Bind(&PrintingMessageFilter::OnScriptedPrintReply, this,
                            printer_query, reply_msg),
                 printer_query));
}

void PrintingMessageFilter::OnScriptedPrintReply(
    scoped_refptr<printing::PrinterQuery> printer_query,
    IPC::Message* reply_msg) {
  PrintMsg_PrintPages_Params params;
  if (printer_query->last_status() != printing::PrintingContext::OK ||
      !printer_query->settings().dpi()) {
    params.Reset();
  } else {
    RenderParamsFromPrintSettings(printer_query->settings(), &params.params);
    params.params.document_cookie = printer_query->cookie();
    params.pages =
        printing::PageRange::GetPages(printer_query->settings().ranges);
  }
  PrintHostMsg_ScriptedPrint::WriteReplyParams(reply_msg, params);
  Send(reply_msg);
  if (params.params.dpi && params.params.document_cookie) {
    print_job_manager_->QueuePrinterQuery(printer_query.get());
  } else {
    printer_query->StopWorker();
  }
}

void PrintingMessageFilter::OnUpdatePrintSettings(
    int document_cookie, const DictionaryValue& job_settings,
    IPC::Message* reply_msg) {
  scoped_refptr<printing::PrinterQuery> printer_query;
#if 0
  if (!profile_io_data_->printing_enabled()->GetValue()) {
    // Reply with NULL query.
    OnUpdatePrintSettingsReply(printer_query, reply_msg);
    return;
  }
#endif
  print_job_manager_->PopPrinterQuery(document_cookie, &printer_query);
  if (!printer_query.get()) {
    printer_query = new printing::PrinterQuery;
    printer_query->SetWorkerDestination(print_job_manager_->destination());
  }
  printer_query->SetSettings(
      job_settings,
      base::Bind(&PrintingMessageFilter::OnUpdatePrintSettingsReply, this,
                 printer_query, reply_msg));
}

void PrintingMessageFilter::OnUpdatePrintSettingsReply(
    scoped_refptr<printing::PrinterQuery> printer_query,
    IPC::Message* reply_msg) {
  PrintMsg_PrintPages_Params params;
  if (!printer_query.get() ||
      printer_query->last_status() != printing::PrintingContext::OK) {
    params.Reset();
  } else {
    RenderParamsFromPrintSettings(printer_query->settings(), &params.params);
    params.params.document_cookie = printer_query->cookie();
    params.pages =
        printing::PageRange::GetPages(printer_query->settings().ranges);
  }
  PrintHostMsg_UpdatePrintSettings::WriteReplyParams(reply_msg, params);
  Send(reply_msg);
  // If user hasn't cancelled.
  if (printer_query.get()) {
    if (printer_query->cookie() && printer_query->settings().dpi())
      print_job_manager_->QueuePrinterQuery(printer_query.get());
    else
      printer_query->StopWorker();
  }
}

void PrintingMessageFilter::OnCheckForCancel(int32 preview_ui_id,
                                             int preview_request_id,
                                             bool* cancel) {
}


var path = require('path');
var app_test = require('./nw_test_app');
var server = global.server;
var cb;

describe('new-instance', function() {

  after(function() {
     server.removeListener('connection', cb);
  });

	it('loaded event can been fired', function(done) {
	    this.timeout(0);
	    var result = false;
	    var times = 0;
	    var pid1, pid2;

	    var child = app_test.createChildProcess({
	      execPath: process.execPath,
	      appPath: path.join('app_tests', 'new-instance'),
	      no_connect: true,

	    });

	    server.on('connection', cb = function(socket){
	      socket.setEncoding('utf8');

	      socket.on('data', function(data) {

	        if (times == 0) {
	          pid1 = data;
	          times += 1;
	        } else {
	          pid2 = data;

	          if (pid1 != pid2) {
	            done();
	          } else {
	            done('they are in the same process');
	          }

	          child.app.kill();
	        } // if (times == 0)
	      });
	    }); // server.on('connection', cb = function(socket)

	})

})


// 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/nw/src/browser/shell_application_mac.h"

#include "base/auto_reset.h"
#include "base/command_line.h"
#include "googleurl/src/gurl.h"
#include "content/nw/src/nw_shell.h"
#include "content/nw/src/shell_browser_context.h"
#include "content/nw/src/shell_content_browser_client.h"
#include "content/nw/src/common/shell_switches.h"

@implementation ShellCrApplication

- (BOOL)isHandlingSendEvent {
  return handlingSendEvent_;
}

- (void)sendEvent:(NSEvent*)event {
  base::AutoReset<BOOL> scoper(&handlingSendEvent_, YES);
  [super sendEvent:event];
}

- (void)setHandlingSendEvent:(BOOL)handlingSendEvent {
  handlingSendEvent_ = handlingSendEvent;
}

@end


keep keep keep keep replace keep keep keep keep

: shell_browser_main_parts_(NULL),
master_rph_(NULL) {


// 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 "chrome/browser/printing/print_job.h"

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/message_loop.h"
#include "base/threading/thread_restrictions.h"
#include "base/timer.h"
#include "content/nw/src/browser/printing/print_job_worker.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "printing/printed_document.h"
#include "printing/printed_page.h"

using base::TimeDelta;

namespace {

// Helper function to ensure |owner| is valid until at least |callback| returns.
void HoldRefCallback(const scoped_refptr<printing::PrintJobWorkerOwner>& owner,
                     const base::Closure& callback) {
  callback.Run();
}

}  // namespace

namespace printing {

PrintJob::PrintJob()
    : ui_message_loop_(MessageLoop::current()),
      source_(NULL),
      worker_(),
      settings_(),
      is_job_pending_(false),
      is_canceling_(false),
      ALLOW_THIS_IN_INITIALIZER_LIST(quit_factory_(this)) {
  DCHECK(ui_message_loop_);
  // This is normally a UI message loop, but in unit tests, the message loop is
  // of the 'default' type.
  DCHECK(ui_message_loop_->type() == MessageLoop::TYPE_UI ||
         ui_message_loop_->type() == MessageLoop::TYPE_DEFAULT);
  ui_message_loop_->AddDestructionObserver(this);
}

PrintJob::~PrintJob() {
  ui_message_loop_->RemoveDestructionObserver(this);
  // The job should be finished (or at least canceled) when it is destroyed.
  DCHECK(!is_job_pending_);
  DCHECK(!is_canceling_);
  if (worker_.get())
    DCHECK(worker_->message_loop() == NULL);
  DCHECK_EQ(ui_message_loop_, MessageLoop::current());
}

void PrintJob::Initialize(PrintJobWorkerOwner* job,
                          PrintedPagesSource* source,
                          int page_count) {
  DCHECK(!source_);
  DCHECK(!worker_.get());
  DCHECK(!is_job_pending_);
  DCHECK(!is_canceling_);
  DCHECK(!document_.get());
  source_ = source;
  worker_.reset(job->DetachWorker(this));
  settings_ = job->settings();

  PrintedDocument* new_doc =
      new PrintedDocument(settings_, source_, job->cookie());
  new_doc->set_page_count(page_count);
  UpdatePrintedDocument(new_doc);

  // Don't forget to register to our own messages.
  registrar_.Add(this, content::NOTIFICATION_PRINT_JOB_EVENT,
                 content::Source<PrintJob>(this));
}

void PrintJob::Observe(int type,
                       const content::NotificationSource& source,
                       const content::NotificationDetails& details) {
  DCHECK_EQ(ui_message_loop_, MessageLoop::current());
  switch (type) {
    case content::NOTIFICATION_PRINT_JOB_EVENT: {
      OnNotifyPrintJobEvent(*content::Details<JobEventDetails>(details).ptr());
      break;
    }
    default: {
      break;
    }
  }
}

void PrintJob::GetSettingsDone(const PrintSettings& new_settings,
                               PrintingContext::Result result) {
  NOTREACHED();
}

PrintJobWorker* PrintJob::DetachWorker(PrintJobWorkerOwner* new_owner) {
  NOTREACHED();
  return NULL;
}

MessageLoop* PrintJob::message_loop() {
  return ui_message_loop_;
}

const PrintSettings& PrintJob::settings() const {
  return settings_;
}

int PrintJob::cookie() const {
  if (!document_.get())
    // Always use an invalid cookie in this case.
    return 0;
  return document_->cookie();
}

void PrintJob::WillDestroyCurrentMessageLoop() {
  NOTREACHED();
}

void PrintJob::StartPrinting() {
  DCHECK_EQ(ui_message_loop_, MessageLoop::current());
  DCHECK(worker_->message_loop());
  DCHECK(!is_job_pending_);
  if (!worker_->message_loop() || is_job_pending_)
    return;

  // Real work is done in PrintJobWorker::StartPrinting().
  worker_->message_loop()->PostTask(
      FROM_HERE,
      base::Bind(&HoldRefCallback, make_scoped_refptr(this),
                 base::Bind(&PrintJobWorker::StartPrinting,
                            base::Unretained(worker_.get()), document_)));
  // Set the flag right now.
  is_job_pending_ = true;

  // Tell everyone!
  scoped_refptr<JobEventDetails> details(
      new JobEventDetails(JobEventDetails::NEW_DOC, document_.get(), NULL));
  content::NotificationService::current()->Notify(
      content::NOTIFICATION_PRINT_JOB_EVENT,
      content::Source<PrintJob>(this),
      content::Details<JobEventDetails>(details.get()));
}

void PrintJob::Stop() {
  DCHECK_EQ(ui_message_loop_, MessageLoop::current());

  if (quit_factory_.HasWeakPtrs()) {
    // In case we're running a nested message loop to wait for a job to finish,
    // and we finished before the timeout, quit the nested loop right away.
    Quit();
    quit_factory_.InvalidateWeakPtrs();
  }

  // Be sure to live long enough.
  scoped_refptr<PrintJob> handle(this);

  MessageLoop* worker_loop = worker_->message_loop();
  if (worker_loop) {
    ControlledWorkerShutdown();

    is_job_pending_ = false;
    registrar_.Remove(this, content::NOTIFICATION_PRINT_JOB_EVENT,
                      content::Source<PrintJob>(this));
  }
  // Flush the cached document.
  UpdatePrintedDocument(NULL);
}

void PrintJob::Cancel() {
  if (is_canceling_)
    return;
  is_canceling_ = true;

  // Be sure to live long enough.
  scoped_refptr<PrintJob> handle(this);

  DCHECK_EQ(ui_message_loop_, MessageLoop::current());
  MessageLoop* worker_loop = worker_.get() ? worker_->message_loop() : NULL;
  if (worker_loop) {
    // Call this right now so it renders the context invalid. Do not use
    // InvokeLater since it would take too much time.
    worker_->Cancel();
  }
  // Make sure a Cancel() is broadcast.
  scoped_refptr<JobEventDetails> details(
      new JobEventDetails(JobEventDetails::FAILED, NULL, NULL));
  content::NotificationService::current()->Notify(
      content::NOTIFICATION_PRINT_JOB_EVENT,
      content::Source<PrintJob>(this),
      content::Details<JobEventDetails>(details.get()));
  Stop();
  is_canceling_ = false;
}

bool PrintJob::FlushJob(base::TimeDelta timeout) {
  // Make sure the object outlive this message loop.
  scoped_refptr<PrintJob> handle(this);

  MessageLoop::current()->PostDelayedTask(FROM_HERE,
      base::Bind(&PrintJob::Quit, quit_factory_.GetWeakPtr()), timeout);

  MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());
  MessageLoop::current()->Run();

  return true;
}

void PrintJob::DisconnectSource() {
  source_ = NULL;
  if (document_.get())
    document_->DisconnectSource();
}

bool PrintJob::is_job_pending() const {
  return is_job_pending_;
}

PrintedDocument* PrintJob::document() const {
  return document_.get();
}

void PrintJob::UpdatePrintedDocument(PrintedDocument* new_document) {
  if (document_.get() == new_document)
    return;

  document_ = new_document;

  if (document_.get()) {
    settings_ = document_->settings();
  }

  if (worker_.get() && worker_->message_loop()) {
    DCHECK(!is_job_pending_);
    // Sync the document with the worker.
    worker_->message_loop()->PostTask(
        FROM_HERE,
        base::Bind(&HoldRefCallback, make_scoped_refptr(this),
                   base::Bind(&PrintJobWorker::OnDocumentChanged,
                              base::Unretained(worker_.get()), document_)));
  }
}

void PrintJob::OnNotifyPrintJobEvent(const JobEventDetails& event_details) {
  switch (event_details.type()) {
    case JobEventDetails::FAILED: {
      settings_.Clear();
      // No need to cancel since the worker already canceled itself.
      Stop();
      break;
    }
    case JobEventDetails::USER_INIT_DONE:
    case JobEventDetails::DEFAULT_INIT_DONE:
    case JobEventDetails::USER_INIT_CANCELED: {
      DCHECK_EQ(event_details.document(), document_.get());
      break;
    }
    case JobEventDetails::NEW_DOC:
    case JobEventDetails::NEW_PAGE:
    case JobEventDetails::PAGE_DONE:
    case JobEventDetails::JOB_DONE:
    case JobEventDetails::ALL_PAGES_REQUESTED: {
      // Don't care.
      break;
    }
    case JobEventDetails::DOC_DONE: {
      // This will call Stop() and broadcast a JOB_DONE message.
      MessageLoop::current()->PostTask(
          FROM_HERE, base::Bind(&PrintJob::OnDocumentDone, this));
      break;
    }
    default: {
      NOTREACHED();
      break;
    }
  }
}

void PrintJob::OnDocumentDone() {
  // Be sure to live long enough. The instance could be destroyed by the
  // JOB_DONE broadcast.
  scoped_refptr<PrintJob> handle(this);

  // Stop the worker thread.
  Stop();

  scoped_refptr<JobEventDetails> details(
      new JobEventDetails(JobEventDetails::JOB_DONE, document_.get(), NULL));
  content::NotificationService::current()->Notify(
      content::NOTIFICATION_PRINT_JOB_EVENT,
      content::Source<PrintJob>(this),
      content::Details<JobEventDetails>(details.get()));
}

void PrintJob::ControlledWorkerShutdown() {
  DCHECK_EQ(ui_message_loop_, MessageLoop::current());

  // The deadlock this code works around is specific to window messaging on
  // Windows, so we aren't likely to need it on any other platforms.
#if defined(OS_WIN)
  // We could easily get into a deadlock case if worker_->Stop() is used; the
  // printer driver created a window as a child of the browser window. By
  // canceling the job, the printer driver initiated dialog box is destroyed,
  // which sends a blocking message to its parent window. If the browser window
  // thread is not processing messages, a deadlock occurs.
  //
  // This function ensures that the dialog box will be destroyed in a timely
  // manner by the mere fact that the thread will terminate. So the potential
  // deadlock is eliminated.
  worker_->StopSoon();

  // Run a tight message loop until the worker terminates. It may seems like a
  // hack but I see no other way to get it to work flawlessly. The issues here
  // are:
  // - We don't want to run tasks while the thread is quitting.
  // - We want this code path to wait on the thread to quit before continuing.
  MSG msg;
  HANDLE thread_handle = worker_->thread_handle();
  for (; thread_handle;) {
    // Note that we don't do any kind of message prioritization since we don't
    // execute any pending task or timer.
    DWORD result = MsgWaitForMultipleObjects(1, &thread_handle,
                                             FALSE, INFINITE, QS_ALLINPUT);
    if (result == WAIT_OBJECT_0 + 1) {
      while (PeekMessage(&msg, NULL, 0, 0, TRUE) > 0) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
      // Continue looping.
    } else if (result == WAIT_OBJECT_0) {
      // The thread quit.
      break;
    } else {
      // An error occurred. Assume the thread quit.
      NOTREACHED();
      break;
    }
  }
#endif

  // Temporarily allow it until we fix
  // http://code.google.com/p/chromium/issues/detail?id=67044
  base::ThreadRestrictions::ScopedAllowIO allow_io;

  // Now make sure the thread object is cleaned up.
  worker_->Stop();
}

void PrintJob::Quit() {
  MessageLoop::current()->Quit();
}

// Takes settings_ ownership and will be deleted in the receiving thread.
JobEventDetails::JobEventDetails(Type type,
                                 PrintedDocument* document,
                                 PrintedPage* page)
    : document_(document),
      page_(page),
      type_(type) {
}

JobEventDetails::~JobEventDetails() {
}

PrintedDocument* JobEventDetails::document() const {
  return document_;
}

PrintedPage* JobEventDetails::page() const {
  return page_;
}

}  // namespace printing