<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 "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"

using content::WebContents;
using extensions::Extension;

namespace {

const char kSubscribePage[] = "/subscribe.html";
const char kFeedPageMultiRel[] = "files/feeds/feed_multi_rel.html";
const char kValidFeedNoLinks[] = "files/feeds/feed_nolinks.xml";
const char kValidFeed0[] = "files/feeds/feed_script.xml";
const char kValidFeed1[] = "files/feeds/feed1.xml";
const char kValidFeed2[] = "files/feeds/feed2.xml";
const char kValidFeed3[] = "files/feeds/feed3.xml";
const char kValidFeed4[] = "files/feeds/feed4.xml";
const char kValidFeed5[] = "files/feeds/feed5.xml";
const char kValidFeed6[] = "files/feeds/feed6.xml";
const char kInvalidFeed1[] = "files/feeds/feed_invalid1.xml";
const char kInvalidFeed2[] = "files/feeds/feed_invalid2.xml";
// We need a triple encoded string to prove that we are not decoding twice in
// subscribe.js because one layer is also stripped off when subscribe.js passes
// it to the XMLHttpRequest object.
const char kFeedTripleEncoded[] = "files/feeds/url%25255Fdecoding.html";

static const char kScriptFeedTitle[] =
    "window.domAutomationController.send("
    "  document.getElementById('title') ? "
    "    document.getElementById('title').textContent : "
    "    \"element 'title' not found\""
    ");";
static const char kScriptAnchor[] =
    "window.domAutomationController.send("
    "  document.getElementById('anchor_0') ? "
    "    document.getElementById('anchor_0').textContent : "
    "    \"element 'anchor_0' not found\""
    ");";
static const char kScriptDesc[] =
    "window.domAutomationController.send("
    "  document.getElementById('desc_0') ? "
    "    document.getElementById('desc_0').textContent : "
    "    \"element 'desc_0' not found\""
    ");";
static const char kScriptError[] =
    "window.domAutomationController.send("
    "  document.getElementById('error') ? "
    "    document.getElementById('error').textContent : "
    "    \"No error\""
    ");";

GURL GetFeedUrl(net::SpawnedTestServer* server, const std::string& feed_page,
                bool direct_url, std::string extension_id) {
  GURL feed_url = server->GetURL(feed_page);
  if (direct_url) {
    // We navigate directly to the subscribe page for feeds where the feed
    // sniffing won't work, in other words, as is the case for malformed feeds.
    return GURL(std::string(extensions::kExtensionScheme) +
        url::kStandardSchemeSeparator +
        extension_id + std::string(kSubscribePage) + std::string("?") +
        feed_url.spec() + std::string("&synchronous"));
  } else {
    // Navigate to the feed content (which will cause the extension to try to
    // sniff the type and display the subscribe page in another tab.
    return GURL(feed_url.spec());
  }
}

bool ValidatePageElement(content::RenderFrameHost* frame,
                         const std::string& javascript,
                         const std::string& expected_value) {
  std::string returned_value;

  if (!content::ExecuteScriptAndExtractString(frame,
                                              javascript,
                                              &returned_value))
    return false;

  EXPECT_STREQ(expected_value.c_str(), returned_value.c_str());
  return expected_value == returned_value;
}

// Navigates to a feed page and, if |sniff_xml_type| is set, wait for the
// extension to kick in, detect the feed and redirect to a feed preview page.
// |sniff_xml_type| is generally set to true if the feed is sniffable and false
// for invalid feeds.
void NavigateToFeedAndValidate(net::SpawnedTestServer* server,
                               const std::string& url,
                               Browser* browser,
                               std::string extension_id,
                               bool sniff_xml_type,
                               const std::string& expected_feed_title,
                               const std::string& expected_item_title,
                               const std::string& expected_item_desc,
                               const std::string& expected_error) {
  if (sniff_xml_type) {
    // TODO(finnur): Implement this is a non-flaky way.
  }

  // Navigate to the subscribe page directly.
  ui_test_utils::NavigateToURL(browser,
                               GetFeedUrl(server, url, true, extension_id));

  WebContents* tab = browser->tab_strip_model()->GetActiveWebContents();
  content::RenderFrameHost* frame = content::FrameMatchingPredicate(
      tab, base::Bind(&content::FrameIsChildOfMainFrame));
  ASSERT_TRUE(ValidatePageElement(
      tab->GetMainFrame(), kScriptFeedTitle, expected_feed_title));
  ASSERT_TRUE(ValidatePageElement(frame, kScriptAnchor, expected_item_title));
  ASSERT_TRUE(ValidatePageElement(frame, kScriptDesc, expected_item_desc));
  ASSERT_TRUE(ValidatePageElement(frame, kScriptError, expected_error));
}

} // namespace

// Makes sure that the RSS detects RSS feed links, even when rel tag contains
// more than just "alternate".
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSMultiRelLink) {
  ASSERT_TRUE(test_server()->Start());

  ASSERT_TRUE(LoadExtension(
    test_data_dir_.AppendASCII("subscribe_page_action")));

  ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(0));

  // Navigate to the feed page.
  GURL feed_url = test_server()->GetURL(kFeedPageMultiRel);
  ui_test_utils::NavigateToURL(browser(), feed_url);
  // We should now have one page action ready to go in the LocationBar.
  ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1));
}

// This test is flaky on all platforms; see http://crbug.com/340354
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, DISABLED_RSSParseFeedValidFeed1) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  NavigateToFeedAndValidate(test_server(), kValidFeed1, browser(), id, true,
                            "Feed for MyFeedTitle",
                            "Title 1",
                            "Desc",
                            "No error");
}

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedValidFeed2) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  NavigateToFeedAndValidate(test_server(), kValidFeed2, browser(), id, true,
                            "Feed for MyFeed2",
                            "My item title1",
                            "This is a summary.",
                            "No error");
}

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedValidFeed3) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  NavigateToFeedAndValidate(test_server(), kValidFeed3, browser(), id, true,
                            "Feed for Google Code buglist rss feed",
                            "My dear title",
                            "My dear content",
                            "No error");
}

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedValidFeed4) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  NavigateToFeedAndValidate(test_server(), kValidFeed4, browser(), id, true,
                            "Feed for Title chars <script> %23 stop",
                            "Title chars  %23 stop",
                            "My dear content %23 stop",
                            "No error");
}

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedValidFeed0) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  // Try a feed with a link with an onclick handler (before r27440 this would
  // trigger a NOTREACHED).
  NavigateToFeedAndValidate(test_server(), kValidFeed0, browser(), id, true,
                            "Feed for MyFeedTitle",
                            "Title 1",
                            "Desc VIDEO",
                            "No error");
}

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedValidFeed5) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  // Feed with valid but mostly empty xml.
  NavigateToFeedAndValidate(test_server(), kValidFeed5, browser(), id, true,
                            "Feed for Unknown feed name",
                            "element 'anchor_0' not found",
                            "element 'desc_0' not found",
                            "This feed contains no entries.");
}

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedValidFeed6) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  // Feed that is technically invalid but still parseable.
  NavigateToFeedAndValidate(test_server(), kValidFeed6, browser(), id, true,
                            "Feed for MyFeedTitle",
                            "Title 1",
                            "Desc",
                            "No error");
}

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedInvalidFeed1) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  // Try an empty feed.
  NavigateToFeedAndValidate(test_server(), kInvalidFeed1, browser(), id, false,
                            "Feed for Unknown feed name",
                            "element 'anchor_0' not found",
                            "element 'desc_0' not found",
                            "This feed contains no entries.");
}

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedInvalidFeed2) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  // Try a garbage feed.
  NavigateToFeedAndValidate(test_server(), kInvalidFeed2, browser(), id, false,
                            "Feed for Unknown feed name",
                            "element 'anchor_0' not found",
                            "element 'desc_0' not found",
                            "This feed contains no entries.");
}

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedInvalidFeed3) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  // Try a feed that doesn't exist.
  NavigateToFeedAndValidate(test_server(), "foo.xml", browser(), id, false,
                            "Feed for Unknown feed name",
                            "element 'anchor_0' not found",
                            "element 'desc_0' not found",
                            "This feed contains no entries.");
}

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedInvalidFeed4) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  // subscribe.js shouldn't double-decode the URL passed in. Otherwise feed
  // links such as http://search.twitter.com/search.atom?lang=en&q=%23chrome
  // will result in no feed being downloaded because %23 gets decoded to # and
  // therefore #chrome is not treated as part of the Twitter query. This test
  // uses an underscore instead of a hash, but the principle is the same. If
  // we start erroneously double decoding again, the path (and the feed) will
  // become valid resulting in a failure for this test.
  NavigateToFeedAndValidate(
      test_server(), kFeedTripleEncoded, browser(), id, true,
      "Feed for Unknown feed name",
      "element 'anchor_0' not found",
      "element 'desc_0' not found",
      "This feed contains no entries.");
}

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedValidFeedNoLinks) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  // Valid feed but containing no links.
  NavigateToFeedAndValidate(
      test_server(), kValidFeedNoLinks, browser(), id, true,
      "Feed for MyFeedTitle",
      "Title with no link",
      "Desc",
      "No error");
}
<commit_msg>Disable ExtensionBrowserTest.RSSParseValidFeed*<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 "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"

using content::WebContents;
using extensions::Extension;

namespace {

const char kSubscribePage[] = "/subscribe.html";
const char kFeedPageMultiRel[] = "files/feeds/feed_multi_rel.html";
const char kValidFeedNoLinks[] = "files/feeds/feed_nolinks.xml";
const char kValidFeed0[] = "files/feeds/feed_script.xml";
const char kValidFeed1[] = "files/feeds/feed1.xml";
const char kValidFeed2[] = "files/feeds/feed2.xml";
const char kValidFeed3[] = "files/feeds/feed3.xml";
const char kValidFeed4[] = "files/feeds/feed4.xml";
const char kValidFeed5[] = "files/feeds/feed5.xml";
const char kValidFeed6[] = "files/feeds/feed6.xml";
const char kInvalidFeed1[] = "files/feeds/feed_invalid1.xml";
const char kInvalidFeed2[] = "files/feeds/feed_invalid2.xml";
// We need a triple encoded string to prove that we are not decoding twice in
// subscribe.js because one layer is also stripped off when subscribe.js passes
// it to the XMLHttpRequest object.
const char kFeedTripleEncoded[] = "files/feeds/url%25255Fdecoding.html";

static const char kScriptFeedTitle[] =
    "window.domAutomationController.send("
    "  document.getElementById('title') ? "
    "    document.getElementById('title').textContent : "
    "    \"element 'title' not found\""
    ");";
static const char kScriptAnchor[] =
    "window.domAutomationController.send("
    "  document.getElementById('anchor_0') ? "
    "    document.getElementById('anchor_0').textContent : "
    "    \"element 'anchor_0' not found\""
    ");";
static const char kScriptDesc[] =
    "window.domAutomationController.send("
    "  document.getElementById('desc_0') ? "
    "    document.getElementById('desc_0').textContent : "
    "    \"element 'desc_0' not found\""
    ");";
static const char kScriptError[] =
    "window.domAutomationController.send("
    "  document.getElementById('error') ? "
    "    document.getElementById('error').textContent : "
    "    \"No error\""
    ");";

GURL GetFeedUrl(net::SpawnedTestServer* server, const std::string& feed_page,
                bool direct_url, std::string extension_id) {
  GURL feed_url = server->GetURL(feed_page);
  if (direct_url) {
    // We navigate directly to the subscribe page for feeds where the feed
    // sniffing won't work, in other words, as is the case for malformed feeds.
    return GURL(std::string(extensions::kExtensionScheme) +
        url::kStandardSchemeSeparator +
        extension_id + std::string(kSubscribePage) + std::string("?") +
        feed_url.spec() + std::string("&synchronous"));
  } else {
    // Navigate to the feed content (which will cause the extension to try to
    // sniff the type and display the subscribe page in another tab.
    return GURL(feed_url.spec());
  }
}

bool ValidatePageElement(content::RenderFrameHost* frame,
                         const std::string& javascript,
                         const std::string& expected_value) {
  std::string returned_value;

  if (!content::ExecuteScriptAndExtractString(frame,
                                              javascript,
                                              &returned_value))
    return false;

  EXPECT_STREQ(expected_value.c_str(), returned_value.c_str());
  return expected_value == returned_value;
}

// Navigates to a feed page and, if |sniff_xml_type| is set, wait for the
// extension to kick in, detect the feed and redirect to a feed preview page.
// |sniff_xml_type| is generally set to true if the feed is sniffable and false
// for invalid feeds.
void NavigateToFeedAndValidate(net::SpawnedTestServer* server,
                               const std::string& url,
                               Browser* browser,
                               std::string extension_id,
                               bool sniff_xml_type,
                               const std::string& expected_feed_title,
                               const std::string& expected_item_title,
                               const std::string& expected_item_desc,
                               const std::string& expected_error) {
  if (sniff_xml_type) {
    // TODO(finnur): Implement this is a non-flaky way.
  }

  // Navigate to the subscribe page directly.
  ui_test_utils::NavigateToURL(browser,
                               GetFeedUrl(server, url, true, extension_id));

  WebContents* tab = browser->tab_strip_model()->GetActiveWebContents();
  content::RenderFrameHost* frame = content::FrameMatchingPredicate(
      tab, base::Bind(&content::FrameIsChildOfMainFrame));
  ASSERT_TRUE(ValidatePageElement(
      tab->GetMainFrame(), kScriptFeedTitle, expected_feed_title));
  ASSERT_TRUE(ValidatePageElement(frame, kScriptAnchor, expected_item_title));
  ASSERT_TRUE(ValidatePageElement(frame, kScriptDesc, expected_item_desc));
  ASSERT_TRUE(ValidatePageElement(frame, kScriptError, expected_error));
}

} // namespace

// Makes sure that the RSS detects RSS feed links, even when rel tag contains
// more than just "alternate".
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSMultiRelLink) {
  ASSERT_TRUE(test_server()->Start());

  ASSERT_TRUE(LoadExtension(
    test_data_dir_.AppendASCII("subscribe_page_action")));

  ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(0));

  // Navigate to the feed page.
  GURL feed_url = test_server()->GetURL(kFeedPageMultiRel);
  ui_test_utils::NavigateToURL(browser(), feed_url);
  // We should now have one page action ready to go in the LocationBar.
  ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1));
}

// This test is flaky on all platforms; see http://crbug.com/340354
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, DISABLED_RSSParseFeedValidFeed1) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  NavigateToFeedAndValidate(test_server(), kValidFeed1, browser(), id, true,
                            "Feed for MyFeedTitle",
                            "Title 1",
                            "Desc",
                            "No error");
}

// This test is flaky on all platforms; see http://crbug.com/340354
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, DISABLED_RSSParseFeedValidFeed2) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  NavigateToFeedAndValidate(test_server(), kValidFeed2, browser(), id, true,
                            "Feed for MyFeed2",
                            "My item title1",
                            "This is a summary.",
                            "No error");
}

// This test is flaky on all platforms; see http://crbug.com/340354
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, DISABLED_RSSParseFeedValidFeed3) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  NavigateToFeedAndValidate(test_server(), kValidFeed3, browser(), id, true,
                            "Feed for Google Code buglist rss feed",
                            "My dear title",
                            "My dear content",
                            "No error");
}

// This test is flaky on all platforms; see http://crbug.com/340354
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, DISABLED_RSSParseFeedValidFeed4) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  NavigateToFeedAndValidate(test_server(), kValidFeed4, browser(), id, true,
                            "Feed for Title chars <script> %23 stop",
                            "Title chars  %23 stop",
                            "My dear content %23 stop",
                            "No error");
}

// This test is flaky on all platforms; see http://crbug.com/340354
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, DISABLED_RSSParseFeedValidFeed0) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  // Try a feed with a link with an onclick handler (before r27440 this would
  // trigger a NOTREACHED).
  NavigateToFeedAndValidate(test_server(), kValidFeed0, browser(), id, true,
                            "Feed for MyFeedTitle",
                            "Title 1",
                            "Desc VIDEO",
                            "No error");
}

// This test is flaky on all platforms; see http://crbug.com/340354
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, DISABLED_RSSParseFeedValidFeed5) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  // Feed with valid but mostly empty xml.
  NavigateToFeedAndValidate(test_server(), kValidFeed5, browser(), id, true,
                            "Feed for Unknown feed name",
                            "element 'anchor_0' not found",
                            "element 'desc_0' not found",
                            "This feed contains no entries.");
}

// This test is flaky on all platforms; see http://crbug.com/340354
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, DISABLED_RSSParseFeedValidFeed6) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  // Feed that is technically invalid but still parseable.
  NavigateToFeedAndValidate(test_server(), kValidFeed6, browser(), id, true,
                            "Feed for MyFeedTitle",
                            "Title 1",
                            "Desc",
                            "No error");
}

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedInvalidFeed1) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  // Try an empty feed.
  NavigateToFeedAndValidate(test_server(), kInvalidFeed1, browser(), id, false,
                            "Feed for Unknown feed name",
                            "element 'anchor_0' not found",
                            "element 'desc_0' not found",
                            "This feed contains no entries.");
}

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedInvalidFeed2) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  // Try a garbage feed.
  NavigateToFeedAndValidate(test_server(), kInvalidFeed2, browser(), id, false,
                            "Feed for Unknown feed name",
                            "element 'anchor_0' not found",
                            "element 'desc_0' not found",
                            "This feed contains no entries.");
}

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedInvalidFeed3) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  // Try a feed that doesn't exist.
  NavigateToFeedAndValidate(test_server(), "foo.xml", browser(), id, false,
                            "Feed for Unknown feed name",
                            "element 'anchor_0' not found",
                            "element 'desc_0' not found",
                            "This feed contains no entries.");
}

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSParseFeedInvalidFeed4) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  // subscribe.js shouldn't double-decode the URL passed in. Otherwise feed
  // links such as http://search.twitter.com/search.atom?lang=en&q=%23chrome
  // will result in no feed being downloaded because %23 gets decoded to # and
  // therefore #chrome is not treated as part of the Twitter query. This test
  // uses an underscore instead of a hash, but the principle is the same. If
  // we start erroneously double decoding again, the path (and the feed) will
  // become valid resulting in a failure for this test.
  NavigateToFeedAndValidate(
      test_server(), kFeedTripleEncoded, browser(), id, true,
      "Feed for Unknown feed name",
      "element 'anchor_0' not found",
      "element 'desc_0' not found",
      "This feed contains no entries.");
}

// This test is flaky on all platforms; see http://crbug.com/340354
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest,
                       DISABLED_RSSParseFeedValidFeedNoLinks) {
  ASSERT_TRUE(test_server()->Start());

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("subscribe_page_action"));
  ASSERT_TRUE(extension);
  std::string id = extension->id();

  // Valid feed but containing no links.
  NavigateToFeedAndValidate(
      test_server(), kValidFeedNoLinks, browser(), id, true,
      "Feed for MyFeedTitle",
      "Title with no link",
      "Desc",
      "No error");
}
<|endoftext|>


<commit_before>// Copyright 2014 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 "ui/events/ozone/evdev/device_manager_udev.h"

#include <libudev.h>

#include "base/debug/trace_event.h"
#include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_pump_ozone.h"
#include "base/strings/stringprintf.h"
#include "ui/events/ozone/evdev/device_manager_evdev.h"
#include "ui/events/ozone/evdev/event_factory_evdev.h"
#include "ui/events/ozone/evdev/scoped_udev.h"

namespace ui {

namespace {

const char kSubsystemInput[] = "input";

// Severity levels from syslog.h. We can't include it directly as it
// conflicts with base/logging.h
enum {
  SYS_LOG_EMERG = 0,
  SYS_LOG_ALERT = 1,
  SYS_LOG_CRIT = 2,
  SYS_LOG_ERR = 3,
  SYS_LOG_WARNING = 4,
  SYS_LOG_NOTICE = 5,
  SYS_LOG_INFO = 6,
  SYS_LOG_DEBUG = 7,
};

// Log handler for messages generated from libudev.
void UdevLog(struct udev* udev,
             int priority,
             const char* file,
             int line,
             const char* fn,
             const char* format,
             va_list args) {
  std::string message = base::StringPrintf("libudev: %s: ", fn);
  base::StringAppendV(&message, format, args);
  if (priority <= SYS_LOG_ERR)
    LOG(ERROR) << message;
  else if (priority <= SYS_LOG_INFO)
    VLOG(1) << message;
  else  // SYS_LOG_DEBUG
    VLOG(2) << message;
}

// Create libudev context.
scoped_udev UdevCreate() {
  struct udev* udev = udev_new();
  if (udev) {
    udev_set_log_fn(udev, UdevLog);
    udev_set_log_priority(udev, SYS_LOG_DEBUG);
  }
  return scoped_udev(udev);
}

// Start monitoring input device changes.
scoped_udev_monitor UdevCreateMonitor(struct udev* udev) {
  struct udev_monitor* monitor = udev_monitor_new_from_netlink(udev, "udev");
  if (monitor) {
    udev_monitor_filter_add_match_subsystem_devtype(
        monitor, kSubsystemInput, NULL);

    if (udev_monitor_enable_receiving(monitor))
      LOG(ERROR) << "failed to start receiving events from udev";
  }

  return scoped_udev_monitor(monitor);
}

// Enumerate all input devices using udev. Calls device_callback per device.
bool UdevEnumerateInputDevices(struct udev* udev,
                               const EvdevDeviceCallback& device_callback) {
  scoped_udev_enumerate enumerate(udev_enumerate_new(udev));
  if (!enumerate)
    return false;

  // Build list of devices with subsystem "input".
  udev_enumerate_add_match_subsystem(enumerate.get(), kSubsystemInput);
  udev_enumerate_scan_devices(enumerate.get());

  struct udev_list_entry* devices =
      udev_enumerate_get_list_entry(enumerate.get());
  struct udev_list_entry* entry;

  // Run callback per device in the list.
  udev_list_entry_foreach(entry, devices) {
    const char* name = udev_list_entry_get_name(entry);

    scoped_udev_device device(udev_device_new_from_syspath(udev, name));
    if (!device)
      continue;

    const char* path = udev_device_get_devnode(device.get());
    if (!path)
      continue;

    // Found input device node; attach.
    device_callback.Run(base::FilePath(path));
  }

  return true;
}

// Device enumerator & monitor using udev.
//
// This class enumerates input devices attached to the system using udev.
//
// It also creates & monitors a udev netlink socket and issues callbacks for
// any changes to the set of attached devices.
//
// TODO(spang): Figure out how to test this.
class DeviceManagerUdev : public DeviceManagerEvdev,
                          base::MessagePumpLibevent::Watcher {
 public:
  DeviceManagerUdev() {}
  virtual ~DeviceManagerUdev() { Stop(); }

  // Enumerate existing devices & start watching for device changes.
  virtual void ScanAndStartMonitoring(const EvdevDeviceCallback& device_added,
                                      const EvdevDeviceCallback& device_removed)
      OVERRIDE {
    udev_ = UdevCreate();
    if (!udev_) {
      LOG(ERROR) << "failed to initialize libudev";
      return;
    }

    if (!StartMonitoring(device_added, device_removed))
      LOG(ERROR) << "failed to start monitoring device changes via udev";

    if (!UdevEnumerateInputDevices(udev_.get(), device_added))
      LOG(ERROR) << "failed to enumerate input devices via udev";
  }

  virtual void Stop() OVERRIDE {
    controller_.StopWatchingFileDescriptor();
    device_added_.Reset();
    device_removed_.Reset();
  }

  virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE {
    // The netlink socket should never become disconnected. There's no need
    // to handle broken connections here.
    TRACE_EVENT1("ozone", "UdevDeviceChange", "socket", fd);

    scoped_udev_device device(udev_monitor_receive_device(udev_monitor_.get()));
    if (!device)
      return;

    const char* path = udev_device_get_devnode(device.get());
    const char* action = udev_device_get_action(device.get());
    if (!path || !action)
      return;

    if (!strcmp(action, "add") || !strcmp(action, "change"))
      device_added_.Run(base::FilePath(path));
    else if (!strcmp(action, "remove"))
      device_removed_.Run(base::FilePath(path));
  }

  virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE { NOTREACHED(); }

 private:
  bool StartMonitoring(const EvdevDeviceCallback& device_added,
                       const EvdevDeviceCallback& device_removed) {
    udev_monitor_ = UdevCreateMonitor(udev_.get());
    if (!udev_monitor_)
      return false;

    // Grab monitor socket.
    int fd = udev_monitor_get_fd(udev_monitor_.get());
    if (fd < 0)
      return false;

    // Save callbacks.
    device_added_ = device_added;
    device_removed_ = device_removed;

    // Watch for incoming events on monitor socket.
    return base::MessagePumpOzone::Current()->WatchFileDescriptor(
        fd, true, base::MessagePumpOzone::WATCH_READ, &controller_, this);
  }

  // Udev daemon connection.
  scoped_udev udev_;

  // Udev device change monitor.
  scoped_udev_monitor udev_monitor_;

  // Callbacks for device changes.
  EvdevDeviceCallback device_added_;
  EvdevDeviceCallback device_removed_;

  // Watcher for uevent netlink socket.
  base::MessagePumpLibevent::FileDescriptorWatcher controller_;

  DISALLOW_COPY_AND_ASSIGN(DeviceManagerUdev);
};

}  // namespace

scoped_ptr<DeviceManagerEvdev> CreateDeviceManagerUdev() {
  return make_scoped_ptr<DeviceManagerEvdev>(new DeviceManagerUdev());
}

}  // namespace ui
<commit_msg>ozone: evdev: Avoid unnecessary log message building<commit_after>// Copyright 2014 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 "ui/events/ozone/evdev/device_manager_udev.h"

#include <libudev.h>

#include "base/debug/trace_event.h"
#include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_pump_ozone.h"
#include "base/strings/stringprintf.h"
#include "ui/events/ozone/evdev/device_manager_evdev.h"
#include "ui/events/ozone/evdev/event_factory_evdev.h"
#include "ui/events/ozone/evdev/scoped_udev.h"

namespace ui {

namespace {

const char kSubsystemInput[] = "input";

// Severity levels from syslog.h. We can't include it directly as it
// conflicts with base/logging.h
enum {
  SYS_LOG_EMERG = 0,
  SYS_LOG_ALERT = 1,
  SYS_LOG_CRIT = 2,
  SYS_LOG_ERR = 3,
  SYS_LOG_WARNING = 4,
  SYS_LOG_NOTICE = 5,
  SYS_LOG_INFO = 6,
  SYS_LOG_DEBUG = 7,
};

// Log handler for messages generated from libudev.
void UdevLog(struct udev* udev,
             int priority,
             const char* file,
             int line,
             const char* fn,
             const char* format,
             va_list args) {
  if (priority <= SYS_LOG_ERR)
    LOG(ERROR) << "libudev: " << fn << ": " << base::StringPrintV(format, args);
  else if (priority <= SYS_LOG_INFO)
    VLOG(1) << "libudev: " << fn << ": " << base::StringPrintV(format, args);
  else  // SYS_LOG_DEBUG
    VLOG(2) << "libudev: " << fn << ": " << base::StringPrintV(format, args);
}

// Create libudev context.
scoped_udev UdevCreate() {
  struct udev* udev = udev_new();
  if (udev) {
    udev_set_log_fn(udev, UdevLog);
    udev_set_log_priority(udev, SYS_LOG_DEBUG);
  }
  return scoped_udev(udev);
}

// Start monitoring input device changes.
scoped_udev_monitor UdevCreateMonitor(struct udev* udev) {
  struct udev_monitor* monitor = udev_monitor_new_from_netlink(udev, "udev");
  if (monitor) {
    udev_monitor_filter_add_match_subsystem_devtype(
        monitor, kSubsystemInput, NULL);

    if (udev_monitor_enable_receiving(monitor))
      LOG(ERROR) << "failed to start receiving events from udev";
  }

  return scoped_udev_monitor(monitor);
}

// Enumerate all input devices using udev. Calls device_callback per device.
bool UdevEnumerateInputDevices(struct udev* udev,
                               const EvdevDeviceCallback& device_callback) {
  scoped_udev_enumerate enumerate(udev_enumerate_new(udev));
  if (!enumerate)
    return false;

  // Build list of devices with subsystem "input".
  udev_enumerate_add_match_subsystem(enumerate.get(), kSubsystemInput);
  udev_enumerate_scan_devices(enumerate.get());

  struct udev_list_entry* devices =
      udev_enumerate_get_list_entry(enumerate.get());
  struct udev_list_entry* entry;

  // Run callback per device in the list.
  udev_list_entry_foreach(entry, devices) {
    const char* name = udev_list_entry_get_name(entry);

    scoped_udev_device device(udev_device_new_from_syspath(udev, name));
    if (!device)
      continue;

    const char* path = udev_device_get_devnode(device.get());
    if (!path)
      continue;

    // Found input device node; attach.
    device_callback.Run(base::FilePath(path));
  }

  return true;
}

// Device enumerator & monitor using udev.
//
// This class enumerates input devices attached to the system using udev.
//
// It also creates & monitors a udev netlink socket and issues callbacks for
// any changes to the set of attached devices.
//
// TODO(spang): Figure out how to test this.
class DeviceManagerUdev : public DeviceManagerEvdev,
                          base::MessagePumpLibevent::Watcher {
 public:
  DeviceManagerUdev() {}
  virtual ~DeviceManagerUdev() { Stop(); }

  // Enumerate existing devices & start watching for device changes.
  virtual void ScanAndStartMonitoring(const EvdevDeviceCallback& device_added,
                                      const EvdevDeviceCallback& device_removed)
      OVERRIDE {
    udev_ = UdevCreate();
    if (!udev_) {
      LOG(ERROR) << "failed to initialize libudev";
      return;
    }

    if (!StartMonitoring(device_added, device_removed))
      LOG(ERROR) << "failed to start monitoring device changes via udev";

    if (!UdevEnumerateInputDevices(udev_.get(), device_added))
      LOG(ERROR) << "failed to enumerate input devices via udev";
  }

  virtual void Stop() OVERRIDE {
    controller_.StopWatchingFileDescriptor();
    device_added_.Reset();
    device_removed_.Reset();
  }

  virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE {
    // The netlink socket should never become disconnected. There's no need
    // to handle broken connections here.
    TRACE_EVENT1("ozone", "UdevDeviceChange", "socket", fd);

    scoped_udev_device device(udev_monitor_receive_device(udev_monitor_.get()));
    if (!device)
      return;

    const char* path = udev_device_get_devnode(device.get());
    const char* action = udev_device_get_action(device.get());
    if (!path || !action)
      return;

    if (!strcmp(action, "add") || !strcmp(action, "change"))
      device_added_.Run(base::FilePath(path));
    else if (!strcmp(action, "remove"))
      device_removed_.Run(base::FilePath(path));
  }

  virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE { NOTREACHED(); }

 private:
  bool StartMonitoring(const EvdevDeviceCallback& device_added,
                       const EvdevDeviceCallback& device_removed) {
    udev_monitor_ = UdevCreateMonitor(udev_.get());
    if (!udev_monitor_)
      return false;

    // Grab monitor socket.
    int fd = udev_monitor_get_fd(udev_monitor_.get());
    if (fd < 0)
      return false;

    // Save callbacks.
    device_added_ = device_added;
    device_removed_ = device_removed;

    // Watch for incoming events on monitor socket.
    return base::MessagePumpOzone::Current()->WatchFileDescriptor(
        fd, true, base::MessagePumpOzone::WATCH_READ, &controller_, this);
  }

  // Udev daemon connection.
  scoped_udev udev_;

  // Udev device change monitor.
  scoped_udev_monitor udev_monitor_;

  // Callbacks for device changes.
  EvdevDeviceCallback device_added_;
  EvdevDeviceCallback device_removed_;

  // Watcher for uevent netlink socket.
  base::MessagePumpLibevent::FileDescriptorWatcher controller_;

  DISALLOW_COPY_AND_ASSIGN(DeviceManagerUdev);
};

}  // namespace

scoped_ptr<DeviceManagerEvdev> CreateDeviceManagerUdev() {
  return make_scoped_ptr<DeviceManagerEvdev>(new DeviceManagerUdev());
}

}  // namespace ui
<|endoftext|>


<commit_before>/** ==========================================================================
* 2012 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================
* Filename:g2loglevels.cpp  Part of Framework for Logging and Design By Contract
* Created: 2012 by Kjell Hedström
*
* PUBLIC DOMAIN and Not copywrited. First published at KjellKod.cc
* ********************************************* */

#include "g2loglevels.hpp"
#include "g2log.hpp"
#include <atomic>
#include <cassert>
namespace g2
{
  namespace internal {
     bool wasFatal(const LEVELS& level) {
        return level.value >= FATAL.value;
     }

     // All levels are by default ON: i.e. for DEBUG, INFO, WARNING, FATAL
    constexpr const int size{ FATAL.value + 1 };
    std::atomic<bool> g_log_level_status[4]{{true}, {true}, {true},{true}};

	#ifndef _MSC_VER
	static_assert(4 == size, "Mismatch between number of logging levels and their use");
	#endif
  } // internal

#ifdef G2_DYNAMIC_LOGGING
  void setLogLevel(LEVELS log_level, bool enabled)
  {
    // MSC: remove when constexpr available. see static_assert above
    assert(size == 4 && "Mismatch between number of logging levels and their use");
    int level = log_level.value;
    CHECK((level >= DEBUG.value) && (level <= FATAL.value));
    internal::g_log_level_status[level].store(enabled, std::memory_order_release);
  }
#endif

  bool logLevel(LEVELS log_level)
  {
#ifdef G2_DYNAMIC_LOGGING
    int level = log_level.value;
    CHECK((level >= DEBUG.value) && (level <= FATAL.value));
    bool status = (internal::g_log_level_status[level].load(std::memory_order_acquire));
    return status;
#endif
    return true;
  }

} // g2
<commit_msg>Thanks to Aleksey Dobrunov who noticed this compile error. Weird that it did not show up in gcc<commit_after>/** ==========================================================================
* 2012 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================
* Filename:g2loglevels.cpp  Part of Framework for Logging and Design By Contract
* Created: 2012 by Kjell Hedström
*
* PUBLIC DOMAIN and Not copywrited. First published at KjellKod.cc
* ********************************************* */

#include "g2loglevels.hpp"
#include "g2log.hpp"
#include <atomic>
#include <cassert>
namespace g2
{
  namespace internal {
     bool wasFatal(const LEVELS& level) {
        return level.value >= FATAL.value;
     }

     // All levels are by default ON: i.e. for DEBUG, INFO, WARNING, FATAL
    constexpr const int g_level_size{ FATAL.value + 1 };
    std::atomic<bool> g_log_level_status[4]{{true}, {true}, {true},{true}};

	#ifndef _MSC_VER
	static_assert(4 == g_level_size, "Mismatch between number of logging levels and their use");
	#endif
  } // internal

#ifdef G2_DYNAMIC_LOGGING
  void setLogLevel(LEVELS log_level, bool enabled)
  {
    // MSC: remove when constexpr available. see static_assert above
    assert(internal::g_level_size == 4 && "Mismatch between number of logging levels and their use");
    int level = log_level.value;
    CHECK((level >= DEBUG.value) && (level <= FATAL.value));
    internal::g_log_level_status[level].store(enabled, std::memory_order_release);
  }
#endif

  bool logLevel(LEVELS log_level)
  {
#ifdef G2_DYNAMIC_LOGGING
    int level = log_level.value;
    CHECK((level >= DEBUG.value) && (level <= FATAL.value));
    bool status = (internal::g_log_level_status[level].load(std::memory_order_acquire));
    return status;
#endif
    return true;
  }

} // g2
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "PowerManagement.h"
#include "logging/RhoLog.h"
#include "common/RhodesApp.h"

#include <pm.h>

#undef DEFAULT_LOGCATEGORY
#define DEFAULT_LOGCATEGORY "PowerManagement"

extern "C" void createPowerManagementThread()
{
    rho::common::PowerNotificationThread* g_powerManageThread = new rho::common::PowerNotificationThread();
    g_powerManageThread->start(rho::common::IRhoRunnable::epNormal);
};

namespace rho {
namespace common {

void PowerNotificationThread::run()
{
    // size of a POWER_BROADCAST message
    DWORD cbPowerMsgSize = sizeof POWER_BROADCAST + (MAX_PATH * sizeof TCHAR);

    // Initialize our MSGQUEUEOPTIONS structure
    MSGQUEUEOPTIONS mqo;
    mqo.dwSize        = sizeof(MSGQUEUEOPTIONS);
    mqo.dwFlags       = MSGQUEUE_NOPRECOMMIT;
    mqo.dwMaxMessages = 4;
    mqo.cbMaxMessage  = cbPowerMsgSize;
    mqo.bReadAccess   = TRUE;

    // Create a message queue to receive power notifications
    m_powerMsgQ = CreateMsgQueue(NULL, &mqo);
    if (NULL == m_powerMsgQ)
    {
        RAWLOG_ERROR1("CreateMsgQueue failed: %x", GetLastError());
        closePowerManQueue();
        return;
    }

    // Request power notifications
    m_powerNotifications = RequestPowerNotifications(m_powerMsgQ, PBT_TRANSITION);
    if (NULL == m_powerNotifications)
    {
        RAWLOG_ERROR1("RequestPowerNotifications failed: %x", GetLastError());
        closePowerManQueue();
        return;
    }

    // Wait for a power notification or for the app to exit
    while(WaitForSingleObject(m_powerMsgQ, INFINITE) == WAIT_OBJECT_0)
    {
        DWORD cbRead;
        DWORD dwFlags;
        POWER_BROADCAST *ppb = (POWER_BROADCAST*) new BYTE[cbPowerMsgSize];

        // loop through in case there is more than 1 msg
        while(ReadMsgQueue(m_powerMsgQ, ppb, cbPowerMsgSize, &cbRead,
            0, &dwFlags))
        {
            if (ppb->Message == PBT_TRANSITION)
            {
                if (ppb->Flags & POWER_STATE_ON)
                {
                    rho_rhodesapp_callScreenOnCallback();
                    rho_rhodesapp_callScreenUnlockedCallback();
                }
                else if (ppb->Flags & POWER_STATE_UNATTENDED)
                {
                    rho_rhodesapp_callScreenLockedCallback();
                    rho_rhodesapp_callScreenOffCallback();
                }
            }
        }

        delete[] ppb;
    }

    closePowerManQueue();
}

void PowerNotificationThread::closePowerManQueue()
{
    if (m_powerNotifications)
        StopPowerNotifications(m_powerNotifications);

    if (m_powerMsgQ)
        CloseMsgQueue(m_powerMsgQ);
}

}
}<commit_msg>ce: fix build<commit_after>#include "stdafx.h"
#include "PowerManagement.h"
#include "logging/RhoLog.h"
#include "common/RhodesApp.h"

#include <pm.h>

//TODO: read: http://msdn.microsoft.com/en-us/library/ms894059.aspx ; there is no  POWER_STATE_UNATTENDED on CE
#ifndef POWER_STATE_UNATTENDED
#define POWER_STATE_UNATTENDED   (DWORD)(0x00400000)        // Unattended state.
#endif

#undef DEFAULT_LOGCATEGORY
#define DEFAULT_LOGCATEGORY "PowerManagement"

extern "C" void createPowerManagementThread()
{
    rho::common::PowerNotificationThread* g_powerManageThread = new rho::common::PowerNotificationThread();
    g_powerManageThread->start(rho::common::IRhoRunnable::epNormal);
};

namespace rho {
namespace common {

void PowerNotificationThread::run()
{
    // size of a POWER_BROADCAST message
    DWORD cbPowerMsgSize = sizeof POWER_BROADCAST + (MAX_PATH * sizeof TCHAR);

    // Initialize our MSGQUEUEOPTIONS structure
    MSGQUEUEOPTIONS mqo;
    mqo.dwSize        = sizeof(MSGQUEUEOPTIONS);
    mqo.dwFlags       = MSGQUEUE_NOPRECOMMIT;
    mqo.dwMaxMessages = 4;
    mqo.cbMaxMessage  = cbPowerMsgSize;
    mqo.bReadAccess   = TRUE;

    // Create a message queue to receive power notifications
    m_powerMsgQ = CreateMsgQueue(NULL, &mqo);
    if (NULL == m_powerMsgQ)
    {
        RAWLOG_ERROR1("CreateMsgQueue failed: %x", GetLastError());
        closePowerManQueue();
        return;
    }

    // Request power notifications
    m_powerNotifications = RequestPowerNotifications(m_powerMsgQ, PBT_TRANSITION);
    if (NULL == m_powerNotifications)
    {
        RAWLOG_ERROR1("RequestPowerNotifications failed: %x", GetLastError());
        closePowerManQueue();
        return;
    }

    // Wait for a power notification or for the app to exit
    while(WaitForSingleObject(m_powerMsgQ, INFINITE) == WAIT_OBJECT_0)
    {
        DWORD cbRead;
        DWORD dwFlags;
        POWER_BROADCAST *ppb = (POWER_BROADCAST*) new BYTE[cbPowerMsgSize];

        // loop through in case there is more than 1 msg
        while(ReadMsgQueue(m_powerMsgQ, ppb, cbPowerMsgSize, &cbRead,
            0, &dwFlags))
        {
            if (ppb->Message == PBT_TRANSITION)
            {
                if (ppb->Flags & POWER_STATE_ON)
                {
                    rho_rhodesapp_callScreenOnCallback();
                    rho_rhodesapp_callScreenUnlockedCallback();
                }
                else if (ppb->Flags & POWER_STATE_UNATTENDED)
                {
                    rho_rhodesapp_callScreenLockedCallback();
                    rho_rhodesapp_callScreenOffCallback();
                }
            }
        }

        delete[] ppb;
    }

    closePowerManQueue();
}

void PowerNotificationThread::closePowerManQueue()
{
    if (m_powerNotifications)
        StopPowerNotifications(m_powerNotifications);

    if (m_powerMsgQ)
        CloseMsgQueue(m_powerMsgQ);
}

}
}<|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 "chrome/browser/ui/views/ash/app_list/app_list_model_builder.h"

#include "base/i18n/case_conversion.h"
#include "base/i18n/string_search.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/views/ash/app_list/extension_app_item.h"
#include "chrome/common/chrome_notification_types.h"
#include "content/public/browser/notification_service.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/l10n/l10n_util_collator.h"

namespace {

// ModelItemSortData provides a string key to sort with
// l10n_util::StringComparator.
struct ModelItemSortData {
  explicit ModelItemSortData(ash::AppListItemModel* item)
      : item(item),
        key(base::i18n::ToLower(UTF8ToUTF16(item->title()))) {
  }

  // Needed by StringComparator<Element> in SortVectorWithStringKey, which uses
  // this method to get a key to sort.
  const string16& GetStringKey() const {
    return key;
  }

  ash::AppListItemModel* item;
  string16 key;
};

// Returns true if given |str| matches |query|. Currently, it returns
// if |query| is a substr of |str|.
bool MatchesQuery(const string16& query, const string16& str) {
  return query.empty() ||
      base::i18n::StringSearchIgnoringCaseAndAccents(query, str);
}

}  // namespace

AppListModelBuilder::AppListModelBuilder(Profile* profile)
    : profile_(profile),
      model_(NULL) {
  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
      content::Source<Profile>(profile_));
  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
      content::Source<Profile>(profile_));
  registrar_.Add(this, chrome::NOTIFICATION_APP_INSTALLED_TO_APPLIST,
      content::Source<Profile>(profile_));
}

AppListModelBuilder::~AppListModelBuilder() {
}

void AppListModelBuilder::SetModel(ash::AppListModel* model) {
  model_ = model;
}

void AppListModelBuilder::Build(const std::string& query) {
  DCHECK(model_ && model_->item_count() == 0);
  query_ = base::i18n::ToLower(UTF8ToUTF16(query));

  Items items;
  GetExtensionApps(query_, &items);

  SortAndPopulateModel(items);
  HighlightApp();
}

void AppListModelBuilder::SortAndPopulateModel(const Items& items) {
  // Sort items case insensitive alphabetically.
  std::vector<ModelItemSortData> sorted;
  for (Items::const_iterator it = items.begin(); it != items.end(); ++it)
    sorted.push_back(ModelItemSortData(*it));

  l10n_util::SortVectorWithStringKey(g_browser_process->GetApplicationLocale(),
                                     &sorted,
                                     false /* needs_stable_sort */);
  for (std::vector<ModelItemSortData>::const_iterator it = sorted.begin();
       it != sorted.end();
       ++it) {
    model_->AddItem(it->item);
  }
}

void AppListModelBuilder::InsertItemByTitle(ash::AppListItemModel* item) {
  DCHECK(model_);

  icu::Locale locale(g_browser_process->GetApplicationLocale().c_str());
  UErrorCode error = U_ZERO_ERROR;
  scoped_ptr<icu::Collator> collator(
      icu::Collator::createInstance(locale, error));
  if (U_FAILURE(error))
    collator.reset();

  l10n_util::StringComparator<string16> c(collator.get());
  ModelItemSortData data(item);
  for (int i = 0; i < model_->item_count(); ++i) {
    ModelItemSortData current(model_->GetItem(i));
    if (!c(current.key, data.key)) {
      model_->AddItemAt(i, item);
      return;
    }
  }
  model_->AddItem(item);
}

void AppListModelBuilder::GetExtensionApps(const string16& query,
                                           Items* items) {
  DCHECK(profile_);
  ExtensionService* service = profile_->GetExtensionService();
  if (!service)
    return;

  // Get extension apps.
  const ExtensionSet* extensions = service->extensions();
  for (ExtensionSet::const_iterator app = extensions->begin();
       app != extensions->end(); ++app) {
    if ((*app)->ShouldDisplayInLauncher() &&
        MatchesQuery(query, UTF8ToUTF16((*app)->name()))) {
      items->push_back(new ExtensionAppItem(profile_, *app));
    }
  }
}

int AppListModelBuilder::FindApp(const std::string& app_id) {
  DCHECK(model_);
  for (int i = 0; i < model_->item_count(); ++i) {
    ExtensionAppItem* extension_item =
        static_cast<ExtensionAppItem*>(model_->GetItem(i));
    if (extension_item->extension_id() == app_id)
      return i;
  }

  return -1;
}

void AppListModelBuilder::HighlightApp() {
  DCHECK(model_);
  if (highlight_app_id_.empty())
    return;

  int index = FindApp(highlight_app_id_);
  if (index == -1)
    return;

  model_->GetItem(index)->SetHighlighted(true);
  highlight_app_id_.clear();
}

void AppListModelBuilder::Observe(int type,
                                  const content::NotificationSource& source,
                                  const content::NotificationDetails& details) {
  switch (type) {
    case chrome::NOTIFICATION_EXTENSION_LOADED: {
      const Extension* extension =
          content::Details<const Extension>(details).ptr();
      if (!extension->ShouldDisplayInLauncher() ||
          !MatchesQuery(query_, UTF8ToUTF16(extension->name())))
        return;

      if (FindApp(extension->id()) != -1)
        return;

      InsertItemByTitle(new ExtensionAppItem(profile_, extension));
      HighlightApp();
      break;
    }
    case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
      const Extension* extension =
          content::Details<const Extension>(details).ptr();
      int index = FindApp(extension->id());
      if (index >= 0)
        model_->DeleteItemAt(index);
      break;
    }
    case chrome::NOTIFICATION_APP_INSTALLED_TO_APPLIST: {
      highlight_app_id_ = *content::Details<const std::string>(details).ptr();
      HighlightApp();
      break;
    }
    default:
      NOTREACHED();
  }
}
<commit_msg>Fix notification detail type in AppListModelBuilder::Observe for extension unloads.<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 "chrome/browser/ui/views/ash/app_list/app_list_model_builder.h"

#include "base/i18n/case_conversion.h"
#include "base/i18n/string_search.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/views/ash/app_list/extension_app_item.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/chrome_notification_types.h"
#include "content/public/browser/notification_service.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/l10n/l10n_util_collator.h"

namespace {

// ModelItemSortData provides a string key to sort with
// l10n_util::StringComparator.
struct ModelItemSortData {
  explicit ModelItemSortData(ash::AppListItemModel* item)
      : item(item),
        key(base::i18n::ToLower(UTF8ToUTF16(item->title()))) {
  }

  // Needed by StringComparator<Element> in SortVectorWithStringKey, which uses
  // this method to get a key to sort.
  const string16& GetStringKey() const {
    return key;
  }

  ash::AppListItemModel* item;
  string16 key;
};

// Returns true if given |str| matches |query|. Currently, it returns
// if |query| is a substr of |str|.
bool MatchesQuery(const string16& query, const string16& str) {
  return query.empty() ||
      base::i18n::StringSearchIgnoringCaseAndAccents(query, str);
}

}  // namespace

AppListModelBuilder::AppListModelBuilder(Profile* profile)
    : profile_(profile),
      model_(NULL) {
  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
      content::Source<Profile>(profile_));
  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
      content::Source<Profile>(profile_));
  registrar_.Add(this, chrome::NOTIFICATION_APP_INSTALLED_TO_APPLIST,
      content::Source<Profile>(profile_));
}

AppListModelBuilder::~AppListModelBuilder() {
}

void AppListModelBuilder::SetModel(ash::AppListModel* model) {
  model_ = model;
}

void AppListModelBuilder::Build(const std::string& query) {
  DCHECK(model_ && model_->item_count() == 0);
  query_ = base::i18n::ToLower(UTF8ToUTF16(query));

  Items items;
  GetExtensionApps(query_, &items);

  SortAndPopulateModel(items);
  HighlightApp();
}

void AppListModelBuilder::SortAndPopulateModel(const Items& items) {
  // Sort items case insensitive alphabetically.
  std::vector<ModelItemSortData> sorted;
  for (Items::const_iterator it = items.begin(); it != items.end(); ++it)
    sorted.push_back(ModelItemSortData(*it));

  l10n_util::SortVectorWithStringKey(g_browser_process->GetApplicationLocale(),
                                     &sorted,
                                     false /* needs_stable_sort */);
  for (std::vector<ModelItemSortData>::const_iterator it = sorted.begin();
       it != sorted.end();
       ++it) {
    model_->AddItem(it->item);
  }
}

void AppListModelBuilder::InsertItemByTitle(ash::AppListItemModel* item) {
  DCHECK(model_);

  icu::Locale locale(g_browser_process->GetApplicationLocale().c_str());
  UErrorCode error = U_ZERO_ERROR;
  scoped_ptr<icu::Collator> collator(
      icu::Collator::createInstance(locale, error));
  if (U_FAILURE(error))
    collator.reset();

  l10n_util::StringComparator<string16> c(collator.get());
  ModelItemSortData data(item);
  for (int i = 0; i < model_->item_count(); ++i) {
    ModelItemSortData current(model_->GetItem(i));
    if (!c(current.key, data.key)) {
      model_->AddItemAt(i, item);
      return;
    }
  }
  model_->AddItem(item);
}

void AppListModelBuilder::GetExtensionApps(const string16& query,
                                           Items* items) {
  DCHECK(profile_);
  ExtensionService* service = profile_->GetExtensionService();
  if (!service)
    return;

  // Get extension apps.
  const ExtensionSet* extensions = service->extensions();
  for (ExtensionSet::const_iterator app = extensions->begin();
       app != extensions->end(); ++app) {
    if ((*app)->ShouldDisplayInLauncher() &&
        MatchesQuery(query, UTF8ToUTF16((*app)->name()))) {
      items->push_back(new ExtensionAppItem(profile_, *app));
    }
  }
}

int AppListModelBuilder::FindApp(const std::string& app_id) {
  DCHECK(model_);
  for (int i = 0; i < model_->item_count(); ++i) {
    ExtensionAppItem* extension_item =
        static_cast<ExtensionAppItem*>(model_->GetItem(i));
    if (extension_item->extension_id() == app_id)
      return i;
  }

  return -1;
}

void AppListModelBuilder::HighlightApp() {
  DCHECK(model_);
  if (highlight_app_id_.empty())
    return;

  int index = FindApp(highlight_app_id_);
  if (index == -1)
    return;

  model_->GetItem(index)->SetHighlighted(true);
  highlight_app_id_.clear();
}

void AppListModelBuilder::Observe(int type,
                                  const content::NotificationSource& source,
                                  const content::NotificationDetails& details) {
  switch (type) {
    case chrome::NOTIFICATION_EXTENSION_LOADED: {
      const Extension* extension =
          content::Details<const Extension>(details).ptr();
      if (!extension->ShouldDisplayInLauncher() ||
          !MatchesQuery(query_, UTF8ToUTF16(extension->name())))
        return;

      if (FindApp(extension->id()) != -1)
        return;

      InsertItemByTitle(new ExtensionAppItem(profile_, extension));
      HighlightApp();
      break;
    }
    case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
      const Extension* extension =
          content::Details<UnloadedExtensionInfo>(details)->extension;
      int index = FindApp(extension->id());
      if (index >= 0)
        model_->DeleteItemAt(index);
      break;
    }
    case chrome::NOTIFICATION_APP_INSTALLED_TO_APPLIST: {
      highlight_app_id_ = *content::Details<const std::string>(details).ptr();
      HighlightApp();
      break;
    }
    default:
      NOTREACHED();
  }
}
<|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 "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"

#include "base/command_line.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/avatar_menu.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_info_cache.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/ui/view_ids.h"
#include "chrome/browser/ui/views/avatar_label.h"
#include "chrome/browser/ui/views/avatar_menu_button.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/taskbar_decorator.h"
#include "chrome/browser/ui/views/new_avatar_button.h"
#include "chrome/common/chrome_switches.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/theme_provider.h"
#include "ui/gfx/image/image.h"
#include "ui/views/background.h"

BrowserNonClientFrameView::BrowserNonClientFrameView(BrowserFrame* frame,
                                                     BrowserView* browser_view)
    : frame_(frame),
      browser_view_(browser_view),
      avatar_button_(NULL),
      avatar_label_(NULL),
      new_avatar_button_(NULL) {
}

BrowserNonClientFrameView::~BrowserNonClientFrameView() {
}

void BrowserNonClientFrameView::VisibilityChanged(views::View* starting_from,
                                                  bool is_visible) {
  if (!is_visible)
    return;
  // The first time UpdateAvatarInfo() is called the window is not visible so
  // DrawTaskBarDecoration() has no effect. Therefore we need to call it again
  // once the window is visible.
  if (!browser_view_->IsRegularOrGuestSession() ||
      !profiles::IsNewProfileManagementEnabled())
    UpdateAvatarInfo();
}

void BrowserNonClientFrameView::OnThemeChanged() {
  if (avatar_label_)
    avatar_label_->UpdateLabelStyle();
}

void BrowserNonClientFrameView::UpdateAvatarInfo() {
  if (browser_view_->ShouldShowAvatar()) {
    if (!avatar_button_) {
      Profile* profile = browser_view_->browser()->profile();
      if (profile->IsManaged() && !avatar_label_) {
        avatar_label_ = new AvatarLabel(browser_view_);
        avatar_label_->set_id(VIEW_ID_AVATAR_LABEL);
        AddChildView(avatar_label_);
      }
      avatar_button_ = new AvatarMenuButton(
          browser_view_->browser(), !browser_view_->IsRegularOrGuestSession());
      avatar_button_->set_id(VIEW_ID_AVATAR_BUTTON);
      AddChildView(avatar_button_);
      frame_->GetRootView()->Layout();
    }
  } else if (avatar_button_) {
    // The avatar label can just be there if there is also an avatar button.
    if (avatar_label_) {
      RemoveChildView(avatar_label_);
      delete avatar_label_;
      avatar_label_ = NULL;
    }
    RemoveChildView(avatar_button_);
    delete avatar_button_;
    avatar_button_ = NULL;
    frame_->GetRootView()->Layout();
  }

  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
  gfx::Image avatar;
  string16 text;
  bool is_rectangle = false;
  if (browser_view_->IsGuestSession()) {
    avatar = rb.GetImageNamed(browser_view_->GetGuestIconResourceID());
  } else if (browser_view_->IsOffTheRecord()) {
    avatar = rb.GetImageNamed(browser_view_->GetOTRIconResourceID());
  } else if (avatar_button_ || AvatarMenu::ShouldShowAvatarMenu()) {
    ProfileInfoCache& cache =
        g_browser_process->profile_manager()->GetProfileInfoCache();
    Profile* profile = browser_view_->browser()->profile();
    size_t index = cache.GetIndexOfProfileWithPath(profile->GetPath());
    if (index == std::string::npos)
      return;
    text = cache.GetNameOfProfileAtIndex(index);

    AvatarMenu::GetImageForMenuButton(browser_view_->browser()->profile(),
                                      &avatar,
                                      &is_rectangle);
    // Disable the menu when we should not show the menu.
    if (avatar_button_ && !AvatarMenu::ShouldShowAvatarMenu())
      avatar_button_->SetEnabled(false);
  }
  if (avatar_button_) {
    avatar_button_->SetAvatarIcon(avatar, is_rectangle);
    if (!text.empty())
      avatar_button_->SetText(text);
  }

  // For popups and panels which don't have the avatar button, we still
  // need to draw the taskbar decoration. Even though we have an icon on the
  // window's relaunch details, we draw over it because the user may have pinned
  // the badge-less Chrome shortcut which will cause windows to ignore the
  // relaunch details.
  // TODO(calamity): ideally this should not be necessary but due to issues with
  // the default shortcut being pinned, we add the runtime badge for safety.
  // See crbug.com/313800.
  chrome::DrawTaskbarDecoration(
      frame_->GetNativeWindow(),
      AvatarMenu::ShouldShowAvatarMenu() ? &avatar : NULL);
}

void BrowserNonClientFrameView::UpdateNewStyleAvatarInfo(
    views::ButtonListener* listener,
    const NewAvatarButton::AvatarButtonStyle style) {
  DCHECK(profiles::IsNewProfileManagementEnabled());
  // This should never be called in incognito mode.
  DCHECK(browser_view_->IsRegularOrGuestSession());

  if (browser_view_->ShouldShowAvatar()) {
    if (!new_avatar_button_) {
      string16 profile_name =
          profiles::GetActiveProfileDisplayName(browser_view_->browser());
      new_avatar_button_ = new NewAvatarButton(
          listener, profile_name, style, browser_view_->browser());
      new_avatar_button_->set_id(VIEW_ID_NEW_AVATAR_BUTTON);
      AddChildView(new_avatar_button_);
      frame_->GetRootView()->Layout();
    }
  } else if (new_avatar_button_) {
    delete new_avatar_button_;
    new_avatar_button_ = NULL;
    frame_->GetRootView()->Layout();
  }
}
<commit_msg>Taskbar runtime profile badge should not use Incognito icon.<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 "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"

#include "base/command_line.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/avatar_menu.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_info_cache.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/ui/view_ids.h"
#include "chrome/browser/ui/views/avatar_label.h"
#include "chrome/browser/ui/views/avatar_menu_button.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/taskbar_decorator.h"
#include "chrome/browser/ui/views/new_avatar_button.h"
#include "chrome/common/chrome_switches.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/theme_provider.h"
#include "ui/gfx/image/image.h"
#include "ui/views/background.h"

BrowserNonClientFrameView::BrowserNonClientFrameView(BrowserFrame* frame,
                                                     BrowserView* browser_view)
    : frame_(frame),
      browser_view_(browser_view),
      avatar_button_(NULL),
      avatar_label_(NULL),
      new_avatar_button_(NULL) {
}

BrowserNonClientFrameView::~BrowserNonClientFrameView() {
}

void BrowserNonClientFrameView::VisibilityChanged(views::View* starting_from,
                                                  bool is_visible) {
  if (!is_visible)
    return;
  // The first time UpdateAvatarInfo() is called the window is not visible so
  // DrawTaskBarDecoration() has no effect. Therefore we need to call it again
  // once the window is visible.
  if (!browser_view_->IsRegularOrGuestSession() ||
      !profiles::IsNewProfileManagementEnabled())
    UpdateAvatarInfo();
}

void BrowserNonClientFrameView::OnThemeChanged() {
  if (avatar_label_)
    avatar_label_->UpdateLabelStyle();
}

void BrowserNonClientFrameView::UpdateAvatarInfo() {
  if (browser_view_->ShouldShowAvatar()) {
    if (!avatar_button_) {
      Profile* profile = browser_view_->browser()->profile();
      if (profile->IsManaged() && !avatar_label_) {
        avatar_label_ = new AvatarLabel(browser_view_);
        avatar_label_->set_id(VIEW_ID_AVATAR_LABEL);
        AddChildView(avatar_label_);
      }
      avatar_button_ = new AvatarMenuButton(
          browser_view_->browser(), !browser_view_->IsRegularOrGuestSession());
      avatar_button_->set_id(VIEW_ID_AVATAR_BUTTON);
      AddChildView(avatar_button_);
      frame_->GetRootView()->Layout();
    }
  } else if (avatar_button_) {
    // The avatar label can just be there if there is also an avatar button.
    if (avatar_label_) {
      RemoveChildView(avatar_label_);
      delete avatar_label_;
      avatar_label_ = NULL;
    }
    RemoveChildView(avatar_button_);
    delete avatar_button_;
    avatar_button_ = NULL;
    frame_->GetRootView()->Layout();
  }

  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
  gfx::Image avatar;
  gfx::Image taskbar_badge_avatar;
  string16 text;
  bool is_rectangle = false;
  if (browser_view_->IsGuestSession()) {
    avatar = rb.GetImageNamed(browser_view_->GetGuestIconResourceID());
  } else if (browser_view_->IsOffTheRecord()) {
    avatar = rb.GetImageNamed(browser_view_->GetOTRIconResourceID());
    // TODO(nkostylev): Allow this on ChromeOS once the ChromeOS test
    // environment handles profile directories correctly.
#if !defined(OS_CHROMEOS)
    bool is_badge_rectangle = false;
    // The taskbar badge should be the profile avatar, not the OTR avatar.
    AvatarMenu::GetImageForMenuButton(browser_view_->browser()->profile(),
                                      &taskbar_badge_avatar,
                                      &is_badge_rectangle);
#endif
  } else if (avatar_button_ || AvatarMenu::ShouldShowAvatarMenu()) {
    ProfileInfoCache& cache =
        g_browser_process->profile_manager()->GetProfileInfoCache();
    Profile* profile = browser_view_->browser()->profile();
    size_t index = cache.GetIndexOfProfileWithPath(profile->GetPath());
    if (index == std::string::npos)
      return;
    text = cache.GetNameOfProfileAtIndex(index);

    AvatarMenu::GetImageForMenuButton(browser_view_->browser()->profile(),
                                      &avatar,
                                      &is_rectangle);
    // Disable the menu when we should not show the menu.
    if (avatar_button_ && !AvatarMenu::ShouldShowAvatarMenu())
      avatar_button_->SetEnabled(false);
  }
  if (avatar_button_) {
    avatar_button_->SetAvatarIcon(avatar, is_rectangle);
    if (!text.empty())
      avatar_button_->SetText(text);
  }

  // For popups and panels which don't have the avatar button, we still
  // need to draw the taskbar decoration. Even though we have an icon on the
  // window's relaunch details, we draw over it because the user may have pinned
  // the badge-less Chrome shortcut which will cause windows to ignore the
  // relaunch details.
  // TODO(calamity): ideally this should not be necessary but due to issues with
  // the default shortcut being pinned, we add the runtime badge for safety.
  // See crbug.com/313800.
  chrome::DrawTaskbarDecoration(
      frame_->GetNativeWindow(),
      AvatarMenu::ShouldShowAvatarMenu()
          ? (taskbar_badge_avatar.IsEmpty() ? &avatar : &taskbar_badge_avatar)
          : NULL);
}

void BrowserNonClientFrameView::UpdateNewStyleAvatarInfo(
    views::ButtonListener* listener,
    const NewAvatarButton::AvatarButtonStyle style) {
  DCHECK(profiles::IsNewProfileManagementEnabled());
  // This should never be called in incognito mode.
  DCHECK(browser_view_->IsRegularOrGuestSession());

  if (browser_view_->ShouldShowAvatar()) {
    if (!new_avatar_button_) {
      string16 profile_name =
          profiles::GetActiveProfileDisplayName(browser_view_->browser());
      new_avatar_button_ = new NewAvatarButton(
          listener, profile_name, style, browser_view_->browser());
      new_avatar_button_->set_id(VIEW_ID_NEW_AVATAR_BUTTON);
      AddChildView(new_avatar_button_);
      frame_->GetRootView()->Layout();
    }
  } else if (new_avatar_button_) {
    delete new_avatar_button_;
    new_avatar_button_ = NULL;
    frame_->GetRootView()->Layout();
  }
}
<|endoftext|>


<commit_before>#include "gb_thread.hpp"
#include "z80.hpp"
#include "memory.hpp"
#include "rom.hpp"
#include "cart_rom_only.hpp"
#include "cart_mbc1.hpp"
#include "cart_mbc5.hpp"
#include "internal_ram.hpp"
#include "video.hpp"
#include "timer.hpp"
#include "joypad.hpp"
#include "sound.hpp"
#include "debug.hpp"
#include <cstdlib>
#include <vector>
#include <fstream>
#include <cassert>
#include <memory>
#include <chrono>

namespace
{
class stop_exception {};
}

gb::gb_thread::gb_thread() :
	_running(false)
{
}

gb::gb_thread::~gb_thread()
{
	post_stop();
	join();
}

void gb::gb_thread::start(gb::rom rom)
{
	assert(!_running);
	_running = true;
	_thread = std::thread(&gb_thread::run, this, std::move(rom));
}

void gb::gb_thread::join()
{
	if (_running)
	{
		_thread.join();
	}
}

void gb::gb_thread::post_stop()
{
	command fn([] (video &){
		throw stop_exception();
	});

	std::lock_guard<std::mutex> lock(_mutex);
	_command_queue.emplace_back(std::move(fn));
}

std::future<gb::video::raw_image> gb::gb_thread::post_get_image()
{
	auto promise = std::make_shared<std::promise<video::raw_image>>();
	auto future = promise->get_future();
	command fn([promise] (video &video) {
		promise->set_value(video.image());
	});

	std::lock_guard<std::mutex> lock(_mutex);
	_command_queue.emplace_back(std::move(fn));
	return future;
}

void gb::gb_thread::run(gb::rom rom)
{
	using namespace std::chrono;

	using clock = steady_clock;
	static_assert(clock::is_monotonic, "clock not monotonic");
	static_assert(clock::is_steady, "clock not steady");
	static_assert(std::ratio_less_equal<clock::period, std::ratio_multiply<std::ratio<100>, std::nano>>::value,
		"clock too inaccurate (period > 100ns)");

	// Make Cartridge
	std::unique_ptr<gb::memory_mapping> cartridge;
	switch (rom.cartridge())
	{
	case 0x00:
		cartridge = std::make_unique<gb::cart_rom_only>(std::move(rom));
		break;
	case 0x01:
		cartridge = std::make_unique<gb::cart_mbc1>(std::move(rom));
		break;
	case 0x19:
		cartridge = std::make_unique<gb::cart_mbc5>(std::move(rom));
		break;
	default:
		return;
	}

	// Misc. Hardware
	gb::internal_ram internal_ram;
	gb::video video;
	gb::timer timer;
	gb::joypad joypad;
	gb::sound sound;

	// Make Memory
	gb::memory memory;
	memory.add_mapping(cartridge.get());
	memory.add_mapping(&internal_ram);
	memory.add_mapping(&video);
	memory.add_mapping(&joypad);
	memory.add_mapping(&timer);
	memory.add_mapping(&sound);
	memory.write8(0xff05, 0x00);
	memory.write8(0xff06, 0x00);
	memory.write8(0xff07, 0x00);
	memory.write8(0xff10, 0x80);
	memory.write8(0xff11, 0xbf);
	memory.write8(0xff12, 0xf3);
	memory.write8(0xff14, 0xbf);
	memory.write8(0xff16, 0x3f);
	memory.write8(0xff17, 0x00);
	memory.write8(0xff19, 0xbf);
	memory.write8(0xff1a, 0x7f);
	memory.write8(0xff1b, 0xff);
	memory.write8(0xff1c, 0x9f);
	memory.write8(0xff1e, 0xbf);
	memory.write8(0xff20, 0xff);
	memory.write8(0xff21, 0x00);
	memory.write8(0xff22, 0x00);
	memory.write8(0xff23, 0xbf);
	memory.write8(0xff24, 0x77);
	memory.write8(0xff25, 0xf3);
	memory.write8(0xff26, 0xf1);
	memory.write8(0xff40, 0x91);
	memory.write8(0xff42, 0x00);
	memory.write8(0xff43, 0x00);
	memory.write8(0xff45, 0x00);
	memory.write8(0xff47, 0xfc);
	memory.write8(0xff48, 0xff);
	memory.write8(0xff49, 0xff);
	memory.write8(0xff4a, 0x00);
	memory.write8(0xff4b, 0x00);
	memory.write8(0xffff, 0x00);

	// Register file
	gb::register_file registers;
	registers.write8<register8::a>(0x11);
	registers.write8<register8::f>(0xb0);
	registers.write16<register16::bc>(0x0013);
	registers.write16<register16::de>(0x00d8);
	registers.write16<register16::hl>(0x014d);
	registers.write16<register16::sp>(0xfffe);
	registers.write16<register16::pc>(0x0100);

	// Make Cpu
	gb::z80_cpu cpu(std::move(memory), std::move(registers));

	// Let's go :)
	std::vector<command> current_commands;
	nanoseconds real_time(0);
	nanoseconds gb_time(0);
	auto last_real_time = clock::now();

	try
	{
		while (true)
		{
			{
				std::lock_guard<std::mutex> lock(_mutex);
				if (!_command_queue.empty())
				{
					std::swap(current_commands, _command_queue);
				}
			}

			if (!current_commands.empty())
			{
				for (const auto &command : current_commands)
				{
					command(video);
				}
				current_commands.clear();
			}

			auto ns = cpu.tick();
			video.tick(cpu, ns);
			timer.tick(cpu, ns);

			// Time bookkeeping
			gb_time += ns;
			auto current_time = clock::now();
			real_time += (current_time - last_real_time);
			last_real_time = current_time;

			auto min_time = std::min(gb_time, real_time);
			gb_time -= min_time;
			real_time -= min_time;

			if (gb_time > nanoseconds(0))
			{
				// simulation is too fast
				if (gb_time > milliseconds(15))
				{
					std::this_thread::sleep_for(gb_time);
				}
			}
			else if (real_time > milliseconds(100))
			{
				// simulation is too slow (reset counter)
				debug("simulation is too slow!");
				real_time = nanoseconds(0);
			}
		}
	}
	catch (const stop_exception &)
	{
		// this might be ugly but it works well :)
	}
}
<commit_msg>Performance counters<commit_after>#include "gb_thread.hpp"
#include "z80.hpp"
#include "memory.hpp"
#include "rom.hpp"
#include "cart_rom_only.hpp"
#include "cart_mbc1.hpp"
#include "cart_mbc5.hpp"
#include "internal_ram.hpp"
#include "video.hpp"
#include "timer.hpp"
#include "joypad.hpp"
#include "sound.hpp"
#include "debug.hpp"
#include <cstdlib>
#include <vector>
#include <fstream>
#include <cassert>
#include <memory>
#include <chrono>

namespace
{
class stop_exception {};
}

gb::gb_thread::gb_thread() :
	_running(false)
{
}

gb::gb_thread::~gb_thread()
{
	post_stop();
	join();
}

void gb::gb_thread::start(gb::rom rom)
{
	assert(!_running);
	_running = true;
	_thread = std::thread(&gb_thread::run, this, std::move(rom));
}

void gb::gb_thread::join()
{
	if (_running)
	{
		_thread.join();
	}
}

void gb::gb_thread::post_stop()
{
	command fn([] (video &){
		throw stop_exception();
	});

	std::lock_guard<std::mutex> lock(_mutex);
	_command_queue.emplace_back(std::move(fn));
}

std::future<gb::video::raw_image> gb::gb_thread::post_get_image()
{
	// TODO use capture by move (Visual Studio 2015/C++14)
	auto promise = std::make_shared<std::promise<video::raw_image>>();
	auto future = promise->get_future();
	command fn([promise] (video &video) {
		promise->set_value(video.image());
	});

	std::lock_guard<std::mutex> lock(_mutex);
	_command_queue.emplace_back(std::move(fn));
	return future;
}

void gb::gb_thread::run(gb::rom rom)
{
	using namespace std::chrono;

	using clock = steady_clock;
	static_assert(clock::is_monotonic, "clock not monotonic");
	static_assert(clock::is_steady, "clock not steady");
	static_assert(std::ratio_less_equal<clock::period, std::ratio_multiply<std::ratio<100>, std::nano>>::value,
		"clock too inaccurate (period > 100ns)");

	// Make Cartridge
	std::unique_ptr<gb::memory_mapping> cartridge;
	switch (rom.cartridge())
	{
	case 0x00:
		cartridge = std::make_unique<gb::cart_rom_only>(std::move(rom));
		break;
	case 0x01:
		cartridge = std::make_unique<gb::cart_mbc1>(std::move(rom));
		break;
	case 0x19:
		cartridge = std::make_unique<gb::cart_mbc5>(std::move(rom));
		break;
	default:
		return;
	}

	// Misc. Hardware
	gb::internal_ram internal_ram;
	gb::video video;
	gb::timer timer;
	gb::joypad joypad;
	gb::sound sound;

	// Make Memory
	gb::memory memory;
	memory.add_mapping(cartridge.get());
	memory.add_mapping(&internal_ram);
	memory.add_mapping(&video);
	memory.add_mapping(&joypad);
	memory.add_mapping(&timer);
	memory.add_mapping(&sound);
	memory.write8(0xff05, 0x00);
	memory.write8(0xff06, 0x00);
	memory.write8(0xff07, 0x00);
	memory.write8(0xff10, 0x80);
	memory.write8(0xff11, 0xbf);
	memory.write8(0xff12, 0xf3);
	memory.write8(0xff14, 0xbf);
	memory.write8(0xff16, 0x3f);
	memory.write8(0xff17, 0x00);
	memory.write8(0xff19, 0xbf);
	memory.write8(0xff1a, 0x7f);
	memory.write8(0xff1b, 0xff);
	memory.write8(0xff1c, 0x9f);
	memory.write8(0xff1e, 0xbf);
	memory.write8(0xff20, 0xff);
	memory.write8(0xff21, 0x00);
	memory.write8(0xff22, 0x00);
	memory.write8(0xff23, 0xbf);
	memory.write8(0xff24, 0x77);
	memory.write8(0xff25, 0xf3);
	memory.write8(0xff26, 0xf1);
	memory.write8(0xff40, 0x91);
	memory.write8(0xff42, 0x00);
	memory.write8(0xff43, 0x00);
	memory.write8(0xff45, 0x00);
	memory.write8(0xff47, 0xfc);
	memory.write8(0xff48, 0xff);
	memory.write8(0xff49, 0xff);
	memory.write8(0xff4a, 0x00);
	memory.write8(0xff4b, 0x00);
	memory.write8(0xffff, 0x00);

	// Register file
	gb::register_file registers;
	registers.write8<register8::a>(0x11);
	registers.write8<register8::f>(0xb0);
	registers.write16<register16::bc>(0x0013);
	registers.write16<register16::de>(0x00d8);
	registers.write16<register16::hl>(0x014d);
	registers.write16<register16::sp>(0xfffe);
	registers.write16<register16::pc>(0x0100);

	// Make Cpu
	gb::z80_cpu cpu(std::move(memory), std::move(registers));

	// Let's go :)
	std::vector<command> current_commands;
	nanoseconds real_time(0);
	nanoseconds gb_time(0);
	nanoseconds performance_gb_time(0);
	nanoseconds performance_sleep_time(0);
	auto last_real_time = clock::now();
	auto performance_start = clock::now();

	try
	{
		while (true)
		{
			// Command stream
			{
				std::lock_guard<std::mutex> lock(_mutex);
				if (!_command_queue.empty())
				{
					std::swap(current_commands, _command_queue);
				}
			}

			if (!current_commands.empty())
			{
				for (const auto &command : current_commands)
				{
					command(video);
				}
				current_commands.clear();
			}

			// Simulation itself
			const auto ns = cpu.tick();
			video.tick(cpu, ns);
			timer.tick(cpu, ns);

			// Time bookkeeping
			const auto current_time = clock::now();
			gb_time += ns;
			real_time += (current_time - last_real_time);
			last_real_time = current_time;

			const auto min_time = std::min(gb_time, real_time);
			gb_time -= min_time;
			real_time -= min_time;

			if (gb_time > nanoseconds(0))
			{
				// simulation is too fast
				if (gb_time > milliseconds(15))
				{
					const auto sleep_start = clock::now();
					std::this_thread::sleep_for(gb_time);
					performance_sleep_time += (clock::now() - sleep_start);
				}
				else if (gb_time > milliseconds(1))
				{
					const auto sleep_start = clock::now();
					std::this_thread::yield();
					performance_sleep_time += (clock::now() - sleep_start);
				}
			}
			else if (real_time > milliseconds(100))
			{
				// simulation is too slow (reset counter)
				real_time = nanoseconds(0);
			}

			performance_gb_time += ns;
			const auto performance_now = clock::now();
			const auto performance_real_time = performance_now - performance_start;
			if (performance_real_time > seconds(10))
			{
				const auto accuracy =
					duration_cast<milliseconds>(performance_gb_time - performance_real_time).count();
				const double speed =
					static_cast<double>(duration_cast<nanoseconds>(performance_gb_time).count()) /
					static_cast<double>(duration_cast<nanoseconds>(performance_real_time - performance_sleep_time).count()) *
					100.0;
				debug("PERF: simulation accuracy is at ", accuracy, " ms");
				debug("PERF: simulation speed is at ", speed, " %");
				if (speed < 100.0) {
					debug("PERF WARNING: simulation performance is too low!");
				}
				performance_sleep_time = performance_gb_time = nanoseconds(0);
				performance_start = performance_now;
			}
		}
	}
	catch (const stop_exception &)
	{
		// this might be ugly but it works well :)
	}
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   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 .
 */

#ifndef INCLUDED_XMLSCRIPT_SOURCE_INC_MISC_HXX
#define INCLUDED_XMLSCRIPT_SOURCE_INC_MISC_HXX

#include <com/sun/star/uno/Any.hxx>

namespace xmlscript
{

template< typename T >
inline void extract_throw( T * p, ::com::sun::star::uno::Any const & a )
{
    if (! (a >>= *p))
    {
        throw ::com::sun::star::uno::RuntimeException(
            "expected " + ::getCppuType( p ).getTypeName(),
            ::com::sun::star::uno::Reference<
            ::com::sun::star::uno::XInterface>() );
    }
}

template< typename T >
inline T extract_throw( ::com::sun::star::uno::Any const & a )
{
    T v = T();
    extract_throw<T>( &v, a );
    return v;
}

}

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>Replace remaining getCppuType et al with cppu::UnoType<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   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 .
 */

#ifndef INCLUDED_XMLSCRIPT_SOURCE_INC_MISC_HXX
#define INCLUDED_XMLSCRIPT_SOURCE_INC_MISC_HXX

#include <com/sun/star/uno/Any.hxx>

namespace xmlscript
{

template< typename T >
inline void extract_throw( T * p, ::com::sun::star::uno::Any const & a )
{
    if (! (a >>= *p))
    {
        throw ::com::sun::star::uno::RuntimeException(
            "expected " + cppu::UnoType<T>::get().getTypeName(),
            ::com::sun::star::uno::Reference<
            ::com::sun::star::uno::XInterface>() );
    }
}

template< typename T >
inline T extract_throw( ::com::sun::star::uno::Any const & a )
{
    T v = T();
    extract_throw<T>( &v, a );
    return v;
}

}

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>