#include "base/debug/trace_event.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
-#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/prerender_messages.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
-#include "chrome/renderer/chrome_render_process_observer.h"
+#include "chrome/renderer/isolated_world_ids.h"
#include "chrome/renderer/prerender/prerender_helper.h"
#include "chrome/renderer/safe_browsing/phishing_classifier_delegate.h"
-#include "chrome/renderer/translate/translate_helper.h"
+#include "chrome/renderer/web_apps.h"
#include "chrome/renderer/webview_color_overlay.h"
+#include "components/translate/content/renderer/translate_helper.h"
+#include "components/web_cache/renderer/web_cache_render_process_observer.h"
#include "content/public/common/bindings_policy.h"
#include "content/public/renderer/content_renderer_client.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_view.h"
#include "extensions/common/constants.h"
-#include "extensions/common/stack_frame.h"
+#include "extensions/renderer/extension_groups.h"
#include "net/base/data_url.h"
-#include "skia/ext/image_operations.h"
#include "skia/ext/platform_canvas.h"
#include "third_party/WebKit/public/platform/WebCString.h"
#include "third_party/WebKit/public/platform/WebRect.h"
#include "third_party/WebKit/public/web/WebDataSource.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebElement.h"
-#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "third_party/WebKit/public/web/WebNode.h"
#include "third_party/WebKit/public/web/WebNodeList.h"
#include "third_party/WebKit/public/web/WebView.h"
#include "ui/gfx/skbitmap_operations.h"
#include "v8/include/v8-testing.h"
+#if defined(ENABLE_EXTENSIONS)
+#include "chrome/common/extensions/chrome_extension_messages.h"
+#endif
+
using blink::WebAXObject;
using blink::WebCString;
using blink::WebDataSource;
using blink::WebFrame;
using blink::WebGestureEvent;
using blink::WebIconURL;
+using blink::WebLocalFrame;
using blink::WebNode;
using blink::WebNodeList;
using blink::WebRect;
namespace {
-GURL StripRef(const GURL& url) {
- GURL::Replacements replacements;
- replacements.ClearRef();
- return url.ReplaceComponents(replacements);
-}
-
-// If the source image is null or occupies less area than
-// |thumbnail_min_area_pixels|, we return the image unmodified. Otherwise, we
-// scale down the image so that the width and height do not exceed
-// |thumbnail_max_size_pixels|, preserving the original aspect ratio.
-SkBitmap Downscale(blink::WebImage image,
- int thumbnail_min_area_pixels,
- gfx::Size thumbnail_max_size_pixels) {
- if (image.isNull())
- return SkBitmap();
-
- gfx::Size image_size = image.size();
-
- if (image_size.GetArea() < thumbnail_min_area_pixels)
- return image.getSkBitmap();
-
- if (image_size.width() <= thumbnail_max_size_pixels.width() &&
- image_size.height() <= thumbnail_max_size_pixels.height())
- return image.getSkBitmap();
-
- gfx::SizeF scaled_size = image_size;
-
- if (scaled_size.width() > thumbnail_max_size_pixels.width()) {
- scaled_size.Scale(thumbnail_max_size_pixels.width() / scaled_size.width());
- }
-
- if (scaled_size.height() > thumbnail_max_size_pixels.height()) {
- scaled_size.Scale(
- thumbnail_max_size_pixels.height() / scaled_size.height());
- }
-
- return skia::ImageOperations::Resize(image.getSkBitmap(),
- skia::ImageOperations::RESIZE_GOOD,
- static_cast<int>(scaled_size.width()),
- static_cast<int>(scaled_size.height()));
-}
-
-// The delimiter for a stack trace provided by WebKit.
-const char kStackFrameDelimiter[] = "\n at ";
-
-// Get a stack trace from a WebKit console message.
-// There are three possible scenarios:
-// 1. WebKit gives us a stack trace in |stack_trace|.
-// 2. The stack trace is embedded in the error |message| by an internal
-// script. This will be more useful than |stack_trace|, since |stack_trace|
-// will include the internal bindings trace, instead of a developer's code.
-// 3. No stack trace is included. In this case, we should mock one up from
-// the given line number and source.
-// |message| will be populated with the error message only (i.e., will not
-// include any stack trace).
-extensions::StackTrace GetStackTraceFromMessage(
- base::string16* message,
- const base::string16& source,
- const base::string16& stack_trace,
- int32 line_number) {
- extensions::StackTrace result;
- std::vector<base::string16> pieces;
- size_t index = 0;
-
- if (message->find(base::UTF8ToUTF16(kStackFrameDelimiter)) !=
- base::string16::npos) {
- base::SplitStringUsingSubstr(*message,
- base::UTF8ToUTF16(kStackFrameDelimiter),
- &pieces);
- *message = pieces[0];
- index = 1;
- } else if (!stack_trace.empty()) {
- base::SplitStringUsingSubstr(stack_trace,
- base::UTF8ToUTF16(kStackFrameDelimiter),
- &pieces);
- }
-
- // If we got a stack trace, parse each frame from the text.
- if (index < pieces.size()) {
- for (; index < pieces.size(); ++index) {
- scoped_ptr<extensions::StackFrame> frame =
- extensions::StackFrame::CreateFromText(pieces[index]);
- if (frame.get())
- result.push_back(*frame);
- }
- }
-
- if (result.empty()) { // If we don't have a stack trace, mock one up.
- result.push_back(
- extensions::StackFrame(line_number,
- 1u, // column number
- source,
- base::string16() /* no function name */ ));
- }
-
- return result;
-}
-
#if defined(OS_ANDROID)
// Parses the DOM for a <meta> tag with a particular name.
// |meta_tag_content| is set to the contents of the 'content' attribute.
if (!child.isElementNode())
continue;
WebElement elem = child.to<WebElement>();
- if (elem.hasTagName("meta")) {
+ if (elem.hasHTMLTagName("meta")) {
if (elem.hasAttribute("name") && elem.hasAttribute("content")) {
std::string name = elem.getAttribute("name").utf8();
if (name == meta_tag_name) {
ChromeRenderViewObserver::ChromeRenderViewObserver(
content::RenderView* render_view,
- ChromeRenderProcessObserver* chrome_render_process_observer)
+ web_cache::WebCacheRenderProcessObserver* web_cache_render_process_observer)
: content::RenderViewObserver(render_view),
- chrome_render_process_observer_(chrome_render_process_observer),
- translate_helper_(new TranslateHelper(render_view)),
+ web_cache_render_process_observer_(web_cache_render_process_observer),
+ translate_helper_(new translate::TranslateHelper(
+ render_view,
+ chrome::ISOLATED_WORLD_ID_TRANSLATE,
+ extensions::EXTENSION_GROUP_INTERNAL_TRANSLATE_SCRIPTS,
+ extensions::kExtensionScheme)),
phishing_classifier_(NULL),
- last_indexed_page_id_(-1),
capture_timer_(false, false) {
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
if (!command_line.HasSwitch(switches::kDisableClientSidePhishingDetection))
bool ChromeRenderViewObserver::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(ChromeRenderViewObserver, message)
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
IPC_MESSAGE_HANDLER(ChromeViewMsg_WebUIJavaScript, OnWebUIJavaScript)
- IPC_MESSAGE_HANDLER(ChromeViewMsg_JavaScriptStressTestControl,
- OnJavaScriptStressTestControl)
- IPC_MESSAGE_HANDLER(ChromeViewMsg_SetClientSidePhishingDetection,
- OnSetClientSidePhishingDetection)
+#endif
+#if defined(ENABLE_EXTENSIONS)
IPC_MESSAGE_HANDLER(ChromeViewMsg_SetVisuallyDeemphasized,
OnSetVisuallyDeemphasized)
- IPC_MESSAGE_HANDLER(ChromeViewMsg_RequestThumbnailForContextNode,
- OnRequestThumbnailForContextNode)
- IPC_MESSAGE_HANDLER(ChromeViewMsg_GetFPS, OnGetFPS)
+#endif
#if defined(OS_ANDROID)
IPC_MESSAGE_HANDLER(ChromeViewMsg_UpdateTopControlsState,
OnUpdateTopControlsState)
- IPC_MESSAGE_HANDLER(ChromeViewMsg_RetrieveWebappInformation,
- OnRetrieveWebappInformation)
IPC_MESSAGE_HANDLER(ChromeViewMsg_RetrieveMetaTagContent,
OnRetrieveMetaTagContent)
#endif
+ IPC_MESSAGE_HANDLER(ChromeViewMsg_GetWebApplicationInfo,
+ OnGetWebApplicationInfo)
+ IPC_MESSAGE_HANDLER(ChromeViewMsg_SetClientSidePhishingDetection,
+ OnSetClientSidePhishingDetection)
IPC_MESSAGE_HANDLER(ChromeViewMsg_SetWindowFeatures, OnSetWindowFeatures)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
void ChromeRenderViewObserver::OnWebUIJavaScript(
- const base::string16& frame_xpath,
- const base::string16& jscript,
- int id,
- bool notify_result) {
- webui_javascript_.reset(new WebUIJavaScript());
- webui_javascript_->frame_xpath = frame_xpath;
- webui_javascript_->jscript = jscript;
- webui_javascript_->id = id;
- webui_javascript_->notify_result = notify_result;
-}
-
-void ChromeRenderViewObserver::OnJavaScriptStressTestControl(int cmd,
- int param) {
- if (cmd == kJavaScriptStressTestSetStressRunType) {
- v8::Testing::SetStressRunType(static_cast<v8::Testing::StressType>(param));
- } else if (cmd == kJavaScriptStressTestPrepareStressRun) {
- v8::Testing::PrepareStressRun(param);
- }
+ const base::string16& javascript) {
+ webui_javascript_.push_back(javascript);
}
+#endif
#if defined(OS_ANDROID)
void ChromeRenderViewObserver::OnUpdateTopControlsState(
render_view()->UpdateTopControlsState(constraints, current, animate);
}
-void ChromeRenderViewObserver::OnRetrieveWebappInformation(
- const GURL& expected_url) {
- WebFrame* main_frame = render_view()->GetWebView()->mainFrame();
- bool found_tag;
- std::string content_str;
-
- // Search for the "mobile-web-app-capable" tag.
- bool mobile_parse_success = RetrieveMetaTagContent(
- main_frame,
- expected_url,
- "mobile-web-app-capable",
- &found_tag,
- &content_str);
- bool is_mobile_webapp_capable = mobile_parse_success && found_tag &&
- LowerCaseEqualsASCII(content_str, "yes");
-
- // Search for the "apple-mobile-web-app-capable" tag.
- bool apple_parse_success = RetrieveMetaTagContent(
- main_frame,
- expected_url,
- "apple-mobile-web-app-capable",
- &found_tag,
- &content_str);
- bool is_apple_mobile_webapp_capable = apple_parse_success && found_tag &&
- LowerCaseEqualsASCII(content_str, "yes");
-
- bool is_only_apple_mobile_webapp_capable =
- is_apple_mobile_webapp_capable && !is_mobile_webapp_capable;
- if (main_frame && is_only_apple_mobile_webapp_capable) {
- blink::WebConsoleMessage message(
- blink::WebConsoleMessage::LevelWarning,
- "<meta name=\"apple-mobile-web-app-capable\" content=\"yes\"> is "
- "deprecated. Please include <meta name=\"mobile-web-app-capable\" "
- "content=\"yes\"> - "
- "http://developers.google.com/chrome/mobile/docs/installtohomescreen");
- main_frame->addMessageToConsole(message);
- }
-
- Send(new ChromeViewHostMsg_DidRetrieveWebappInformation(
- routing_id(),
- mobile_parse_success && apple_parse_success,
- is_mobile_webapp_capable,
- is_apple_mobile_webapp_capable,
- expected_url));
-}
-
void ChromeRenderViewObserver::OnRetrieveMetaTagContent(
const GURL& expected_url,
const std::string tag_name) {
}
#endif
+void ChromeRenderViewObserver::OnGetWebApplicationInfo() {
+ WebFrame* main_frame = render_view()->GetWebView()->mainFrame();
+ DCHECK(main_frame);
+
+ WebApplicationInfo web_app_info;
+ web_apps::ParseWebAppFromWebDocument(main_frame, &web_app_info);
+
+ // The warning below is specific to mobile but it doesn't hurt to show it even
+ // if the Chromium build is running on a desktop. It will get more exposition.
+ if (web_app_info.mobile_capable ==
+ WebApplicationInfo::MOBILE_CAPABLE_APPLE) {
+ blink::WebConsoleMessage message(
+ blink::WebConsoleMessage::LevelWarning,
+ "<meta name=\"apple-mobile-web-app-capable\" content=\"yes\"> is "
+ "deprecated. Please include <meta name=\"mobile-web-app-capable\" "
+ "content=\"yes\"> - "
+ "http://developers.google.com/chrome/mobile/docs/installtohomescreen");
+ main_frame->addMessageToConsole(message);
+ }
+
+ // Prune out any data URLs in the set of icons. The browser process expects
+ // any icon with a data URL to have originated from a favicon. We don't want
+ // to decode arbitrary data URLs in the browser process. See
+ // http://b/issue?id=1162972
+ for (std::vector<WebApplicationInfo::IconInfo>::iterator it =
+ web_app_info.icons.begin(); it != web_app_info.icons.end();) {
+ if (it->url.SchemeIs(url::kDataScheme))
+ it = web_app_info.icons.erase(it);
+ else
+ ++it;
+ }
+
+ // Truncate the strings we send to the browser process.
+ web_app_info.title =
+ web_app_info.title.substr(0, chrome::kMaxMetaTagAttributeLength);
+ web_app_info.description =
+ web_app_info.description.substr(0, chrome::kMaxMetaTagAttributeLength);
+
+ Send(new ChromeViewHostMsg_DidGetWebApplicationInfo(
+ routing_id(), web_app_info));
+}
+
void ChromeRenderViewObserver::OnSetWindowFeatures(
const WebWindowFeatures& window_features) {
render_view()->GetWebView()->setWindowFeatures(window_features);
void ChromeRenderViewObserver::Navigate(const GURL& url) {
// Execute cache clear operations that were postponed until a navigation
// event (including tab reload).
- if (chrome_render_process_observer_)
- chrome_render_process_observer_->ExecutePendingClearCache();
+ if (web_cache_render_process_observer_)
+ web_cache_render_process_observer_->ExecutePendingClearCache();
+ // Let translate_helper do any preparatory work for loading a URL.
+ if (translate_helper_)
+ translate_helper_->PrepareForUrl(url);
}
void ChromeRenderViewObserver::OnSetClientSidePhishingDetection(
bool enable_phishing_detection) {
#if defined(FULL_SAFE_BROWSING) && !defined(OS_CHROMEOS)
phishing_classifier_ = enable_phishing_detection ?
- safe_browsing::PhishingClassifierDelegate::Create(
- render_view(), NULL) :
+ safe_browsing::PhishingClassifierDelegate::Create(render_view(), NULL) :
NULL;
#endif
}
+#if defined(ENABLE_EXTENSIONS)
void ChromeRenderViewObserver::OnSetVisuallyDeemphasized(bool deemphasized) {
bool already_deemphasized = !!dimmed_color_overlay_.get();
if (already_deemphasized == deemphasized)
dimmed_color_overlay_.reset();
}
}
-
-void ChromeRenderViewObserver::OnRequestThumbnailForContextNode(
- int thumbnail_min_area_pixels, gfx::Size thumbnail_max_size_pixels) {
- WebNode context_node = render_view()->GetContextMenuNode();
- SkBitmap thumbnail;
- gfx::Size original_size;
- if (!context_node.isNull() && context_node.isElementNode()) {
- blink::WebImage image = context_node.to<WebElement>().imageContents();
- original_size = image.size();
- thumbnail = Downscale(image,
- thumbnail_min_area_pixels,
- thumbnail_max_size_pixels);
- }
- Send(new ChromeViewHostMsg_RequestThumbnailForContextNode_ACK(
- routing_id(), thumbnail, original_size));
-}
-
-void ChromeRenderViewObserver::OnGetFPS() {
- float fps = (render_view()->GetFilteredTimePerFrame() > 0.0f)?
- 1.0f / render_view()->GetFilteredTimePerFrame() : 0.0f;
- Send(new ChromeViewHostMsg_FPS(routing_id(), fps));
-}
+#endif
void ChromeRenderViewObserver::DidStartLoading() {
if ((render_view()->GetEnabledBindings() & content::BINDINGS_POLICY_WEB_UI) &&
- webui_javascript_.get()) {
- render_view()->EvaluateScript(webui_javascript_->frame_xpath,
- webui_javascript_->jscript,
- webui_javascript_->id,
- webui_javascript_->notify_result);
- webui_javascript_.reset();
+ !webui_javascript_.empty()) {
+ for (size_t i = 0; i < webui_javascript_.size(); ++i) {
+ render_view()->GetMainRenderFrame()->ExecuteJavaScript(
+ webui_javascript_[i]);
+ }
+ webui_javascript_.clear();
}
}
void ChromeRenderViewObserver::DidStopLoading() {
WebFrame* main_frame = render_view()->GetWebView()->mainFrame();
- GURL osd_url = main_frame->document().openSearchDescriptionURL();
- if (!osd_url.is_empty()) {
+ GURL osdd_url = main_frame->document().openSearchDescriptionURL();
+ if (!osdd_url.is_empty()) {
Send(new ChromeViewHostMsg_PageHasOSDD(
- routing_id(), render_view()->GetPageId(), osd_url,
+ routing_id(), main_frame->document().url(), osdd_url,
search_provider::AUTODETECTED_PROVIDER));
}
return;
CapturePageInfoLater(
- render_view()->GetPageId(),
false, // preliminary_capture
base::TimeDelta::FromMilliseconds(
render_view()->GetContentStateImmediately() ?
}
void ChromeRenderViewObserver::DidCommitProvisionalLoad(
- WebFrame* frame, bool is_new_navigation) {
+ WebLocalFrame* frame, bool is_new_navigation) {
// Don't capture pages being not new, or including refresh meta tag.
if (!is_new_navigation || HasRefreshMetaTag(frame))
return;
CapturePageInfoLater(
- render_view()->GetPageId(),
true, // preliminary_capture
base::TimeDelta::FromMilliseconds(kDelayForForcedCaptureMs));
}
-void ChromeRenderViewObserver::DetailedConsoleMessageAdded(
- const base::string16& message,
- const base::string16& source,
- const base::string16& stack_trace_string,
- int32 line_number,
- int32 severity_level) {
- base::string16 trimmed_message = message;
- extensions::StackTrace stack_trace = GetStackTraceFromMessage(
- &trimmed_message,
- source,
- stack_trace_string,
- line_number);
- Send(new ChromeViewHostMsg_DetailedConsoleMessageAdded(routing_id(),
- trimmed_message,
- source,
- stack_trace,
- severity_level));
-}
-
-void ChromeRenderViewObserver::CapturePageInfoLater(int page_id,
- bool preliminary_capture,
+void ChromeRenderViewObserver::CapturePageInfoLater(bool preliminary_capture,
base::TimeDelta delay) {
capture_timer_.Start(
FROM_HERE,
delay,
base::Bind(&ChromeRenderViewObserver::CapturePageInfo,
base::Unretained(this),
- page_id,
preliminary_capture));
}
-void ChromeRenderViewObserver::CapturePageInfo(int page_id,
- bool preliminary_capture) {
- // If |page_id| is obsolete, we should stop indexing and capturing a page.
- if (render_view()->GetPageId() != page_id)
- return;
-
+void ChromeRenderViewObserver::CapturePageInfo(bool preliminary_capture) {
if (!render_view()->GetWebView())
return;
UMA_HISTOGRAM_TIMES(kTranslateCaptureText,
base::TimeTicks::Now() - capture_begin_time);
if (translate_helper_)
- translate_helper_->PageCaptured(page_id, contents);
-
- // TODO(shess): Is indexing "Full text search" indexing? In that
- // case more of this can go.
- // Skip indexing if this is not a new load. Note that the case where
- // page_id == last_indexed_page_id_ is more complicated, since we need to
- // reindex if the toplevel URL has changed (such as from a redirect), even
- // though this may not cause the page id to be incremented.
- if (page_id < last_indexed_page_id_)
- return;
-
- bool same_page_id = last_indexed_page_id_ == page_id;
- if (!preliminary_capture)
- last_indexed_page_id_ = page_id;
-
- // Get the URL for this page.
- GURL url(main_frame->document().url());
- if (url.is_empty()) {
- if (!preliminary_capture)
- last_indexed_url_ = GURL();
- return;
- }
-
- // If the page id is unchanged, check whether the URL (ignoring fragments)
- // has changed. If so, we need to reindex. Otherwise, assume this is a
- // reload, in-page navigation, or some other load type where we don't want to
- // reindex. Note: subframe navigations after onload increment the page id,
- // so these will trigger a reindex.
- GURL stripped_url(StripRef(url));
- if (same_page_id && stripped_url == last_indexed_url_)
- return;
-
- if (!preliminary_capture)
- last_indexed_url_ = stripped_url;
+ translate_helper_->PageCaptured(contents);
TRACE_EVENT0("renderer", "ChromeRenderViewObserver::CapturePageInfo");
// terminate the string at the last space to ensure no words are clipped.
if (contents->size() == kMaxIndexChars) {
size_t last_space_index = contents->find_last_of(base::kWhitespaceUTF16);
- if (last_space_index == base::string16::npos)
- return; // don't index if we got a huge block of text with no spaces
- contents->resize(last_space_index);
+ if (last_space_index != base::string16::npos)
+ contents->resize(last_space_index);
}
}
if (!node.isElementNode())
continue;
WebElement element = node.to<WebElement>();
- if (!element.hasTagName(tag_name))
+ if (!element.hasHTMLTagName(tag_name))
continue;
WebString value = element.getAttribute(attribute_name);
if (value.isNull() || !LowerCaseEqualsASCII(value, "refresh"))