summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xchrome/browser/DEPS1
-rw-r--r--chrome/browser/extensions/extension_browsertests_misc.cc24
-rw-r--r--chrome/browser/extensions/extension_function.h11
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.cc2
-rw-r--r--chrome/browser/extensions/extension_tabs_module.cc46
-rw-r--r--chrome/browser/extensions/extension_tabs_module.h12
-rwxr-xr-xchrome/browser/extensions/extension_tabs_module_constants.cc2
-rwxr-xr-xchrome/browser/extensions/extension_tabs_module_constants.h1
-rw-r--r--chrome/browser/renderer_host/render_view_host.cc23
-rw-r--r--chrome/browser/renderer_host/render_view_host.h7
-rw-r--r--chrome/browser/tab_contents/tab_contents.cc4
-rw-r--r--chrome/browser/tab_contents/tab_contents.h3
-rw-r--r--chrome/common/notification_type.h4
-rw-r--r--chrome/common/render_messages_internal.h8
-rw-r--r--chrome/renderer/extensions/extension_api_client_unittest.cc18
-rw-r--r--chrome/renderer/render_view.cc27
-rw-r--r--chrome/renderer/render_view.h4
-rw-r--r--chrome/renderer/renderer_resources.grd2
-rw-r--r--chrome/renderer/resources/extension_process_bindings.js11
-rw-r--r--chrome/test/data/extensions/good/Extensions/behllobkkfkfnphdnhnkndlbkcpglgmj/1.0.0.0/french_sentence.html12
-rw-r--r--chrome/test/data/extensions/good/Extensions/behllobkkfkfnphdnhnkndlbkcpglgmj/1.0.0.0/toolstrip1.html10
-rw-r--r--chrome/test/data/extensions/samples/cld/manifest.json6
-rw-r--r--chrome/test/data/extensions/samples/cld/toolstrip.html36
23 files changed, 265 insertions, 9 deletions
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index a18a7a56..d5be2b8 100755
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -17,6 +17,7 @@ include_rules = [
"+media/audio", # Chrome's lightweight audio library.
"+third_party/sqlite",
"+third_party/libevent", # For the remote V8 debugging server
+ "+third_party/cld",
"+v8/include", # Browser uses V8 to get the version and run the debugger.
# FIXME: this should probably not be here, we need to find a better
diff --git a/chrome/browser/extensions/extension_browsertests_misc.cc b/chrome/browser/extensions/extension_browsertests_misc.cc
index f17e5d5..4b8fb8f 100644
--- a/chrome/browser/extensions/extension_browsertests_misc.cc
+++ b/chrome/browser/extensions/extension_browsertests_misc.cc
@@ -43,10 +43,10 @@ static ExtensionHost* FindHostWithPath(ExtensionProcessManager* manager,
// Tests that toolstrips initializes properly and can run basic extension js.
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, Toolstrip) {
- ASSERT_TRUE(LoadExtension(
- test_data_dir_.AppendASCII("good").AppendASCII("Extensions")
- .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
- .AppendASCII("1.0.0.0")));
+ FilePath extension_test_data_dir = test_data_dir_.AppendASCII("good").
+ AppendASCII("Extensions").AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj").
+ AppendASCII("1.0.0.0");
+ ASSERT_TRUE(LoadExtension(extension_test_data_dir));
// At this point, there should be two ExtensionHosts loaded because this
// extension has two toolstrips. Find the one that is hosting toolstrip1.html.
@@ -59,6 +59,22 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, Toolstrip) {
ui_test_utils::ExecuteJavaScriptAndExtractBool(
host->render_view_host(), L"", L"testTabsAPI()", &result);
EXPECT_TRUE(result);
+
+#if defined(OS_WIN)
+ // Test for compact language detection API. First navigate to a (static) html
+ // file with a French sentence. Then, run the test API in toolstrip1.html to
+ // actually call the language detection API through the existing extension,
+ // and verify that the language returned is indeed French.
+ FilePath language_url = extension_test_data_dir.AppendASCII(
+ "french_sentence.html");
+ ui_test_utils::NavigateToURL(
+ browser(),
+ GURL(language_url.ToWStringHack()));
+
+ ui_test_utils::ExecuteJavaScriptAndExtractBool(
+ host->render_view_host(), L"", L"testTabsLanguageAPI()", &result);
+ EXPECT_TRUE(result);
+#endif
}
// Tests that the ExtensionShelf initializes properly, notices that
diff --git a/chrome/browser/extensions/extension_function.h b/chrome/browser/extensions/extension_function.h
index 7798a19..ed2f9d0 100644
--- a/chrome/browser/extensions/extension_function.h
+++ b/chrome/browser/extensions/extension_function.h
@@ -93,7 +93,14 @@ class AsyncExtensionFunction : public ExtensionFunction {
virtual void SetArgs(const std::string& args);
virtual const std::string GetResult();
virtual const std::string GetError() { return error_; }
- virtual void Run() = 0;
+ virtual void Run() {
+ if (!RunImpl())
+ SendResponse(false);
+ }
+
+ // Derived classes should implement this method to do their work and return
+ // success/failure.
+ virtual bool RunImpl() = 0;
protected:
void SendResponse(bool success);
@@ -107,7 +114,7 @@ class AsyncExtensionFunction : public ExtensionFunction {
Value* args_;
// The result of the API. This should be populated by the derived class before
- // Run() returns.
+ // SendResponse() is called.
scoped_ptr<Value> result_;
// Any detailed error from the API. This should be populated by the derived
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index 70cb59e..8238595 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -98,6 +98,8 @@ void FactoryRegistry::ResetFunctions() {
&NewExtensionFunction<MoveTabFunction>;
factories_[tabs::kRemoveTabFunction] =
&NewExtensionFunction<RemoveTabFunction>;
+ factories_[tabs::kGetTabLanguageFunction] =
+ &NewExtensionFunction<GetTabLanguageFunction>;
// Page Actions.
factories_[page_actions::kEnablePageActionFunction] =
diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc
index b92677d..57248d7 100644
--- a/chrome/browser/extensions/extension_tabs_module.cc
+++ b/chrome/browser/extensions/extension_tabs_module.cc
@@ -615,6 +615,52 @@ bool RemoveTabFunction::RunImpl() {
return true;
}
+bool GetTabLanguageFunction::RunImpl() {
+ int tab_id = 0;
+ Browser* browser = NULL;
+ TabContents* contents = NULL;
+
+ // If |tab_id| is specified, look for it. Otherwise default to selected tab
+ // in the current window.
+ if (!args_->IsType(Value::TYPE_NULL)) {
+ EXTENSION_FUNCTION_VALIDATE(args_->GetAsInteger(&tab_id));
+ if (!GetTabById(tab_id, profile(), &browser, NULL, &contents, NULL,
+ &error_)) {
+ return false;
+ }
+ if (!browser || !contents)
+ return false;
+ } else {
+ browser = dispatcher()->GetBrowser();
+ if (!browser)
+ return false;
+ contents = browser->tabstrip_model()->GetSelectedTabContents();
+ if (!contents)
+ return false;
+ }
+
+ // Figure out what language |contents| contains. This sends an async call via
+ // the browser to the renderer to determine the language of the tab the
+ // renderer has. The renderer sends back the language of the tab after the
+ // tab loads (it may be delayed) to the browser, which in turn notifies this
+ // object that the language has been received.
+ contents->GetPageLanguage();
+ registrar_.Add(this, NotificationType::TAB_LANGUAGE_DETERMINED,
+ NotificationService::AllSources());
+ AddRef(); // balanced in Observe()
+ return true;
+}
+
+void GetTabLanguageFunction::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(type == NotificationType::TAB_LANGUAGE_DETERMINED);
+ std::string language(*Details<std::string>(details).ptr());
+ result_.reset(Value::CreateStringValue(language.c_str()));
+ SendResponse(true);
+ Release(); // balanced in Run()
+}
+
// static helpers
// if |populate| is true, each window gets a list property |tabs| which contains
diff --git a/chrome/browser/extensions/extension_tabs_module.h b/chrome/browser/extensions/extension_tabs_module.h
index cb8b3d3..1b7c307 100644
--- a/chrome/browser/extensions/extension_tabs_module.h
+++ b/chrome/browser/extensions/extension_tabs_module.h
@@ -8,6 +8,8 @@
#include <string>
#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_registrar.h"
class Browser;
class DictionaryValue;
@@ -86,5 +88,15 @@ class MoveTabFunction : public SyncExtensionFunction {
class RemoveTabFunction : public SyncExtensionFunction {
virtual bool RunImpl();
};
+class GetTabLanguageFunction : public AsyncExtensionFunction,
+ public NotificationObserver {
+ virtual bool RunImpl();
+
+ private:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+ NotificationRegistrar registrar_;
+};
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_TABS_MODULE_H__
diff --git a/chrome/browser/extensions/extension_tabs_module_constants.cc b/chrome/browser/extensions/extension_tabs_module_constants.cc
index 049f36a..69676e7 100755
--- a/chrome/browser/extensions/extension_tabs_module_constants.cc
+++ b/chrome/browser/extensions/extension_tabs_module_constants.cc
@@ -56,6 +56,6 @@ const char kCreateTabFunction[] = "CreateTab";
const char kUpdateTabFunction[] = "UpdateTab";
const char kMoveTabFunction[] = "MoveTab";
const char kRemoveTabFunction[] = "RemoveTab";
-
+const char kGetTabLanguageFunction[] = "GetTabLanguage";
} // namespace extension_tabs_module_constants
diff --git a/chrome/browser/extensions/extension_tabs_module_constants.h b/chrome/browser/extensions/extension_tabs_module_constants.h
index 10abcf7..4df84c8 100755
--- a/chrome/browser/extensions/extension_tabs_module_constants.h
+++ b/chrome/browser/extensions/extension_tabs_module_constants.h
@@ -64,6 +64,7 @@ extern const char kCreateTabFunction[];
extern const char kUpdateTabFunction[];
extern const char kMoveTabFunction[];
extern const char kRemoveTabFunction[];
+extern const char kGetTabLanguageFunction[];
}; // namespace extension_tabs_module_constants
diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc
index 8e8f161..b41c04c 100644
--- a/chrome/browser/renderer_host/render_view_host.cc
+++ b/chrome/browser/renderer_host/render_view_host.cc
@@ -41,6 +41,8 @@
#if defined(OS_WIN)
// TODO(port): accessibility not yet implemented. See http://crbug.com/8288.
#include "chrome/browser/browser_accessibility_manager.h"
+// TODO(port): The compact language detection library works only for Windows.
+#include "third_party/cld/bar/toolbar/cld/i18n/encodings/compact_lang_det/win/cld_unicodetext.h"
#endif
using base::TimeDelta;
@@ -410,6 +412,10 @@ void RenderViewHost::StopFinding(bool clear_selection) {
Send(new ViewMsg_StopFinding(routing_id(), clear_selection));
}
+void RenderViewHost::GetPageLanguage() {
+ Send(new ViewMsg_DeterminePageText(routing_id()));
+}
+
void RenderViewHost::Zoom(PageZoom::Function function) {
Send(new ViewMsg_Zoom(routing_id(), function));
}
@@ -726,6 +732,8 @@ void RenderViewHost::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER(ViewHostMsg_DidFailProvisionalLoadWithError,
OnMsgDidFailProvisionalLoadWithError)
IPC_MESSAGE_HANDLER(ViewHostMsg_Find_Reply, OnMsgFindReply)
+ IPC_MESSAGE_HANDLER(ViewMsg_DeterminePageText_Reply,
+ OnDeterminePageTextReply)
IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFavIconURL, OnMsgUpdateFavIconURL)
IPC_MESSAGE_HANDLER(ViewHostMsg_DidDownloadFavIcon, OnMsgDidDownloadFavIcon)
IPC_MESSAGE_HANDLER(ViewHostMsg_ContextMenu, OnMsgContextMenu)
@@ -1058,6 +1066,21 @@ void RenderViewHost::OnMsgFindReply(int request_id,
Send(new ViewMsg_FindReplyACK(routing_id()));
}
+void RenderViewHost::OnDeterminePageTextReply(
+ const std::wstring& page_text) {
+#if defined(OS_WIN) // Only for windows.
+ int num_languages = 0;
+ bool is_reliable = false;
+ const char* language_char = LanguageName(DetectLanguageOfUnicodeText(
+ page_text.c_str(), true, &is_reliable, &num_languages, NULL));
+ std::string language(language_char);
+ NotificationService::current()->Notify(
+ NotificationType::TAB_LANGUAGE_DETERMINED,
+ Source<RenderViewHost>(this),
+ Details<std::string>(&language));
+#endif
+}
+
void RenderViewHost::OnMsgUpdateFavIconURL(int32 page_id,
const GURL& icon_url) {
RenderViewHostDelegate::FavIcon* favicon_delegate =
diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h
index de4c70c..a43c5a2 100644
--- a/chrome/browser/renderer_host/render_view_host.h
+++ b/chrome/browser/renderer_host/render_view_host.h
@@ -206,6 +206,12 @@ class RenderViewHost : public RenderWidgetHost,
// clear the selection on the focused frame.
void StopFinding(bool clear_selection);
+ // Get the most probable language of the text content in the tab. This sends
+ // a message to the render view to get the content of the page as text. The
+ // caller gets the language via the NotificationService by registering to the
+ // NotificationType TAB_LANGUAGE_DETERMINED.
+ void GetPageLanguage();
+
// Change the zoom level of a page.
void Zoom(PageZoom::Function function);
@@ -460,6 +466,7 @@ class RenderViewHost : public RenderWidgetHost,
const gfx::Rect& selection_rect,
int active_match_ordinal,
bool final_update);
+ void OnDeterminePageTextReply(const std::wstring& tab_text);
void OnMsgUpdateFavIconURL(int32 page_id, const GURL& icon_url);
void OnMsgDidDownloadFavIcon(int id,
const GURL& image_url,
diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc
index 001be58..9832fa4 100644
--- a/chrome/browser/tab_contents/tab_contents.cc
+++ b/chrome/browser/tab_contents/tab_contents.cc
@@ -976,6 +976,10 @@ void TabContents::StopFinding(bool clear_selection) {
render_view_host()->StopFinding(clear_selection);
}
+void TabContents::GetPageLanguage() {
+ render_view_host()->GetPageLanguage();
+}
+
void TabContents::OnJavaScriptMessageBoxClosed(IPC::Message* reply_msg,
bool success,
const std::wstring& prompt) {
diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h
index 99e99a1..e974f8e 100644
--- a/chrome/browser/tab_contents/tab_contents.h
+++ b/chrome/browser/tab_contents/tab_contents.h
@@ -493,6 +493,9 @@ class TabContents : public PageNavigator,
return last_search_result_;
}
+ // Get the most probable language of the text content in the tab.
+ void GetPageLanguage();
+
// Misc state & callbacks ----------------------------------------------------
// Set whether the contents should block javascript message boxes or not.
diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h
index d2c8fca..93cbbaf 100644
--- a/chrome/common/notification_type.h
+++ b/chrome/common/notification_type.h
@@ -204,6 +204,10 @@ class NotificationType {
// is the InfoBubble.
INFO_BUBBLE_CREATED,
+ // Sent after a call to RenderViewHost::DeterminePageLanguage. The details
+ // are Details<std::string> and the source is Source<RenderViewHost>.
+ TAB_LANGUAGE_DETERMINED,
+
// The user has changed the browser theme.
BROWSER_THEME_CHANGED,
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index 5205bf6..ee3d154 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -191,6 +191,14 @@ IPC_BEGIN_MESSAGES(View)
string16 /* search_text */,
WebKit::WebFindOptions)
+ // Send from the browser to the rendered to get the text content of the page.
+ IPC_MESSAGE_ROUTED0(ViewMsg_DeterminePageText)
+
+ // Send from the renderer to the browser to return the text content of the
+ // page.
+ IPC_MESSAGE_ROUTED1(ViewMsg_DeterminePageText_Reply,
+ std::wstring /* the language */)
+
// Sent when the headers are available for a resource request.
IPC_MESSAGE_ROUTED2(ViewMsg_Resource_ReceivedResponse,
int /* request_id */,
diff --git a/chrome/renderer/extensions/extension_api_client_unittest.cc b/chrome/renderer/extensions/extension_api_client_unittest.cc
index 663a892..0cb2876 100644
--- a/chrome/renderer/extensions/extension_api_client_unittest.cc
+++ b/chrome/renderer/extensions/extension_api_client_unittest.cc
@@ -275,6 +275,24 @@ TEST_F(ExtensionAPIClientTest, GetTab) {
"GetTab", "2");
}
+#if defined(OS_WIN)
+TEST_F(ExtensionAPIClientTest, GetTabLanguage) {
+ ExpectJsFail("chrome.tabs.getLanguage(32, function(){}, 20);",
+ "Uncaught Error: Too many arguments.");
+
+ ExpectJsFail("chrome.tabs.getLanguage('abc', function(){});",
+ "Uncaught Error: Invalid value for argument 0. "
+ "Expected 'integer' but got 'string'.");
+
+ ExpectJsFail("chrome.tabs.getLanguage(1, 1);",
+ "Uncaught Error: Invalid value for argument 1. "
+ "Expected 'function' but got 'integer'.");
+
+ ExpectJsPass("chrome.tabs.getLanguage(null, function(){})",
+ "GetTabLanguage", "null");
+}
+#endif
+
TEST_F(ExtensionAPIClientTest, GetSelectedTab) {
ExpectJsFail("chrome.tabs.getSelected(32, function(){}, 20);",
"Uncaught Error: Too many arguments.");
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index 5f72843..f08ad79e 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -192,7 +192,8 @@ RenderView::RenderView(RenderThreadBase* render_thread)
popup_notification_visible_(false),
delay_seconds_for_form_state_sync_(kDefaultDelaySecondsForFormStateSync),
preferred_width_(0),
- send_preferred_width_changes_(false) {
+ send_preferred_width_changes_(false),
+ determine_page_text_after_loading_stops_(false) {
}
RenderView::~RenderView() {
@@ -355,6 +356,7 @@ void RenderView::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ViewMsg_CopyImageAt, OnCopyImageAt)
IPC_MESSAGE_HANDLER(ViewMsg_ExecuteEditCommand, OnExecuteEditCommand)
IPC_MESSAGE_HANDLER(ViewMsg_Find, OnFind)
+ IPC_MESSAGE_HANDLER(ViewMsg_DeterminePageText, OnDeterminePageText)
IPC_MESSAGE_HANDLER(ViewMsg_Zoom, OnZoom)
IPC_MESSAGE_HANDLER(ViewMsg_InsertText, OnInsertText)
IPC_MESSAGE_HANDLER(ViewMsg_SetPageEncoding, OnSetPageEncoding)
@@ -497,6 +499,12 @@ void RenderView::CapturePageInfo(int load_id, bool preliminary_capture) {
Send(new ViewHostMsg_PageContents(url, load_id, contents));
}
+ // Send over text content of this page to the browser.
+ if (determine_page_text_after_loading_stops_) {
+ determine_page_text_after_loading_stops_ = false;
+ Send(new ViewMsg_DeterminePageText_Reply(routing_id_, contents));
+ }
+
// thumbnail
SendThumbnail();
}
@@ -2199,6 +2207,23 @@ void RenderView::OnFind(int request_id,
}
}
+void RenderView::OnDeterminePageText() {
+ if (!is_loading_) {
+ if (!webview())
+ return;
+ WebFrame* main_frame = webview()->GetMainFrame();
+ std::wstring contents;
+ CaptureText(main_frame, &contents);
+ Send(new ViewMsg_DeterminePageText_Reply(routing_id_, contents));
+ determine_page_text_after_loading_stops_ = false;
+ return;
+ }
+
+ // We set |determine_page_text_after_loading_stops_| true here so that,
+ // after page has been loaded completely, the text in the page is captured.
+ determine_page_text_after_loading_stops_ = true;
+}
+
void RenderView::ReportFindInPageMatchCount(int count, int request_id,
bool final_update) {
// If we have a message that has been queued up, then we should just replace
diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h
index bc44ac9..24621a4 100644
--- a/chrome/renderer/render_view.h
+++ b/chrome/renderer/render_view.h
@@ -478,6 +478,7 @@ class RenderView : public RenderWidget,
void OnSetupDevToolsClient();
void OnCancelDownload(int32 download_id);
void OnFind(int request_id, const string16&, const WebKit::WebFindOptions&);
+ void OnDeterminePageText();
void OnZoom(int function);
void OnInsertText(const string16& text);
void OnSetPageEncoding(const std::wstring& encoding_name);
@@ -778,6 +779,9 @@ class RenderView : public RenderWidget,
// The text selection the last time DidChangeSelection got called.
std::string last_selection_;
+ // Set to true if request for capturing page text has been made.
+ bool determine_page_text_after_loading_stops_;
+
// Holds state pertaining to a navigation that we initiated. This is held by
// the WebDataSource::ExtraData attribute. We use pending_navigation_state_
// as a temporary holder for the state until the WebDataSource corresponding
diff --git a/chrome/renderer/renderer_resources.grd b/chrome/renderer/renderer_resources.grd
index ed66407..8acec84 100644
--- a/chrome/renderer/renderer_resources.grd
+++ b/chrome/renderer/renderer_resources.grd
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This comment is only here because changes to resources are not picked up
-without changes to the corresponding grd file. mp12 -->
+without changes to the corresponding grd file. mp13 -->
<grit latest_public_release="0" current_release="1">
<outputs>
<output filename="grit/renderer_resources.h" type="rc_header">
diff --git a/chrome/renderer/resources/extension_process_bindings.js b/chrome/renderer/resources/extension_process_bindings.js
index f3893fb..51756d0 100644
--- a/chrome/renderer/resources/extension_process_bindings.js
+++ b/chrome/renderer/resources/extension_process_bindings.js
@@ -24,6 +24,7 @@ var chrome = chrome || {};
native function UpdateTab();
native function MoveTab();
native function RemoveTab();
+ native function GetTabLanguage();
native function EnablePageAction();
native function DisablePageAction();
native function GetBookmarks();
@@ -313,6 +314,16 @@ var chrome = chrome || {};
chrome.types.optFun
];
+ chrome.tabs.getLanguage = function(tabId, callback) {
+ validate(arguments, arguments.callee.params);
+ sendRequest(GetTabLanguage, tabId, callback);
+ };
+
+ chrome.tabs.getLanguage.params = [
+ chrome.types.optPInt,
+ chrome.types.optFun
+ ];
+
// Sends ({Tab}).
// Will *NOT* be followed by tab-attached - it is implied.
// *MAY* be followed by tab-selection-changed.
diff --git a/chrome/test/data/extensions/good/Extensions/behllobkkfkfnphdnhnkndlbkcpglgmj/1.0.0.0/french_sentence.html b/chrome/test/data/extensions/good/Extensions/behllobkkfkfnphdnhnkndlbkcpglgmj/1.0.0.0/french_sentence.html
new file mode 100644
index 0000000..3d3c2e8
--- /dev/null
+++ b/chrome/test/data/extensions/good/Extensions/behllobkkfkfnphdnhnkndlbkcpglgmj/1.0.0.0/french_sentence.html
@@ -0,0 +1,12 @@
+<!--
+Copyright (c) 2009 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.
+-->
+<html>
+<body>
+<p>
+Ceci est une phrase complète est en français, rédigé en anglais puis traduits
+</p>
+</body>
+</html>
diff --git a/chrome/test/data/extensions/good/Extensions/behllobkkfkfnphdnhnkndlbkcpglgmj/1.0.0.0/toolstrip1.html b/chrome/test/data/extensions/good/Extensions/behllobkkfkfnphdnhnkndlbkcpglgmj/1.0.0.0/toolstrip1.html
index d0a1f21..cf87fe5 100644
--- a/chrome/test/data/extensions/good/Extensions/behllobkkfkfnphdnhnkndlbkcpglgmj/1.0.0.0/toolstrip1.html
+++ b/chrome/test/data/extensions/good/Extensions/behllobkkfkfnphdnhnkndlbkcpglgmj/1.0.0.0/toolstrip1.html
@@ -8,6 +8,16 @@ function testTabsAPI() {
window.domAutomationController.send(tabs.length == 1);
});
}
+
+// This function is called from the C++ browser test. It tests the getLanguage
+// function to make sure it can be used as an extension API. This will pass if
+// the browser navigates to a page in French language before this is called.
+function testTabsLanguageAPI() {
+ chrome.tabs.getLanguage(null, function(language) {
+ window.domAutomationController.send(language == 'FRENCH');
+ });
+}
+
</script>
<select>
<option>one</option>
diff --git a/chrome/test/data/extensions/samples/cld/manifest.json b/chrome/test/data/extensions/samples/cld/manifest.json
new file mode 100644
index 0000000..c0f20f2
--- /dev/null
+++ b/chrome/test/data/extensions/samples/cld/manifest.json
@@ -0,0 +1,6 @@
+{
+ "name": "CLD",
+ "description": "Returns language of a tab",
+ "version": "0.1",
+ "toolstrips": ["toolstrip.html"]
+}
diff --git a/chrome/test/data/extensions/samples/cld/toolstrip.html b/chrome/test/data/extensions/samples/cld/toolstrip.html
new file mode 100644
index 0000000..726a030
--- /dev/null
+++ b/chrome/test/data/extensions/samples/cld/toolstrip.html
@@ -0,0 +1,36 @@
+<!--
+Copyright (c) 2009 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.
+-->
+
+<html>
+ <head>
+ <script>
+
+var selectedId = -1;
+function refreshLanguage() {
+ console.log("refeshing...");
+ chrome.tabs.getLanguage(null, function(language) {
+ document.getElementById("languageDiv").innerHTML = language;
+ });
+}
+
+chrome.tabs.onUpdated.addListener(function(tabId, props) {
+ console.log("updated: " + tabId);
+ if (prop.status == "complete" && tabId == selectedId)
+ refreshLanguage();
+});
+
+chrome.tabs.onSelectionChanged.addListener(function(tabId, props) {
+ console.log("selection: " + tabId);
+ selectedId = tabId;
+ refreshLanguage();
+});
+ </script>
+ </head>
+ <body onload="refreshLanguage();">
+ <div id="languageDiv" class="toolstrip-button" onclick="refreshLanguage();">
+ </div>
+ </body>
+</html> \ No newline at end of file