diff options
author | Torne (Richard Coles) <torne@google.com> | 2013-08-05 13:57:33 +0100 |
---|---|---|
committer | Torne (Richard Coles) <torne@google.com> | 2013-08-05 13:57:33 +0100 |
commit | a36e5920737c6adbddd3e43b760e5de8431db6e0 (patch) | |
tree | 347d048bb8c8828d50113bf94ace40bf0613f2cd /content/browser | |
parent | 34378da0e9429d394aafdaa771301aff58447cb1 (diff) | |
download | chromium_org-a36e5920737c6adbddd3e43b760e5de8431db6e0.tar.gz |
Merge from Chromium at DEPS revision r215573
This commit was generated by merge_to_master.py.
Change-Id: Ib95814f98e5765b459dd32425f9bf9138edf2bca
Diffstat (limited to 'content/browser')
147 files changed, 3335 insertions, 1670 deletions
diff --git a/content/browser/DEPS b/content/browser/DEPS index d61441d09a..39be989190 100644 --- a/content/browser/DEPS +++ b/content/browser/DEPS @@ -39,7 +39,6 @@ include_rules = [ "+third_party/WebKit/public/platform/WebGamepads.h", "+third_party/WebKit/public/platform/WebGraphicsContext3D.h", "+third_party/WebKit/public/platform/WebIDBCallbacks.h", - "+third_party/WebKit/public/platform/WebIDBDatabase.h", "+third_party/WebKit/public/platform/WebIDBDatabaseException.h", "+third_party/WebKit/public/platform/WebIDBTypes.h", "+third_party/WebKit/public/platform/WebReferrerPolicy.h", @@ -49,7 +48,6 @@ include_rules = [ "+third_party/WebKit/public/web/WebCompositionUnderline.h", "+third_party/WebKit/public/web/WebConsoleMessage.h", "+third_party/WebKit/public/web/WebCursorInfo.h", - "+third_party/WebKit/public/web/WebDevToolsAgent.h", "+third_party/WebKit/public/web/WebDragOperation.h", "+third_party/WebKit/public/web/WebDragStatus.h", "+third_party/WebKit/public/web/WebFindOptions.h", @@ -63,10 +61,7 @@ include_rules = [ "+third_party/WebKit/public/web/WebTextDirection.h", # These should be burned down. http://crbug.com/237267 - "!third_party/WebKit/public/web/WebBindings.h", - "!third_party/WebKit/public/web/android/WebInputEventFactory.h", "!third_party/WebKit/public/web/gtk/WebInputEventFactory.h", - "!third_party/WebKit/public/web/linux/WebFontInfo.h", "!third_party/WebKit/public/web/mac/WebInputEventFactory.h", # DO NOT ADD ANY CHROME OR COMPONENTS INCLUDES HERE!!! diff --git a/content/browser/accessibility/browser_accessibility_gtk.cc b/content/browser/accessibility/browser_accessibility_gtk.cc index f5539b78b5..50364282b3 100644 --- a/content/browser/accessibility/browser_accessibility_gtk.cc +++ b/content/browser/accessibility/browser_accessibility_gtk.cc @@ -12,11 +12,6 @@ namespace content { -// The maximum length of an autogenerated unique type name string, -// generated from the 16-bit interface mask from an AtkObject. -// 30 is enough for the prefix "WAIType" + 5 hex chars (max) */ -static const int kWAITypeNameLen = 30; - static gpointer browser_accessibility_parent_class = NULL; static BrowserAccessibilityGtk* ToBrowserAccessibilityGtk( @@ -27,6 +22,150 @@ static BrowserAccessibilityGtk* ToBrowserAccessibilityGtk( return atk_object->m_object; } +// +// AtkComponent interface. +// + +static BrowserAccessibilityGtk* ToBrowserAccessibilityGtk( + AtkComponent* atk_object) { + if (!IS_BROWSER_ACCESSIBILITY(atk_object)) + return NULL; + + return ToBrowserAccessibilityGtk(BROWSER_ACCESSIBILITY(atk_object)); +} + +static AtkObject* browser_accessibility_accessible_at_point( + AtkComponent* component, gint x, gint y, AtkCoordType coord_type) { + BrowserAccessibilityGtk* obj = ToBrowserAccessibilityGtk(component); + if (!obj) + return NULL; + + gfx::Point point(x, y); + if (!obj->GetGlobalBoundsRect().Contains(point)) + return NULL; + + BrowserAccessibility* result = obj->BrowserAccessibilityForPoint(point); + if (!result) + return NULL; + + AtkObject* atk_result = result->ToBrowserAccessibilityGtk()->GetAtkObject(); + g_object_ref(atk_result); + return atk_result; +} + +static void browser_accessibility_get_extents( + AtkComponent* component, gint* x, gint* y, gint* width, gint* height, + AtkCoordType coord_type) { + BrowserAccessibilityGtk* obj = ToBrowserAccessibilityGtk(component); + if (!obj) + return; + + gfx::Rect bounds = obj->GetGlobalBoundsRect(); + *x = bounds.x(); + *y = bounds.y(); + *width = bounds.width(); + *height = bounds.height(); +} + +static gboolean browser_accessibility_grab_focus(AtkComponent* component) { + BrowserAccessibilityGtk* obj = ToBrowserAccessibilityGtk(component); + if (!obj) + return false; + + obj->manager()->SetFocus(obj, true); + return true; +} + +static void ComponentInterfaceInit(AtkComponentIface* iface) { + iface->ref_accessible_at_point = browser_accessibility_accessible_at_point; + iface->get_extents = browser_accessibility_get_extents; + iface->grab_focus = browser_accessibility_grab_focus; +} + +static const GInterfaceInfo ComponentInfo = { + reinterpret_cast<GInterfaceInitFunc>(ComponentInterfaceInit), 0, 0 +}; + +// +// AtkValue interface. +// + +static BrowserAccessibilityGtk* ToBrowserAccessibilityGtk( + AtkValue* atk_object) { + if (!IS_BROWSER_ACCESSIBILITY(atk_object)) + return NULL; + + return ToBrowserAccessibilityGtk(BROWSER_ACCESSIBILITY(atk_object)); +} + +static void browser_accessibility_get_current_value( + AtkValue* atk_object, GValue* value) { + BrowserAccessibilityGtk* obj = ToBrowserAccessibilityGtk(atk_object); + if (!obj) + return; + + float float_val; + if (obj->GetFloatAttribute(AccessibilityNodeData::ATTR_VALUE_FOR_RANGE, + &float_val)) { + memset(value, 0, sizeof(*value)); + g_value_init(value, G_TYPE_FLOAT); + g_value_set_float(value, float_val); + } +} + +static void browser_accessibility_get_minimum_value( + AtkValue* atk_object, GValue* value) { + BrowserAccessibilityGtk* obj = ToBrowserAccessibilityGtk(atk_object); + if (!obj) + return; + + float float_val; + if (obj->GetFloatAttribute(AccessibilityNodeData::ATTR_MIN_VALUE_FOR_RANGE, + &float_val)) { + memset(value, 0, sizeof(*value)); + g_value_init(value, G_TYPE_FLOAT); + g_value_set_float(value, float_val); + } +} + +static void browser_accessibility_get_maximum_value( + AtkValue* atk_object, GValue* value) { + BrowserAccessibilityGtk* obj = ToBrowserAccessibilityGtk(atk_object); + if (!obj) + return; + + float float_val; + if (obj->GetFloatAttribute(AccessibilityNodeData::ATTR_MAX_VALUE_FOR_RANGE, + &float_val)) { + memset(value, 0, sizeof(*value)); + g_value_init(value, G_TYPE_FLOAT); + g_value_set_float(value, float_val); + } +} + +static void browser_accessibility_get_minimum_increment( + AtkValue* atk_object, GValue* value) { + // TODO(dmazzoni): get the correct value from an <input type=range>. + memset(value, 0, sizeof(*value)); + g_value_init(value, G_TYPE_FLOAT); + g_value_set_float(value, 1.0); +} + +static void ValueInterfaceInit(AtkValueIface* iface) { + iface->get_current_value = browser_accessibility_get_current_value; + iface->get_minimum_value = browser_accessibility_get_minimum_value; + iface->get_maximum_value = browser_accessibility_get_maximum_value; + iface->get_minimum_increment = browser_accessibility_get_minimum_increment; +} + +static const GInterfaceInfo ValueInfo = { + reinterpret_cast<GInterfaceInitFunc>(ValueInterfaceInit), 0, 0 +}; + +// +// AtkObject interface +// + static BrowserAccessibilityGtk* ToBrowserAccessibilityGtk( AtkObject* atk_object) { if (!IS_BROWSER_ACCESSIBILITY(atk_object)) @@ -126,6 +265,11 @@ static AtkRelationSet* browser_accessibility_ref_relation_set( return relation_set; } +// +// The rest of the BrowserAccessibilityGtk code, not specific to one +// of the Atk* interfaces. +// + static void browser_accessibility_init(AtkObject* atk_object, gpointer data) { if (ATK_OBJECT_CLASS(browser_accessibility_parent_class)->initialize) { ATK_OBJECT_CLASS(browser_accessibility_parent_class)->initialize( @@ -183,64 +327,42 @@ GType browser_accessibility_get_type() { return type_volatile; } -static guint16 GetInterfaceMaskFromObject(BrowserAccessibilityGtk* obj) { - return 0; -} - -static const char* GetUniqueAccessibilityTypeName(guint16 interface_mask) +static const char* GetUniqueAccessibilityTypeName(int interface_mask) { - static char name[kWAITypeNameLen + 1]; - - sprintf(name, "WAIType%x", interface_mask); - name[kWAITypeNameLen] = '\0'; - + // 20 characters is enough for "Chrome%x" with any integer value. + static char name[20]; + snprintf(name, sizeof(name), "Chrome%x", interface_mask); return name; } -static const GInterfaceInfo AtkInterfacesInitFunctions[] = { +enum AtkInterfaces { + ATK_ACTION_INTERFACE, + ATK_COMPONENT_INTERFACE, + ATK_DOCUMENT_INTERFACE, + ATK_EDITABLE_TEXT_INTERFACE, + ATK_HYPERLINK_INTERFACE, + ATK_HYPERTEXT_INTERFACE, + ATK_IMAGE_INTERFACE, + ATK_SELECTION_INTERFACE, + ATK_TABLE_INTERFACE, + ATK_TEXT_INTERFACE, + ATK_VALUE_INTERFACE, }; -enum WAIType { - WAI_ACTION, - WAI_SELECTION, - WAI_EDITABLE_TEXT, - WAI_TEXT, - WAI_COMPONENT, - WAI_IMAGE, - WAI_TABLE, - WAI_HYPERTEXT, - WAI_HYPERLINK, - WAI_DOCUMENT, - WAI_VALUE, -}; +static int GetInterfaceMaskFromObject(BrowserAccessibilityGtk* obj) { + int interface_mask = 0; + + // Component interface is always supported. + interface_mask |= 1 << ATK_COMPONENT_INTERFACE; -static GType GetAtkInterfaceTypeFromWAIType(WAIType type) { - switch (type) { - case WAI_ACTION: - return ATK_TYPE_ACTION; - case WAI_SELECTION: - return ATK_TYPE_SELECTION; - case WAI_EDITABLE_TEXT: - return ATK_TYPE_EDITABLE_TEXT; - case WAI_TEXT: - return ATK_TYPE_TEXT; - case WAI_COMPONENT: - return ATK_TYPE_COMPONENT; - case WAI_IMAGE: - return ATK_TYPE_IMAGE; - case WAI_TABLE: - return ATK_TYPE_TABLE; - case WAI_HYPERTEXT: - return ATK_TYPE_HYPERTEXT; - case WAI_HYPERLINK: - return ATK_TYPE_HYPERLINK_IMPL; - case WAI_DOCUMENT: - return ATK_TYPE_DOCUMENT; - case WAI_VALUE: - return ATK_TYPE_VALUE; + int role = obj->role(); + if (role == AccessibilityNodeData::ROLE_PROGRESS_INDICATOR || + role == AccessibilityNodeData::ROLE_SCROLLBAR || + role == AccessibilityNodeData::ROLE_SLIDER) { + interface_mask |= 1 << ATK_VALUE_INTERFACE; } - return G_TYPE_INVALID; + return interface_mask; } static GType GetAccessibilityTypeFromObject(BrowserAccessibilityGtk* obj) { @@ -257,7 +379,7 @@ static GType GetAccessibilityTypeFromObject(BrowserAccessibilityGtk* obj) { 0 /* value table */ }; - guint16 interface_mask = GetInterfaceMaskFromObject(obj); + int interface_mask = GetInterfaceMaskFromObject(obj); const char* atk_type_name = GetUniqueAccessibilityTypeName(interface_mask); GType type = g_type_from_name(atk_type_name); if (type) @@ -267,14 +389,10 @@ static GType GetAccessibilityTypeFromObject(BrowserAccessibilityGtk* obj) { atk_type_name, &type_info, GTypeFlags(0)); - for (guint i = 0; i < G_N_ELEMENTS(AtkInterfacesInitFunctions); i++) { - if (interface_mask & (1 << i)) { - g_type_add_interface_static( - type, - GetAtkInterfaceTypeFromWAIType(static_cast<WAIType>(i)), - &AtkInterfacesInitFunctions[i]); - } - } + if (interface_mask & (1 << ATK_COMPONENT_INTERFACE)) + g_type_add_interface_static(type, ATK_TYPE_COMPONENT, &ComponentInfo); + if (interface_mask & (1 << ATK_VALUE_INTERFACE)) + g_type_add_interface_static(type, ATK_TYPE_VALUE, &ValueInfo); return type; } @@ -302,13 +420,14 @@ BrowserAccessibilityGtk* BrowserAccessibility::ToBrowserAccessibilityGtk() { return static_cast<BrowserAccessibilityGtk*>(this); } -BrowserAccessibilityGtk::BrowserAccessibilityGtk() { - atk_object_ = ATK_OBJECT(browser_accessibility_new(this)); +BrowserAccessibilityGtk::BrowserAccessibilityGtk() + : atk_object_(NULL) { } BrowserAccessibilityGtk::~BrowserAccessibilityGtk() { browser_accessibility_detach(BROWSER_ACCESSIBILITY(atk_object_)); - g_object_unref(atk_object_); + if (atk_object_) + g_object_unref(atk_object_); } AtkObject* BrowserAccessibilityGtk::GetAtkObject() const { @@ -321,10 +440,25 @@ void BrowserAccessibilityGtk::PreInitialize() { BrowserAccessibility::PreInitialize(); InitRoleAndState(); - if (this->parent()) { - atk_object_set_parent( - atk_object_, - this->parent()->ToBrowserAccessibilityGtk()->GetAtkObject()); + if (atk_object_) { + // If the object's role changes and that causes its + // interface mask to change, we need to create a new + // AtkObject for it. + int interface_mask = GetInterfaceMaskFromObject(this); + if (interface_mask != interface_mask_) { + g_object_unref(atk_object_); + atk_object_ = NULL; + } + } + + if (!atk_object_) { + interface_mask_ = GetInterfaceMaskFromObject(this); + atk_object_ = ATK_OBJECT(browser_accessibility_new(this)); + if (this->parent()) { + atk_object_set_parent( + atk_object_, + this->parent()->ToBrowserAccessibilityGtk()->GetAtkObject()); + } } } diff --git a/content/browser/accessibility/browser_accessibility_gtk.h b/content/browser/accessibility/browser_accessibility_gtk.h index ba28b12f7b..8f3a2e31e5 100644 --- a/content/browser/accessibility/browser_accessibility_gtk.h +++ b/content/browser/accessibility/browser_accessibility_gtk.h @@ -85,6 +85,7 @@ class BrowserAccessibilityGtk : public BrowserAccessibility { AtkRole atk_role_; std::string atk_acc_name_; std::string atk_acc_description_; + int interface_mask_; private: DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityGtk); diff --git a/content/browser/android/DEPS b/content/browser/android/DEPS new file mode 100644 index 0000000000..0410b36ac8 --- /dev/null +++ b/content/browser/android/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+third_party/WebKit/public/web/WebBindings.h", # For java bridge bindings +] diff --git a/content/browser/android/browser_jni_registrar.cc b/content/browser/android/browser_jni_registrar.cc index 25e0c3b926..35da3af3f3 100644 --- a/content/browser/android/browser_jni_registrar.cc +++ b/content/browser/android/browser_jni_registrar.cc @@ -9,6 +9,7 @@ #include "content/browser/accessibility/browser_accessibility_android.h" #include "content/browser/accessibility/browser_accessibility_manager_android.h" #include "content/browser/android/android_browser_process.h" +#include "content/browser/android/browser_startup_config.h" #include "content/browser/android/child_process_launcher_android.h" #include "content/browser/android/content_settings.h" #include "content/browser/android/content_video_view.h" @@ -36,37 +37,37 @@ using content::SurfaceTexturePeerBrowserImpl; namespace { base::android::RegistrationMethod kContentRegisteredMethods[] = { - { "AndroidLocationApiAdapter", - content::AndroidLocationApiAdapter::RegisterGeolocationService }, - { "AndroidBrowserProcess", content::RegisterAndroidBrowserProcess }, - { "BrowserAccessibilityManager", - content::RegisterBrowserAccessibilityManager }, - { "ChildProcessLauncher", content::RegisterChildProcessLauncher }, - { "ContentSettings", content::ContentSettings::RegisterContentSettings }, - { "ContentViewRenderView", - content::ContentViewRenderView::RegisterContentViewRenderView }, - { "ContentVideoView", content::ContentVideoView::RegisterContentVideoView }, - { "ContentViewCore", content::RegisterContentViewCore }, - { "DataFetcherImplAndroid", content::DataFetcherImplAndroid::Register }, - { "DateTimePickerAndroid", content::RegisterDateTimeChooserAndroid }, - { "DownloadControllerAndroidImpl", - content::DownloadControllerAndroidImpl::RegisterDownloadController }, - { "InterstitialPageDelegateAndroid", - content::InterstitialPageDelegateAndroid - ::RegisterInterstitialPageDelegateAndroid }, - { "MediaResourceGetterImpl", - content::MediaResourceGetterImpl::RegisterMediaResourceGetter }, - { "LoadUrlParams", content::RegisterLoadUrlParams }, - { "PowerSaveBlock", content::RegisterPowerSaveBlocker }, - { "RegisterImeAdapter", content::RegisterImeAdapter }, - { "SpeechRecognizerImplAndroid", - content::SpeechRecognizerImplAndroid::RegisterSpeechRecognizer }, - { "TouchPoint", content::RegisterTouchPoint }, - { "TracingIntentHandler", content::RegisterTracingIntentHandler }, - { "VibrationMessageFilter", content::VibrationMessageFilter::Register }, - { "WebContentsObserverAndroid", content::RegisterWebContentsObserverAndroid }, - { "WebViewStatics", content::RegisterWebViewStatics }, -}; + {"AndroidLocationApiAdapter", + content::AndroidLocationApiAdapter::RegisterGeolocationService}, + {"AndroidBrowserProcess", content::RegisterAndroidBrowserProcess}, + {"BrowserAccessibilityManager", + content::RegisterBrowserAccessibilityManager}, + {"BrowserStartupConfiguration", content::RegisterBrowserStartupConfig}, + {"ChildProcessLauncher", content::RegisterChildProcessLauncher}, + {"ContentSettings", content::ContentSettings::RegisterContentSettings}, + {"ContentViewRenderView", + content::ContentViewRenderView::RegisterContentViewRenderView}, + {"ContentVideoView", content::ContentVideoView::RegisterContentVideoView}, + {"ContentViewCore", content::RegisterContentViewCore}, + {"DataFetcherImplAndroid", content::DataFetcherImplAndroid::Register}, + {"DateTimePickerAndroid", content::RegisterDateTimeChooserAndroid}, + {"DownloadControllerAndroidImpl", + content::DownloadControllerAndroidImpl::RegisterDownloadController}, + {"InterstitialPageDelegateAndroid", + content::InterstitialPageDelegateAndroid:: + RegisterInterstitialPageDelegateAndroid}, + {"MediaResourceGetterImpl", + content::MediaResourceGetterImpl::RegisterMediaResourceGetter}, + {"LoadUrlParams", content::RegisterLoadUrlParams}, + {"PowerSaveBlock", content::RegisterPowerSaveBlocker}, + {"RegisterImeAdapter", content::RegisterImeAdapter}, + {"SpeechRecognizerImplAndroid", + content::SpeechRecognizerImplAndroid::RegisterSpeechRecognizer}, + {"TouchPoint", content::RegisterTouchPoint}, + {"TracingIntentHandler", content::RegisterTracingIntentHandler}, + {"VibrationMessageFilter", content::VibrationMessageFilter::Register}, + {"WebContentsObserverAndroid", content::RegisterWebContentsObserverAndroid}, + {"WebViewStatics", content::RegisterWebViewStatics}, }; } // namespace diff --git a/content/browser/android/browser_media_player_manager.cc b/content/browser/android/browser_media_player_manager.cc index 78c1499ca3..dbf0c8f303 100644 --- a/content/browser/android/browser_media_player_manager.cc +++ b/content/browser/android/browser_media_player_manager.cc @@ -58,12 +58,12 @@ bool BrowserMediaPlayerManager::OnMessageReceived(const IPC::Message& msg) { IPC_BEGIN_MESSAGE_MAP(BrowserMediaPlayerManager, msg) IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_EnterFullscreen, OnEnterFullscreen) IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_ExitFullscreen, OnExitFullscreen) - IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_MediaPlayerInitialize, OnInitialize) - IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_MediaPlayerStart, OnStart) - IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_MediaPlayerSeek, OnSeek) - IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_MediaPlayerPause, OnPause) - IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_MediaPlayerRelease, - OnReleaseResources) + IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_Initialize, OnInitialize) + IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_Start, OnStart) + IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_Seek, OnSeek) + IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_Pause, OnPause) + IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_SetVolume, OnSetVolume) + IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_Release, OnReleaseResources) IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_DestroyMediaPlayer, OnDestroyPlayer) IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_DestroyAllMediaPlayers, DestroyAllMediaPlayers) @@ -406,6 +406,12 @@ void BrowserMediaPlayerManager::OnPause(int player_id) { player->Pause(); } +void BrowserMediaPlayerManager::OnSetVolume(int player_id, double volume) { + MediaPlayerAndroid* player = GetPlayer(player_id); + if (player) + player->SetVolume(volume); +} + void BrowserMediaPlayerManager::OnReleaseResources(int player_id) { MediaPlayerAndroid* player = GetPlayer(player_id); // Don't release the fullscreen player when tab visibility changes, diff --git a/content/browser/android/browser_media_player_manager.h b/content/browser/android/browser_media_player_manager.h index 8f192e7a84..7f193e9617 100644 --- a/content/browser/android/browser_media_player_manager.h +++ b/content/browser/android/browser_media_player_manager.h @@ -116,6 +116,7 @@ class CONTENT_EXPORT BrowserMediaPlayerManager virtual void OnStart(int player_id); virtual void OnSeek(int player_id, base::TimeDelta time); virtual void OnPause(int player_id); + virtual void OnSetVolume(int player_id, double volume); virtual void OnReleaseResources(int player_id); virtual void OnDestroyPlayer(int player_id); virtual void OnDemuxerReady( diff --git a/content/browser/android/browser_startup_config.cc b/content/browser/android/browser_startup_config.cc new file mode 100644 index 0000000000..3e74208069 --- /dev/null +++ b/content/browser/android/browser_startup_config.cc @@ -0,0 +1,25 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/android/browser_startup_config.h" + +#include "base/android/jni_android.h" +#include "jni/BrowserStartupConfig_jni.h" + +namespace content { + +bool BrowserMayStartAsynchronously() { + JNIEnv* env = base::android::AttachCurrentThread(); + return Java_BrowserStartupConfig_browserMayStartAsynchonously(env); +} + +void BrowserStartupComplete(int result) { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_BrowserStartupConfig_browserStartupComplete(env, result); +} + +bool RegisterBrowserStartupConfig(JNIEnv* env) { + return RegisterNativesImpl(env); +} +} // namespace content diff --git a/content/browser/android/browser_startup_config.h b/content/browser/android/browser_startup_config.h new file mode 100644 index 0000000000..95575f2bc2 --- /dev/null +++ b/content/browser/android/browser_startup_config.h @@ -0,0 +1,18 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_BROWSER_STARTUP_CONFIGURATION_H_ +#define CONTENT_BROWSER_BROWSER_STARTUP_CONFIGURATION_H_ + +#include <jni.h> + +namespace content { + +bool BrowserMayStartAsynchronously(); +void BrowserStartupComplete(int result); + +bool RegisterBrowserStartupConfig(JNIEnv* env); + +} // namespace content +#endif // CONTENT_BROWSER_BROWSER_STARTUP_CONFIGURATION_H_ diff --git a/content/browser/android/content_video_view.cc b/content/browser/android/content_video_view.cc index 144ac01aba..4a0fdc67a4 100644 --- a/content/browser/android/content_video_view.cc +++ b/content/browser/android/content_video_view.cc @@ -54,7 +54,7 @@ ContentVideoView::ContentVideoView( ContentVideoView::~ContentVideoView() { DCHECK(g_content_video_view); - DCHECK(!GetJavaObject(AttachCurrentThread()).obj()); + DestroyContentVideoView(true); g_content_video_view = NULL; } @@ -100,13 +100,7 @@ void ContentVideoView::OnPlaybackComplete() { } void ContentVideoView::OnExitFullscreen() { - JNIEnv *env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env); - if (!content_video_view.is_null()) { - Java_ContentVideoView_destroyContentVideoView(env, - content_video_view.obj()); - j_content_video_view_.reset(); - } + DestroyContentVideoView(false); } void ContentVideoView::UpdateMediaMetadata() { @@ -178,4 +172,13 @@ ScopedJavaLocalRef<jobject> ContentVideoView::GetJavaObject(JNIEnv* env) { return j_content_video_view_.get(env); } +void ContentVideoView::DestroyContentVideoView(bool native_view_destroyed) { + JNIEnv *env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env); + if (!content_video_view.is_null()) { + Java_ContentVideoView_destroyContentVideoView(env, + content_video_view.obj(), native_view_destroyed); + j_content_video_view_.reset(); + } +} } // namespace content diff --git a/content/browser/android/content_video_view.h b/content/browser/android/content_video_view.h index 2647bb0688..2a86830def 100644 --- a/content/browser/android/content_video_view.h +++ b/content/browser/android/content_video_view.h @@ -76,6 +76,10 @@ class ContentVideoView { base::android::ScopedJavaLocalRef<jobject> GetJavaObject(JNIEnv* env); private: + // Destroy the |j_content_video_view_|. If |native_view_destroyed| is true, + // no further calls to the native object is allowed. + void DestroyContentVideoView(bool native_view_destroyed); + // Object that manages the fullscreen media player. It is responsible for // handling all the playback controls. BrowserMediaPlayerManager* manager_; diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc index cfd19dbc04..80fe628dd0 100644 --- a/content/browser/android/content_view_core_impl.cc +++ b/content/browser/android/content_view_core_impl.cc @@ -471,6 +471,14 @@ void ContentViewCoreImpl::ConfirmTouchEvent(InputEventAckState ack_result) { static_cast<jint>(ack_result)); } +void ContentViewCoreImpl::UnhandledFlingStartEvent() { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); + if (j_obj.is_null()) + return; + Java_ContentViewCore_unhandledFlingStartEvent(env, j_obj.obj()); +} + void ContentViewCoreImpl::HasTouchEventHandlers(bool need_touch_events) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); diff --git a/content/browser/android/content_view_core_impl.h b/content/browser/android/content_view_core_impl.h index dc5bd584d0..ab7da6d243 100644 --- a/content/browser/android/content_view_core_impl.h +++ b/content/browser/android/content_view_core_impl.h @@ -253,6 +253,7 @@ class ContentViewCoreImpl : public ContentViewCore, bool HasFocus(); void ConfirmTouchEvent(InputEventAckState ack_result); + void UnhandledFlingStartEvent(); void HasTouchEventHandlers(bool need_touch_events); void OnSelectionChanged(const std::string& text); void OnSelectionBoundsChanged( diff --git a/content/browser/android/edge_effect.cc b/content/browser/android/edge_effect.cc index b46d3dafc7..d8411bc1f8 100644 --- a/content/browser/android/edge_effect.cc +++ b/content/browser/android/edge_effect.cc @@ -33,11 +33,6 @@ const float kHeldEdgeScaleY = .5f; const float kMaxGlowHeight = 4.f; -// Note: The Android version computes the aspect ratio from the source texture; -// because we use rescaled images, this is precomputed from the original Android -// textures. -const float kGlowImageAspectRatioInverse = 0.25f; - const float kPullGlowBegin = 1.f; const float kPullEdgeBegin = 0.6f; @@ -352,8 +347,9 @@ void EdgeEffect::ApplyToLayers(gfx::SizeF size, Edge edge) { &dummy_scale_x, &dummy_scale_y, &glow_image_bounds); const int glow_height = glow_image_bounds.height(); + const int glow_width = glow_image_bounds.width(); const int glow_bottom = static_cast<int>(std::min( - glow_height * glow_scale_y_ * kGlowImageAspectRatioInverse * 0.6f, + glow_height * glow_scale_y_ * glow_height / glow_width * 0.6f, glow_height * kMaxGlowHeight) * dpi_scale_ + 0.5f); UpdateLayer(glow_.get(), edge, size, glow_bottom, glow_alpha_); diff --git a/content/browser/android/in_process/synchronous_compositor_output_surface.cc b/content/browser/android/in_process/synchronous_compositor_output_surface.cc index a65ab1fa4e..fafd06fda2 100644 --- a/content/browser/android/in_process/synchronous_compositor_output_surface.cc +++ b/content/browser/android/in_process/synchronous_compositor_output_surface.cc @@ -9,6 +9,7 @@ #include "cc/output/begin_frame_args.h" #include "cc/output/compositor_frame.h" #include "cc/output/context_provider.h" +#include "cc/output/managed_memory_policy.h" #include "cc/output/output_surface_client.h" #include "cc/output/software_output_device.h" #include "content/browser/android/in_process/synchronous_compositor_impl.h" @@ -124,6 +125,16 @@ bool SynchronousCompositorOutputSurface::BindToClient( SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate(); if (delegate) delegate->DidBindOutputSurface(this); + + const int bytes_limit = 64 * 1024 * 1024; + const int num_resources_limit = 100; + surface_client->SetMemoryPolicy( + cc::ManagedMemoryPolicy(bytes_limit, + cc::ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING, + 0, + cc::ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING, + num_resources_limit)); + return true; } diff --git a/content/browser/android/overscroll_glow.cc b/content/browser/android/overscroll_glow.cc index 891201e640..2c9efeea72 100644 --- a/content/browser/android/overscroll_glow.cc +++ b/content/browser/android/overscroll_glow.cc @@ -4,10 +4,10 @@ #include "content/browser/android/overscroll_glow.h" +#include "base/debug/trace_event.h" #include "base/lazy_instance.h" #include "cc/layers/image_layer.h" #include "content/browser/android/edge_effect.h" -#include "skia/ext/image_operations.h" #include "ui/gfx/android/java_bitmap.h" using std::max; @@ -19,22 +19,16 @@ namespace { const float kEpsilon = 1e-3f; -SkBitmap CreateBitmap(const char* resource, gfx::Size size) { - SkBitmap bitmap = gfx::CreateSkBitmapFromResource(resource); - if (bitmap.isNull()) - return bitmap; - return skia::ImageOperations::Resize(bitmap, - skia::ImageOperations::RESIZE_GOOD, - size.width(), size.height()); -} - class OverscrollResources { public: - OverscrollResources() - : edge_bitmap_(CreateBitmap("android:drawable/overscroll_edge", - gfx::Size(256, 12))), - glow_bitmap_(CreateBitmap("android:drawable/overscroll_glow", - gfx::Size(128, 128))) { + OverscrollResources() { + TRACE_EVENT0("browser", "OverscrollResources::Create"); + edge_bitmap_ = + gfx::CreateSkBitmapFromResource("android:drawable/overscroll_edge", + gfx::Size(128, 12)); + glow_bitmap_ = + gfx::CreateSkBitmapFromResource("android:drawable/overscroll_glow", + gfx::Size(128, 64)); } const SkBitmap& edge_bitmap() { return edge_bitmap_; } diff --git a/content/browser/aura/OWNERS b/content/browser/aura/OWNERS index 7b915c61ea..3b61cda829 100644 --- a/content/browser/aura/OWNERS +++ b/content/browser/aura/OWNERS @@ -1,3 +1,4 @@ piman@chromium.org danakj@chromium.org sievers@chromium.org +jbauman@chromium.org diff --git a/content/browser/aura/gpu_process_transport_factory.cc b/content/browser/aura/gpu_process_transport_factory.cc index 6ac45f7665..2210e8de21 100644 --- a/content/browser/aura/gpu_process_transport_factory.cc +++ b/content/browser/aura/gpu_process_transport_factory.cc @@ -32,10 +32,10 @@ #include "ui/gfx/size.h" #if defined(OS_WIN) -#include "content/browser/renderer_host/software_output_device_win.h" +#include "content/browser/aura/software_output_device_win.h" #include "ui/surface/accelerated_surface_win.h" #elif defined(USE_X11) -#include "content/browser/renderer_host/software_output_device_x11.h" +#include "content/browser/aura/software_output_device_x11.h" #endif namespace content { @@ -197,6 +197,11 @@ scoped_ptr<cc::OutputSurface> CreateSoftwareOutputSurface( ui::Compositor* compositor) { scoped_ptr<cc::OutputSurface> output_surface; + if (ui::Compositor::WasInitializedWithThread()) { + LOG(FATAL) << "Can't use software compositing with browser threaded" + " compositing."; + } + #if defined(OS_WIN) scoped_ptr<SoftwareOutputDeviceWin> software_device( new SoftwareOutputDeviceWin(compositor)); @@ -405,14 +410,15 @@ GpuProcessTransportFactory::OffscreenContextProviderForMainThread() { base::Bind(&GpuProcessTransportFactory:: CreateOffscreenCommandBufferContext, base::Unretained(this))); - shared_contexts_main_thread_->SetLostContextCallback(base::Bind( - &GpuProcessTransportFactory:: - OnLostMainThreadSharedContextInsideCallback, - callback_factory_.GetWeakPtr())); - - if (shared_contexts_main_thread_.get() && - !shared_contexts_main_thread_->BindToCurrentThread()) - shared_contexts_main_thread_ = NULL; + if (shared_contexts_main_thread_) { + shared_contexts_main_thread_->SetLostContextCallback(base::Bind( + &GpuProcessTransportFactory:: + OnLostMainThreadSharedContextInsideCallback, + callback_factory_.GetWeakPtr())); + + if (!shared_contexts_main_thread_->BindToCurrentThread()) + shared_contexts_main_thread_ = NULL; + } } return shared_contexts_main_thread_; } diff --git a/content/browser/renderer_host/software_output_device_win.cc b/content/browser/aura/software_output_device_win.cc index 6535d4d23e..0332e3e936 100644 --- a/content/browser/renderer_host/software_output_device_win.cc +++ b/content/browser/aura/software_output_device_win.cc @@ -1,8 +1,8 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/browser/renderer_host/software_output_device_win.h" +#include "content/browser/aura/software_output_device_win.h" #include "content/public/browser/browser_thread.h" #include "third_party/skia/include/core/SkBitmap.h" diff --git a/content/browser/renderer_host/software_output_device_win.h b/content/browser/aura/software_output_device_win.h index e52808609d..93568c2bd5 100644 --- a/content/browser/renderer_host/software_output_device_win.h +++ b/content/browser/aura/software_output_device_win.h @@ -1,9 +1,9 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_BROWSER_RENDERER_HOST_SOFTWARE_OUTPUT_DEVICE_WIN_H_ -#define CONTENT_BROWSER_RENDERER_HOST_SOFTWARE_OUTPUT_DEVICE_WIN_H_ +#ifndef CONTENT_BROWSER_AURA_SOFTWARE_OUTPUT_DEVICE_WIN_H_ +#define CONTENT_BROWSER_AURA_SOFTWARE_OUTPUT_DEVICE_WIN_H_ #include "base/memory/scoped_ptr.h" #include "cc/output/software_output_device.h" @@ -38,4 +38,4 @@ class SoftwareOutputDeviceWin : public cc::SoftwareOutputDevice { } // namespace content -#endif // CONTENT_BROWSER_RENDERER_HOST_SOFTWARE_OUTPUT_DEVICE_WIN_H_ +#endif // CONTENT_BROWSER_AURA_SOFTWARE_OUTPUT_DEVICE_WIN_H_ diff --git a/content/browser/renderer_host/software_output_device_x11.cc b/content/browser/aura/software_output_device_x11.cc index 2c7ab2283f..229755b6ff 100644 --- a/content/browser/renderer_host/software_output_device_x11.cc +++ b/content/browser/aura/software_output_device_x11.cc @@ -1,8 +1,8 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/browser/renderer_host/software_output_device_x11.h" +#include "content/browser/aura/software_output_device_x11.h" #include <X11/Xlib.h> #include <X11/Xutil.h> diff --git a/content/browser/renderer_host/software_output_device_x11.h b/content/browser/aura/software_output_device_x11.h index 4c7876a365..986a486d75 100644 --- a/content/browser/renderer_host/software_output_device_x11.h +++ b/content/browser/aura/software_output_device_x11.h @@ -1,9 +1,9 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_BROWSER_RENDERER_HOST_SOFTWARE_OUTPUT_DEVICE_X11_H_ -#define CONTENT_BROWSER_RENDERER_HOST_SOFTWARE_OUTPUT_DEVICE_X11_H_ +#ifndef CONTENT_BROWSER_AURA_SOFTWARE_OUTPUT_DEVICE_X11_H_ +#define CONTENT_BROWSER_AURA_SOFTWARE_OUTPUT_DEVICE_X11_H_ #include "cc/output/software_output_device.h" #include "ui/base/x/x11_util.h" @@ -35,4 +35,4 @@ class SoftwareOutputDeviceX11 : public cc::SoftwareOutputDevice { } // namespace content -#endif // CONTENT_BROWSER_RENDERER_HOST_SOFTWARE_OUTPUT_DEVICE_X11_H_ +#endif // CONTENT_BROWSER_AURA_SOFTWARE_OUTPUT_DEVICE_X11_H_ diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc index 6155776e56..780dc6a2d4 100644 --- a/content/browser/browser_child_process_host_impl.cc +++ b/content/browser/browser_child_process_host_impl.cc @@ -95,7 +95,8 @@ BrowserChildProcessHostImpl::BrowserChildProcessHostImpl( int process_type, BrowserChildProcessHostDelegate* delegate) : data_(process_type), - delegate_(delegate) { + delegate_(delegate), + power_monitor_message_broadcaster_(this) { data_.id = ChildProcessHostImpl::GenerateChildProcessUniqueId(); child_process_host_.reset(ChildProcessHost::Create(this)); diff --git a/content/browser/browser_child_process_host_impl.h b/content/browser/browser_child_process_host_impl.h index e25b514415..61971d6d97 100644 --- a/content/browser/browser_child_process_host_impl.h +++ b/content/browser/browser_child_process_host_impl.h @@ -12,6 +12,7 @@ #include "base/process/process.h" #include "base/synchronization/waitable_event_watcher.h" #include "content/browser/child_process_launcher.h" +#include "content/browser/power_monitor_message_broadcaster.h" #include "content/public/browser/browser_child_process_host.h" #include "content/public/browser/child_process_data.h" #include "content/public/common/child_process_host_delegate.h" @@ -104,6 +105,8 @@ class CONTENT_EXPORT BrowserChildProcessHostImpl scoped_ptr<ChildProcessLauncher> child_process_; + PowerMonitorMessageBroadcaster power_monitor_message_broadcaster_; + #if defined(OS_WIN) // Watches to see if the child process exits before the IPC channel has // been connected. Thereafter, its exit is determined by an error on the diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index cc45bc2375..1c6b1a033e 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc @@ -13,6 +13,7 @@ #include "base/metrics/histogram.h" #include "base/pending_task.h" #include "base/power_monitor/power_monitor.h" +#include "base/power_monitor/power_monitor_device_source.h" #include "base/process/process_metrics.h" #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" @@ -34,6 +35,7 @@ #include "content/browser/renderer_host/media/audio_mirroring_manager.h" #include "content/browser/renderer_host/media/media_stream_manager.h" #include "content/browser/speech/speech_recognition_manager_impl.h" +#include "content/browser/startup_task_runner.h" #include "content/browser/tracing/trace_controller_impl.h" #include "content/browser/webui/content_web_ui_controller_factory.h" #include "content/browser/webui/url_data_manager.h" @@ -60,6 +62,7 @@ #if defined(OS_ANDROID) #include "base/android/jni_android.h" +#include "content/browser/android/browser_startup_config.h" #include "content/browser/android/surface_texture_peer_browser_impl.h" #endif @@ -299,7 +302,8 @@ BrowserMainLoop* BrowserMainLoop::GetInstance() { BrowserMainLoop::BrowserMainLoop(const MainFunctionParams& parameters) : parameters_(parameters), parsed_command_line_(parameters.command_line), - result_code_(RESULT_CODE_NORMAL_EXIT) { + result_code_(RESULT_CODE_NORMAL_EXIT), + created_threads_(false) { DCHECK(!g_current_browser_main_loop); g_current_browser_main_loop = this; } @@ -394,7 +398,9 @@ void BrowserMainLoop::MainMessageLoopStart() { } { TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:PowerMonitor") - power_monitor_.reset(new base::PowerMonitor); + scoped_ptr<base::PowerMonitorSource> power_monitor_source( + new base::PowerMonitorDeviceSource()); + power_monitor_.reset(new base::PowerMonitor(power_monitor_source.Pass())); } { TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:HighResTimerManager") @@ -483,8 +489,7 @@ void BrowserMainLoop::MainMessageLoopStart() { #endif } -void BrowserMainLoop::CreateThreads() { - TRACE_EVENT0("startup", "BrowserMainLoop::CreateThreads") +int BrowserMainLoop::PreCreateThreads() { if (parts_) { TRACE_EVENT0("startup", @@ -509,9 +514,44 @@ void BrowserMainLoop::CreateThreads() { if (parsed_command_line_.HasSwitch(switches::kSingleProcess)) RenderProcessHost::SetRunRendererInProcess(true); #endif + return result_code_; +} - if (result_code_ > 0) - return; +void BrowserMainLoop::CreateStartupTasks() { + TRACE_EVENT0("startup", "BrowserMainLoop::CreateStartupTasks") + +#if defined(OS_ANDROID) + scoped_refptr<StartupTaskRunner> task_runner = + new StartupTaskRunner(BrowserMayStartAsynchronously(), + base::Bind(&BrowserStartupComplete), + base::MessageLoop::current()->message_loop_proxy()); +#else + scoped_refptr<StartupTaskRunner> task_runner = + new StartupTaskRunner(false, + base::Callback<void(int)>(), + base::MessageLoop::current()->message_loop_proxy()); +#endif + StartupTask pre_create_threads = + base::Bind(&BrowserMainLoop::PreCreateThreads, base::Unretained(this)); + task_runner->AddTask(pre_create_threads); + + StartupTask create_threads = + base::Bind(&BrowserMainLoop::CreateThreads, base::Unretained(this)); + task_runner->AddTask(create_threads); + + StartupTask browser_thread_started = base::Bind( + &BrowserMainLoop::BrowserThreadsStarted, base::Unretained(this)); + task_runner->AddTask(browser_thread_started); + + StartupTask pre_main_message_loop_run = base::Bind( + &BrowserMainLoop::PreMainMessageLoopRun, base::Unretained(this)); + task_runner->AddTask(pre_main_message_loop_run); + + task_runner->StartRunningTasks(); +} + +int BrowserMainLoop::CreateThreads() { + TRACE_EVENT0("startup", "BrowserMainLoop::CreateThreads"); base::Thread::Options default_options; base::Thread::Options io_message_loop_options; @@ -596,14 +636,11 @@ void BrowserMainLoop::CreateThreads() { TRACE_EVENT_END0("startup", "BrowserMainLoop::CreateThreads:start"); } + created_threads_ = true; + return result_code_; +} -#if !defined(OS_IOS) - indexed_db_thread_.reset(new base::Thread("IndexedDB")); - indexed_db_thread_->Start(); -#endif - - BrowserThreadsStarted(); - +int BrowserMainLoop::PreMainMessageLoopRun() { if (parts_) { TRACE_EVENT0("startup", "BrowserMainLoop::CreateThreads:PreMainMessageLoopRun"); @@ -614,6 +651,7 @@ void BrowserMainLoop::CreateThreads() { // Do not allow disk IO from the UI thread. base::ThreadRestrictions::SetIOAllowed(false); base::ThreadRestrictions::DisallowWaiting(); + return result_code_; } void BrowserMainLoop::RunMainMessageLoopParts() { @@ -630,6 +668,11 @@ void BrowserMainLoop::RunMainMessageLoopParts() { } void BrowserMainLoop::ShutdownThreadsAndCleanUp() { + + if (!created_threads_) { + // Called early, nothing to do + return; + } // Teardown may start in PostMainMessageLoopRun, and during teardown we // need to be able to perform IO. base::ThreadRestrictions::SetIOAllowed(true); @@ -765,8 +808,14 @@ void BrowserMainLoop::InitializeMainThread() { new BrowserThreadImpl(BrowserThread::UI, base::MessageLoop::current())); } -void BrowserMainLoop::BrowserThreadsStarted() { +int BrowserMainLoop::BrowserThreadsStarted() { TRACE_EVENT0("startup", "BrowserMainLoop::BrowserThreadsStarted") + +#if !defined(OS_IOS) + indexed_db_thread_.reset(new base::Thread("IndexedDB")); + indexed_db_thread_->Start(); +#endif + #if defined(OS_ANDROID) // Up the priority of anything that touches with display tasks // (this thread is UI thread, and io_thread_ is for IPCs). @@ -844,6 +893,7 @@ void BrowserMainLoop::BrowserThreadsStarted() { CAUSE_FOR_GPU_LAUNCH_BROWSER_STARTUP)); } #endif // !defined(OS_IOS) + return result_code_; } void BrowserMainLoop::InitializeToolkit() { diff --git a/content/browser/browser_main_loop.h b/content/browser/browser_main_loop.h index 5c3608bc87..7b2879f70e 100644 --- a/content/browser/browser_main_loop.h +++ b/content/browser/browser_main_loop.h @@ -6,8 +6,10 @@ #define CONTENT_BROWSER_BROWSER_MAIN_LOOP_H_ #include "base/basictypes.h" +#include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "content/browser/browser_process_sub_thread.h" +#include "content/public/browser/browser_main_runner.h" class CommandLine; @@ -65,8 +67,8 @@ class CONTENT_EXPORT BrowserMainLoop { void InitializeToolkit(); void MainMessageLoopStart(); - // Create all secondary threads. - void CreateThreads(); + // Create the tasks we need to complete startup. + void CreateStartupTasks(); // Perform the default message loop run logic. void RunMainMessageLoopParts(); @@ -94,8 +96,16 @@ class CONTENT_EXPORT BrowserMainLoop { void InitializeMainThread(); + // Called just before creating the threads + int PreCreateThreads(); + + // Create all secondary threads. + int CreateThreads(); + // Called right after the browser threads have been started. - void BrowserThreadsStarted(); + int BrowserThreadsStarted(); + + int PreMainMessageLoopRun(); void MainMessageLoopRun(); @@ -103,6 +113,8 @@ class CONTENT_EXPORT BrowserMainLoop { const MainFunctionParams& parameters_; const CommandLine& parsed_command_line_; int result_code_; + // True if the non-UI threads were created. + bool created_threads_; // Members initialized in |MainMessageLoopStart()| --------------------------- scoped_ptr<base::MessageLoop> main_message_loop_; diff --git a/content/browser/browser_main_runner.cc b/content/browser/browser_main_runner.cc index f50832af1b..cca1466d9b 100644 --- a/content/browser/browser_main_runner.cc +++ b/content/browser/browser_main_runner.cc @@ -29,11 +29,7 @@ namespace content { class BrowserMainRunnerImpl : public BrowserMainRunner { public: - BrowserMainRunnerImpl() - : is_initialized_(false), - is_shutdown_(false), - created_threads_(false) { - } + BrowserMainRunnerImpl() : is_initialized_(false), is_shutdown_(false) {} virtual ~BrowserMainRunnerImpl() { if (is_initialized_ && !is_shutdown_) @@ -102,11 +98,10 @@ class BrowserMainRunnerImpl : public BrowserMainRunner { #endif ui::InitializeInputMethod(); - main_loop_->CreateThreads(); + main_loop_->CreateStartupTasks(); int result_code = main_loop_->GetResultCode(); if (result_code > 0) return result_code; - created_threads_ = true; // Return -1 to indicate no early termination. return -1; @@ -124,8 +119,7 @@ class BrowserMainRunnerImpl : public BrowserMainRunner { DCHECK(!is_shutdown_); g_exited_main_message_loop = true; - if (created_threads_) - main_loop_->ShutdownThreadsAndCleanUp(); + main_loop_->ShutdownThreadsAndCleanUp(); ui::ShutdownInputMethod(); #if defined(OS_WIN) @@ -146,9 +140,6 @@ class BrowserMainRunnerImpl : public BrowserMainRunner { // True if the runner has been shut down. bool is_shutdown_; - // True if the non-UI threads were created. - bool created_threads_; - scoped_ptr<NotificationServiceImpl> notification_service_; scoped_ptr<BrowserMainLoop> main_loop_; #if defined(OS_WIN) diff --git a/content/browser/browser_plugin/browser_plugin_guest.cc b/content/browser/browser_plugin/browser_plugin_guest.cc index 23277d6cf6..7b6253d7dc 100644 --- a/content/browser/browser_plugin/browser_plugin_guest.cc +++ b/content/browser/browser_plugin/browser_plugin_guest.cc @@ -1417,9 +1417,12 @@ void BrowserPluginGuest::OnUnlockMouseAck(int instance_id) { void BrowserPluginGuest::OnUpdateRectACK( int instance_id, + bool needs_ack, const BrowserPluginHostMsg_AutoSize_Params& auto_size_params, const BrowserPluginHostMsg_ResizeGuest_Params& resize_guest_params) { - Send(new ViewMsg_UpdateRect_ACK(routing_id())); + // Only the software path expects an ACK. + if (needs_ack) + Send(new ViewMsg_UpdateRect_ACK(routing_id())); OnSetSize(instance_id_, auto_size_params, resize_guest_params); } @@ -1552,7 +1555,11 @@ bool BrowserPluginGuest::HandleJavaScriptDialog( return false; } -void BrowserPluginGuest::ResetJavaScriptState(WebContents* web_contents) { +void BrowserPluginGuest::CancelActiveAndPendingDialogs( + WebContents* web_contents) { +} + +void BrowserPluginGuest::WebContentsDestroyed(WebContents* web_contents) { } void BrowserPluginGuest::OnUpdateRect( diff --git a/content/browser/browser_plugin/browser_plugin_guest.h b/content/browser/browser_plugin/browser_plugin_guest.h index c9c7b6bd1f..7e1d1c00bd 100644 --- a/content/browser/browser_plugin/browser_plugin_guest.h +++ b/content/browser/browser_plugin/browser_plugin_guest.h @@ -222,7 +222,9 @@ class CONTENT_EXPORT BrowserPluginGuest virtual bool HandleJavaScriptDialog(WebContents* web_contents, bool accept, const string16* prompt_override) OVERRIDE; - virtual void ResetJavaScriptState(WebContents* web_contents) OVERRIDE; + virtual void CancelActiveAndPendingDialogs( + WebContents* web_contents) OVERRIDE; + virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE; // Exposes the protected web_contents() from WebContentsObserver. WebContentsImpl* GetWebContents(); @@ -410,6 +412,7 @@ class CONTENT_EXPORT BrowserPluginGuest void OnUpdateGeometry(int instance_id, const gfx::Rect& view_rect); void OnUpdateRectACK( int instance_id, + bool needs_ack, const BrowserPluginHostMsg_AutoSize_Params& auto_size_params, const BrowserPluginHostMsg_ResizeGuest_Params& resize_guest_params); diff --git a/content/browser/byte_stream.cc b/content/browser/byte_stream.cc index f83e8c3164..d1f5e175b2 100644 --- a/content/browser/byte_stream.cc +++ b/content/browser/byte_stream.cc @@ -55,7 +55,8 @@ class ByteStreamWriterImpl : public ByteStreamWriter { // Overridden from ByteStreamWriter. virtual bool Write(scoped_refptr<net::IOBuffer> buffer, size_t byte_count) OVERRIDE; - virtual void Close(DownloadInterruptReason status) OVERRIDE; + virtual void Flush() OVERRIDE; + virtual void Close(int status) OVERRIDE; virtual void RegisterCallback(const base::Closure& source_callback) OVERRIDE; // PostTask target from |ByteStreamReaderImpl::MaybeUpdateInput|. @@ -67,7 +68,7 @@ class ByteStreamWriterImpl : public ByteStreamWriter { // Called from UpdateWindow when object existence has been validated. void UpdateWindowInternal(size_t bytes_consumed); - void PostToPeer(bool complete, DownloadInterruptReason status); + void PostToPeer(bool complete, int status); const size_t total_buffer_size_; @@ -113,10 +114,10 @@ class ByteStreamReaderImpl : public ByteStreamReader { // Overridden from ByteStreamReader. virtual StreamState Read(scoped_refptr<net::IOBuffer>* data, size_t* length) OVERRIDE; - virtual DownloadInterruptReason GetStatus() const OVERRIDE; + virtual int GetStatus() const OVERRIDE; virtual void RegisterCallback(const base::Closure& sink_callback) OVERRIDE; - // PostTask target from |ByteStreamWriterImpl::MaybePostToPeer| and + // PostTask target from |ByteStreamWriterImpl::Write| and // |ByteStreamWriterImpl::Close|. // Receive data from our peer. // static because it may be called after the object it is targeting @@ -128,7 +129,7 @@ class ByteStreamReaderImpl : public ByteStreamReader { scoped_ptr<ContentVector> transfer_buffer, size_t transfer_buffer_bytes, bool source_complete, - DownloadInterruptReason status); + int status); private: // Called from TransferData once object existence has been validated. @@ -136,7 +137,7 @@ class ByteStreamReaderImpl : public ByteStreamReader { scoped_ptr<ContentVector> transfer_buffer, size_t transfer_buffer_bytes, bool source_complete, - DownloadInterruptReason status); + int status); void MaybeUpdateInput(); @@ -150,7 +151,7 @@ class ByteStreamReaderImpl : public ByteStreamReader { ContentVector available_contents_; bool received_status_; - DownloadInterruptReason status_; + int status_; base::Closure data_available_callback_; @@ -210,13 +211,18 @@ bool ByteStreamWriterImpl::Write( // Arbitrarily, we buffer to a third of the total size before sending. if (input_contents_size_ > total_buffer_size_ / kFractionBufferBeforeSending) - PostToPeer(false, DOWNLOAD_INTERRUPT_REASON_NONE); + PostToPeer(false, 0); return (input_contents_size_ + output_size_used_ <= total_buffer_size_); } -void ByteStreamWriterImpl::Close( - DownloadInterruptReason status) { +void ByteStreamWriterImpl::Flush() { + DCHECK(my_task_runner_->RunsTasksOnCurrentThread()); + if (input_contents_size_ > 0) + PostToPeer(false, 0); +} + +void ByteStreamWriterImpl::Close(int status) { DCHECK(my_task_runner_->RunsTasksOnCurrentThread()); PostToPeer(true, status); } @@ -252,8 +258,7 @@ void ByteStreamWriterImpl::UpdateWindowInternal(size_t bytes_consumed) { space_available_callback_.Run(); } -void ByteStreamWriterImpl::PostToPeer( - bool complete, DownloadInterruptReason status) { +void ByteStreamWriterImpl::PostToPeer(bool complete, int status) { DCHECK(my_task_runner_->RunsTasksOnCurrentThread()); // Valid contexts in which to call. DCHECK(complete || 0 != input_contents_size_); @@ -286,7 +291,7 @@ ByteStreamReaderImpl::ByteStreamReaderImpl( my_task_runner_(task_runner), my_lifetime_flag_(lifetime_flag), received_status_(false), - status_(DOWNLOAD_INTERRUPT_REASON_NONE), + status_(0), unreported_consumed_bytes_(0), peer_(NULL) { DCHECK(my_lifetime_flag_.get()); @@ -326,7 +331,7 @@ ByteStreamReaderImpl::Read(scoped_refptr<net::IOBuffer>* data, return STREAM_EMPTY; } -DownloadInterruptReason ByteStreamReaderImpl::GetStatus() const { +int ByteStreamReaderImpl::GetStatus() const { DCHECK(my_task_runner_->RunsTasksOnCurrentThread()); DCHECK(received_status_); return status_; @@ -346,7 +351,7 @@ void ByteStreamReaderImpl::TransferData( scoped_ptr<ContentVector> transfer_buffer, size_t buffer_size, bool source_complete, - DownloadInterruptReason status) { + int status) { // If our target is no longer alive, do nothing. if (!object_lifetime_flag->is_alive) return; @@ -358,7 +363,7 @@ void ByteStreamReaderImpl::TransferDataInternal( scoped_ptr<ContentVector> transfer_buffer, size_t buffer_size, bool source_complete, - DownloadInterruptReason status) { + int status) { DCHECK(my_task_runner_->RunsTasksOnCurrentThread()); bool was_empty = available_contents_.empty(); diff --git a/content/browser/byte_stream.h b/content/browser/byte_stream.h index 49b7674905..b16664f314 100644 --- a/content/browser/byte_stream.h +++ b/content/browser/byte_stream.h @@ -12,7 +12,7 @@ #include "base/callback.h" #include "base/memory/ref_counted.h" #include "base/synchronization/lock.h" -#include "content/public/browser/download_interrupt_reasons.h" +#include "content/common/content_export.h" #include "net/base/io_buffer.h" namespace base { @@ -33,8 +33,10 @@ namespace content { // and the sink retrieves bytes already written via |ByteStreamReader::Read|. // // When the source has no more data to add, it will call -// |ByteStreamWriter::Close| to indicate that. Errors at the source -// are indicated to the sink via a non-DOWNLOAD_INTERRUPT_REASON_NONE code. +// |ByteStreamWriter::Close| to indicate that. Operation status at the source +// is indicated to the sink via an int passed to the Close() method and returned +// from the GetStatus() method. Source and sink must agree on the interpretation +// of this int. // // Normally the source is not managed after the relationship is setup; // it is expected to provide data and then close itself. If an error @@ -113,7 +115,7 @@ namespace content { // } // // if (ByteStreamReader::STREAM_COMPLETE == state) { -// DownloadInterruptReason status = reader->GetStatus(); +// int status = reader->GetStatus(); // // Process error or successful completion in |status|. // } // @@ -121,7 +123,7 @@ namespace content { // // again when there's more data. // } class CONTENT_EXPORT ByteStreamWriter { -public: + public: // Inverse of the fraction of the stream buffer that must be full before // a notification is sent to paired Reader that there's more data. static const int kFractionBufferBeforeSending; @@ -134,10 +136,15 @@ public: virtual bool Write(scoped_refptr<net::IOBuffer> buffer, size_t byte_count) = 0; + // Flushes contents buffered in this writer to the corresponding reader + // regardless if buffer filling rate is greater than + // kFractionBufferBeforeSending or not. Does nothing if there's no contents + // buffered. + virtual void Flush() = 0; + // Signal that all data that is going to be sent, has been sent, - // and provide a status. |DOWNLOAD_INTERRUPT_REASON_NONE| should be - // passed for successful completion. - virtual void Close(DownloadInterruptReason status) = 0; + // and provide a status. + virtual void Close(int status) = 0; // Register a callback to be called when the stream transitions from // full to having space available. The callback will always be @@ -172,7 +179,7 @@ class CONTENT_EXPORT ByteStreamReader { size_t* length) = 0; // Only valid to call if Read() has returned STREAM_COMPLETE. - virtual DownloadInterruptReason GetStatus() const = 0; + virtual int GetStatus() const = 0; // Register a callback to be called when data is added or the source // completes. The callback will be always be called on the owning diff --git a/content/browser/byte_stream_unittest.cc b/content/browser/byte_stream_unittest.cc index ed413da8f3..925467c06a 100644 --- a/content/browser/byte_stream_unittest.cc +++ b/content/browser/byte_stream_unittest.cc @@ -115,7 +115,7 @@ TEST_F(ByteStreamTest, ByteStream_PushBack) { EXPECT_FALSE(Write(byte_stream_input.get(), 1)); EXPECT_FALSE(Write(byte_stream_input.get(), 1024)); // Flush - byte_stream_input->Close(DOWNLOAD_INTERRUPT_REASON_NONE); + byte_stream_input->Close(0); message_loop_.RunUntilIdle(); // Pull the IO buffers out; do we get the same buffers and do they @@ -146,6 +146,45 @@ TEST_F(ByteStreamTest, ByteStream_PushBack) { byte_stream_output->Read(&output_io_buffer, &output_length)); } +// Confirm that Flush() method makes the writer to send written contents to +// the reader. +TEST_F(ByteStreamTest, ByteStream_Flush) { + scoped_ptr<ByteStreamWriter> byte_stream_input; + scoped_ptr<ByteStreamReader> byte_stream_output; + CreateByteStream( + message_loop_.message_loop_proxy(), message_loop_.message_loop_proxy(), + 1024, &byte_stream_input, &byte_stream_output); + + EXPECT_TRUE(Write(byte_stream_input.get(), 1)); + message_loop_.RunUntilIdle(); + + scoped_refptr<net::IOBuffer> output_io_buffer; + size_t output_length = 0; + // Check that data is not sent to the reader yet. + EXPECT_EQ(ByteStreamReader::STREAM_EMPTY, + byte_stream_output->Read(&output_io_buffer, &output_length)); + + byte_stream_input->Flush(); + message_loop_.RunUntilIdle(); + + EXPECT_EQ(ByteStreamReader::STREAM_HAS_DATA, + byte_stream_output->Read(&output_io_buffer, &output_length)); + EXPECT_TRUE(ValidateIOBuffer(output_io_buffer, output_length)); + + // Check that it's ok to Flush() an empty writer. + byte_stream_input->Flush(); + message_loop_.RunUntilIdle(); + + EXPECT_EQ(ByteStreamReader::STREAM_EMPTY, + byte_stream_output->Read(&output_io_buffer, &output_length)); + + byte_stream_input->Close(0); + message_loop_.RunUntilIdle(); + + EXPECT_EQ(ByteStreamReader::STREAM_COMPLETE, + byte_stream_output->Read(&output_io_buffer, &output_length)); +} + // Same as above, only use knowledge of the internals to confirm // that we're getting pushback even when data's split across the two // objects @@ -212,12 +251,11 @@ TEST_F(ByteStreamTest, ByteStream_CompleteTransmits) { 3 * 1024, &byte_stream_input, &byte_stream_output); EXPECT_EQ(ByteStreamReader::STREAM_EMPTY, byte_stream_output->Read(&output_io_buffer, &output_length)); - byte_stream_input->Close(DOWNLOAD_INTERRUPT_REASON_NONE); + byte_stream_input->Close(0); message_loop_.RunUntilIdle(); ASSERT_EQ(ByteStreamReader::STREAM_COMPLETE, byte_stream_output->Read(&output_io_buffer, &output_length)); - EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, - byte_stream_output->GetStatus()); + EXPECT_EQ(0, byte_stream_output->GetStatus()); // Non-empty stream, non-error case. CreateByteStream( @@ -226,45 +264,44 @@ TEST_F(ByteStreamTest, ByteStream_CompleteTransmits) { EXPECT_EQ(ByteStreamReader::STREAM_EMPTY, byte_stream_output->Read(&output_io_buffer, &output_length)); EXPECT_TRUE(Write(byte_stream_input.get(), 1024)); - byte_stream_input->Close(DOWNLOAD_INTERRUPT_REASON_NONE); + byte_stream_input->Close(0); message_loop_.RunUntilIdle(); EXPECT_EQ(ByteStreamReader::STREAM_HAS_DATA, byte_stream_output->Read(&output_io_buffer, &output_length)); EXPECT_TRUE(ValidateIOBuffer(output_io_buffer, output_length)); ASSERT_EQ(ByteStreamReader::STREAM_COMPLETE, byte_stream_output->Read(&output_io_buffer, &output_length)); - EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, - byte_stream_output->GetStatus()); + EXPECT_EQ(0, byte_stream_output->GetStatus()); - // Empty stream, non-error case. + const int kFakeErrorCode = 22; + + // Empty stream, error case. CreateByteStream( message_loop_.message_loop_proxy(), message_loop_.message_loop_proxy(), 3 * 1024, &byte_stream_input, &byte_stream_output); EXPECT_EQ(ByteStreamReader::STREAM_EMPTY, byte_stream_output->Read(&output_io_buffer, &output_length)); - byte_stream_input->Close(DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED); + byte_stream_input->Close(kFakeErrorCode); message_loop_.RunUntilIdle(); ASSERT_EQ(ByteStreamReader::STREAM_COMPLETE, byte_stream_output->Read(&output_io_buffer, &output_length)); - EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, - byte_stream_output->GetStatus()); + EXPECT_EQ(kFakeErrorCode, byte_stream_output->GetStatus()); - // Non-empty stream, non-error case. + // Non-empty stream, error case. CreateByteStream( message_loop_.message_loop_proxy(), message_loop_.message_loop_proxy(), 3 * 1024, &byte_stream_input, &byte_stream_output); EXPECT_EQ(ByteStreamReader::STREAM_EMPTY, byte_stream_output->Read(&output_io_buffer, &output_length)); EXPECT_TRUE(Write(byte_stream_input.get(), 1024)); - byte_stream_input->Close(DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED); + byte_stream_input->Close(kFakeErrorCode); message_loop_.RunUntilIdle(); EXPECT_EQ(ByteStreamReader::STREAM_HAS_DATA, byte_stream_output->Read(&output_io_buffer, &output_length)); EXPECT_TRUE(ValidateIOBuffer(output_io_buffer, output_length)); ASSERT_EQ(ByteStreamReader::STREAM_COMPLETE, byte_stream_output->Read(&output_io_buffer, &output_length)); - EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, - byte_stream_output->GetStatus()); + EXPECT_EQ(kFakeErrorCode, byte_stream_output->GetStatus()); } // Confirm that callbacks on the sink side are triggered when they should be. @@ -499,7 +536,7 @@ TEST_F(ByteStreamTest, ByteStream_ZeroCallback) { base::Bind(CountCallbacks, &num_callbacks)); // Immediately close the stream. - byte_stream_input->Close(DOWNLOAD_INTERRUPT_REASON_NONE); + byte_stream_input->Close(0); task_runner->RunUntilIdle(); EXPECT_EQ(1, num_callbacks); } diff --git a/content/browser/device_orientation/data_fetcher_shared_memory.h b/content/browser/device_orientation/data_fetcher_shared_memory.h index 8168e87134..dc5e92ae16 100644 --- a/content/browser/device_orientation/data_fetcher_shared_memory.h +++ b/content/browser/device_orientation/data_fetcher_shared_memory.h @@ -14,31 +14,39 @@ class WebDeviceMotionData; namespace content { -class DataFetcherSharedMemory { +class CONTENT_EXPORT DataFetcherSharedMemory { public: - DataFetcherSharedMemory() : device_motion_buffer_(NULL) { } + DataFetcherSharedMemory() + : device_motion_buffer_(NULL), + started_(false) { } virtual ~DataFetcherSharedMemory(); // Returns true if this fetcher needs explicit calls to fetch the data. + // Called from any thread. virtual bool NeedsPolling(); // If this fetcher NeedsPolling() is true, this method will update the // buffer with the latest device motion data. - // This method will do nothing if NeedsPolling() is false. // Returns true if there was any motion data to update the buffer with. + // Called from the DeviceMotionProvider::PollingThread. virtual bool FetchDeviceMotionDataIntoBuffer(); // Returns true if the relevant sensors could be successfully activated. // This method should be called before any calls to // FetchDeviceMotionDataIntoBuffer(). + // If NeedsPolling() is true this method should be called from the + // PollingThread. virtual bool StartFetchingDeviceMotionData( DeviceMotionHardwareBuffer* buffer); // Indicates to the fetcher to stop fetching device data. + // If NeedsPolling() is true this method should be called from the + // PollingThread. virtual void StopFetchingDeviceMotionData(); private: DeviceMotionHardwareBuffer* device_motion_buffer_; + bool started_; DISALLOW_COPY_AND_ASSIGN(DataFetcherSharedMemory); }; diff --git a/content/browser/device_orientation/data_fetcher_shared_memory_android.cc b/content/browser/device_orientation/data_fetcher_shared_memory_android.cc index 5a87c6d32e..b051557670 100644 --- a/content/browser/device_orientation/data_fetcher_shared_memory_android.cc +++ b/content/browser/device_orientation/data_fetcher_shared_memory_android.cc @@ -10,7 +10,8 @@ namespace content { DataFetcherSharedMemory::~DataFetcherSharedMemory() { - StopFetchingDeviceMotionData(); + if (started_) + StopFetchingDeviceMotionData(); } bool DataFetcherSharedMemory::NeedsPolling() { @@ -24,13 +25,16 @@ bool DataFetcherSharedMemory::FetchDeviceMotionDataIntoBuffer() { bool DataFetcherSharedMemory::StartFetchingDeviceMotionData( DeviceMotionHardwareBuffer* buffer) { + DCHECK(buffer); device_motion_buffer_ = buffer; return DataFetcherImplAndroid::GetInstance()-> StartFetchingDeviceMotionData(buffer); + started_ = true; } void DataFetcherSharedMemory::StopFetchingDeviceMotionData() { - DataFetcherImplAndroid::GetInstance()->StopFetchingDeviceMotionData(); + DataFetcherImplAndroid::GetInstance()->StopFetchingDeviceMotionData(); + started_ = false; } } // namespace content diff --git a/content/browser/device_orientation/data_fetcher_shared_memory_default.cc b/content/browser/device_orientation/data_fetcher_shared_memory_default.cc index 819605cb8a..0f66fc7977 100644 --- a/content/browser/device_orientation/data_fetcher_shared_memory_default.cc +++ b/content/browser/device_orientation/data_fetcher_shared_memory_default.cc @@ -9,7 +9,8 @@ namespace content { DataFetcherSharedMemory::~DataFetcherSharedMemory() { - StopFetchingDeviceMotionData(); + if (started_) + StopFetchingDeviceMotionData(); } bool DataFetcherSharedMemory::NeedsPolling() { @@ -24,9 +25,11 @@ bool DataFetcherSharedMemory::FetchDeviceMotionDataIntoBuffer() { bool DataFetcherSharedMemory::StartFetchingDeviceMotionData( DeviceMotionHardwareBuffer* buffer) { DCHECK(buffer); + device_motion_buffer_ = buffer; device_motion_buffer_->seqlock.WriteBegin(); device_motion_buffer_->data.allAvailableSensorsAreActive = true; device_motion_buffer_->seqlock.WriteEnd(); + started_ = true; return true; } @@ -34,6 +37,7 @@ void DataFetcherSharedMemory::StopFetchingDeviceMotionData() { device_motion_buffer_->seqlock.WriteBegin(); device_motion_buffer_->data.allAvailableSensorsAreActive = false; device_motion_buffer_->seqlock.WriteEnd(); + started_ = false; } } // namespace content diff --git a/content/browser/device_orientation/device_motion_provider.cc b/content/browser/device_orientation/device_motion_provider.cc index 84f65cabd1..e88d5af83f 100644 --- a/content/browser/device_orientation/device_motion_provider.cc +++ b/content/browser/device_orientation/device_motion_provider.cc @@ -4,14 +4,95 @@ #include "content/browser/device_orientation/device_motion_provider.h" +#include "base/bind.h" #include "base/logging.h" +#include "base/threading/thread.h" +#include "base/timer/timer.h" #include "content/browser/device_orientation/data_fetcher_shared_memory.h" #include "content/common/device_motion_hardware_buffer.h" namespace content { +namespace { +const int kPeriodInMilliseconds = 100; +} + +class DeviceMotionProvider::PollingThread : public base::Thread { + public: + explicit PollingThread(const char* name); + virtual ~PollingThread(); + + void StartPolling(DataFetcherSharedMemory* fetcher, + DeviceMotionHardwareBuffer* buffer); + void StopPolling(); + + private: + void DoPoll(); + + scoped_ptr<base::RepeatingTimer<PollingThread> > timer_; + DataFetcherSharedMemory* fetcher_; + + DISALLOW_COPY_AND_ASSIGN(PollingThread); +}; + +// ---- PollingThread methods + +DeviceMotionProvider::PollingThread::PollingThread(const char* name) + : base::Thread(name) { +} + +DeviceMotionProvider::PollingThread::~PollingThread() { +} + +void DeviceMotionProvider::PollingThread::StartPolling( + DataFetcherSharedMemory* fetcher, DeviceMotionHardwareBuffer* buffer) { + DCHECK(base::MessageLoop::current() == message_loop()); + DCHECK(!timer_); + + fetcher_ = fetcher; + fetcher_->StartFetchingDeviceMotionData(buffer); + timer_.reset(new base::RepeatingTimer<PollingThread>()); + timer_->Start(FROM_HERE, + base::TimeDelta::FromMilliseconds(kPeriodInMilliseconds), + this, &PollingThread::DoPoll); +} + +void DeviceMotionProvider::PollingThread::StopPolling() { + DCHECK(base::MessageLoop::current() == message_loop()); + DCHECK(fetcher_); + // this will also stop the timer before killing it. + timer_.reset(); + fetcher_->StopFetchingDeviceMotionData(); +} + +void DeviceMotionProvider::PollingThread::DoPoll() { + DCHECK(base::MessageLoop::current() == message_loop()); + fetcher_->FetchDeviceMotionDataIntoBuffer(); +} + +// ---- end PollingThread methods + DeviceMotionProvider::DeviceMotionProvider() : is_started_(false) { + Initialize(); +} + +DeviceMotionProvider::DeviceMotionProvider( + scoped_ptr<DataFetcherSharedMemory> fetcher) + : is_started_(false) { + data_fetcher_ = fetcher.Pass(); + Initialize(); +} + +DeviceMotionProvider::~DeviceMotionProvider() { + StopFetchingDeviceMotionData(); + // make sure polling thread stops before data_fetcher_ gets deleted. + if (polling_thread_) + polling_thread_->Stop(); + data_fetcher_.reset(); +} + +void DeviceMotionProvider::Initialize() { size_t data_size = sizeof(DeviceMotionHardwareBuffer); bool res = device_motion_shared_memory_.CreateAndMapAnonymous(data_size); // TODO(timvolodine): consider not crashing the browser if the check fails. @@ -20,9 +101,6 @@ DeviceMotionProvider::DeviceMotionProvider() memset(hwbuf, 0, sizeof(DeviceMotionHardwareBuffer)); } -DeviceMotionProvider::~DeviceMotionProvider() { -} - base::SharedMemoryHandle DeviceMotionProvider::GetSharedMemoryHandleForProcess( base::ProcessHandle process) { base::SharedMemoryHandle renderer_handle; @@ -33,20 +111,59 @@ base::SharedMemoryHandle DeviceMotionProvider::GetSharedMemoryHandleForProcess( void DeviceMotionProvider::StartFetchingDeviceMotionData() { if (is_started_) return; + if (!data_fetcher_) data_fetcher_.reset(new DataFetcherSharedMemory); - data_fetcher_->StartFetchingDeviceMotionData(SharedMemoryAsHardwareBuffer()); + + if (data_fetcher_->NeedsPolling()) { + if (!polling_thread_) + CreateAndStartPollingThread(); + + polling_thread_->message_loop()->PostTask( + FROM_HERE, + base::Bind(&PollingThread::StartPolling, + base::Unretained(polling_thread_.get()), + data_fetcher_.get(), + SharedMemoryAsHardwareBuffer())); + } else { + data_fetcher_->StartFetchingDeviceMotionData( + SharedMemoryAsHardwareBuffer()); + } + is_started_ = true; } +void DeviceMotionProvider::CreateAndStartPollingThread() { + polling_thread_.reset( + new PollingThread("Device Motion poller")); + + if (!polling_thread_->Start()) { + LOG(ERROR) << "Failed to start Device Motion data polling thread"; + return; + } +} + void DeviceMotionProvider::StopFetchingDeviceMotionData() { - if (data_fetcher_) + if (!is_started_) + return; + + DCHECK(data_fetcher_); + + if (data_fetcher_->NeedsPolling()) { + DCHECK(polling_thread_); + polling_thread_->message_loop()->PostTask( + FROM_HERE, + base::Bind(&PollingThread::StopPolling, + base::Unretained(polling_thread_.get()))); + } else { data_fetcher_->StopFetchingDeviceMotionData(); + } + is_started_ = false; } -DeviceMotionHardwareBuffer* DeviceMotionProvider:: - SharedMemoryAsHardwareBuffer() { +DeviceMotionHardwareBuffer* +DeviceMotionProvider::SharedMemoryAsHardwareBuffer() { void* mem = device_motion_shared_memory_.memory(); CHECK(mem); return static_cast<DeviceMotionHardwareBuffer*>(mem); diff --git a/content/browser/device_orientation/device_motion_provider.h b/content/browser/device_orientation/device_motion_provider.h index 90588dac58..8fd36de33d 100644 --- a/content/browser/device_orientation/device_motion_provider.h +++ b/content/browser/device_orientation/device_motion_provider.h @@ -13,9 +13,18 @@ namespace content { class DataFetcherSharedMemory; +// This class owns the shared memory buffer for Device Motion and makes +// sure the data is fetched into that buffer. +// When DataFetcherSharedMemory::NeedsPolling() is true, it starts a +// background polling thread to make sure the data is fetched at regular +// intervals. class CONTENT_EXPORT DeviceMotionProvider { public: DeviceMotionProvider(); + + // Creates provider with a custom fetcher. Used for testing. + explicit DeviceMotionProvider(scoped_ptr<DataFetcherSharedMemory> fetcher); + virtual ~DeviceMotionProvider(); // Returns the shared memory handle of the device motion data duplicated @@ -23,18 +32,20 @@ class CONTENT_EXPORT DeviceMotionProvider { base::SharedMemoryHandle GetSharedMemoryHandleForProcess( base::ProcessHandle renderer_process); - // Pause and resume the background polling thread. Can be called from any - // thread. void StartFetchingDeviceMotionData(); void StopFetchingDeviceMotionData(); private: - base::SharedMemory device_motion_shared_memory_; + class PollingThread; + + void Initialize(); + void CreateAndStartPollingThread(); DeviceMotionHardwareBuffer* SharedMemoryAsHardwareBuffer(); + base::SharedMemory device_motion_shared_memory_; scoped_ptr<DataFetcherSharedMemory> data_fetcher_; - + scoped_ptr<PollingThread> polling_thread_; bool is_started_; DISALLOW_COPY_AND_ASSIGN(DeviceMotionProvider); diff --git a/content/browser/device_orientation/device_motion_provider_unittest.cc b/content/browser/device_orientation/device_motion_provider_unittest.cc new file mode 100644 index 0000000000..cd0f3d843e --- /dev/null +++ b/content/browser/device_orientation/device_motion_provider_unittest.cc @@ -0,0 +1,98 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/device_orientation/device_motion_provider.h" + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/synchronization/waitable_event.h" +#include "content/browser/device_orientation/data_fetcher_shared_memory.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace content { + +namespace { + +const int kPeriodInMilliseconds = 100; + +class FakeDataFetcherSharedMemory : public DataFetcherSharedMemory { + public: + FakeDataFetcherSharedMemory() + : start_fetching_data_(false, false), + stop_fetching_data_(false, false), + fetched_data_(false, false) { + } + virtual ~FakeDataFetcherSharedMemory() { } + + virtual bool NeedsPolling() OVERRIDE { + return true; + } + + virtual bool FetchDeviceMotionDataIntoBuffer() OVERRIDE { + buffer_->seqlock.WriteBegin(); + buffer_->data.interval = kPeriodInMilliseconds; + buffer_->seqlock.WriteEnd(); + fetched_data_.Signal(); + return true; + } + + virtual bool StartFetchingDeviceMotionData( + DeviceMotionHardwareBuffer* buffer) OVERRIDE { + buffer_ = buffer; + start_fetching_data_.Signal(); + return true; + } + + virtual void StopFetchingDeviceMotionData() OVERRIDE { + stop_fetching_data_.Signal(); + } + + void WaitForStart() { + start_fetching_data_.Wait(); + } + + void WaitForStop() { + stop_fetching_data_.Wait(); + } + + void WaitForDataFetch() { + fetched_data_.Wait(); + } + + DeviceMotionHardwareBuffer* GetBuffer() { + return buffer_; + } + + private: + base::WaitableEvent start_fetching_data_; + base::WaitableEvent stop_fetching_data_; + base::WaitableEvent fetched_data_; + DeviceMotionHardwareBuffer* buffer_; + + DISALLOW_COPY_AND_ASSIGN(FakeDataFetcherSharedMemory); +}; + + +TEST(DeviceMotionProviderTest, DoesPolling) { + FakeDataFetcherSharedMemory* mock_data_fetcher = + new FakeDataFetcherSharedMemory(); + EXPECT_TRUE(mock_data_fetcher->NeedsPolling()); + + scoped_ptr<DeviceMotionProvider> provider(new DeviceMotionProvider( + scoped_ptr<DataFetcherSharedMemory>(mock_data_fetcher))); + + provider->StartFetchingDeviceMotionData(); + mock_data_fetcher->WaitForStart(); + mock_data_fetcher->WaitForDataFetch(); + + EXPECT_EQ(kPeriodInMilliseconds, + mock_data_fetcher->GetBuffer()->data.interval); + + provider->StopFetchingDeviceMotionData(); + mock_data_fetcher->WaitForStop(); +} + +} // namespace + +} // namespace content diff --git a/content/browser/device_orientation/motion.cc b/content/browser/device_orientation/motion.cc deleted file mode 100644 index d5985e66a1..0000000000 --- a/content/browser/device_orientation/motion.cc +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/device_orientation/motion.h" - -#include "content/common/device_motion_messages.h" - -namespace content { - -Motion::Motion() - : can_provide_acceleration_x_(false), - can_provide_acceleration_y_(false), - can_provide_acceleration_z_(false), - can_provide_acceleration_including_gravity_x_(false), - can_provide_acceleration_including_gravity_y_(false), - can_provide_acceleration_including_gravity_z_(false), - can_provide_rotation_rate_alpha_(false), - can_provide_rotation_rate_beta_(false), - can_provide_rotation_rate_gamma_(false), - can_provide_interval_(false) { -} - -Motion::~Motion() { -} - -IPC::Message* Motion::CreateIPCMessage(int render_view_id) const { - DeviceMotionMsg_Updated_Params params; - - params.can_provide_acceleration_x = can_provide_acceleration_x_; - params.acceleration_x = acceleration_x_; - params.can_provide_acceleration_y = can_provide_acceleration_y_; - params.acceleration_y = acceleration_y_; - params.can_provide_acceleration_z = can_provide_acceleration_z_; - params.acceleration_z = acceleration_z_; - - params.can_provide_acceleration_including_gravity_x = - can_provide_acceleration_including_gravity_x_; - params.acceleration_including_gravity_x = acceleration_including_gravity_x_; - params.can_provide_acceleration_including_gravity_y = - can_provide_acceleration_including_gravity_y_; - params.acceleration_including_gravity_y = acceleration_including_gravity_y_; - params.can_provide_acceleration_including_gravity_z = - can_provide_acceleration_including_gravity_z_; - params.acceleration_including_gravity_z = acceleration_including_gravity_z_; - - params.can_provide_rotation_rate_alpha = can_provide_rotation_rate_alpha_; - params.rotation_rate_alpha = rotation_rate_alpha_; - params.can_provide_rotation_rate_beta = can_provide_rotation_rate_beta_; - params.rotation_rate_beta = rotation_rate_beta_; - params.can_provide_rotation_rate_gamma = can_provide_rotation_rate_gamma_; - params.rotation_rate_gamma = rotation_rate_gamma_; - - params.can_provide_interval = can_provide_interval_; - params.interval = interval_; - - return new DeviceMotionMsg_Updated(render_view_id, params); -} - -// Should always fire new motion events so that they occur at regular intervals. -// The firing frequency is determined by the polling frequency in ProviderImpl. -bool Motion::ShouldFireEvent(const DeviceData* old_data) const { - return true; -} - -}; // namespace content diff --git a/content/browser/device_orientation/motion.h b/content/browser/device_orientation/motion.h deleted file mode 100644 index 8027254b99..0000000000 --- a/content/browser/device_orientation/motion.h +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_DEVICE_ORIENTATION_MOTION_H_ -#define CONTENT_BROWSER_DEVICE_ORIENTATION_MOTION_H_ - -#include "base/compiler_specific.h" -#include "content/browser/device_orientation/device_data.h" -#include "content/common/content_export.h" - -namespace content { - -class Motion : public DeviceData { - public: - // acceleration_x, acceleration_y, and acceleration_z are the accelerations - // excluding gravity along the axes specified in - // http://dev.w3.org/geo/api/spec-source-orientation.html - - // acceleration_including_gravity_x, acceleration_including_gravity_y, and - // acceleration_including_gravity_z are the accelerations including gravity - // along the same axes as above - - // rotation_rate_alpha, rotation_rate_beta, and rotataion_rate_gamma are the - // rotations around the same axes as above - - // interval is the time interval at which data is obtained from the hardware, - // as specified in the document referenced above - - // can_provide_{acceleration_x, acceleration_y, acceleration_z, - // acceleration_including_gravity_x, acceleration_including_gravity_y, - // acceleration_including_gravity_z, rotation_rate_alpha, rotation_rate_beta, - // rotation_rate_gamma, interval} is true if data can be provided for that - // variable - CONTENT_EXPORT Motion(); - - // From DeviceData. - virtual IPC::Message* CreateIPCMessage(int render_view_id) const OVERRIDE; - virtual bool ShouldFireEvent(const DeviceData* old_data) const OVERRIDE; - - void set_acceleration_x(double acceleration_x) { - can_provide_acceleration_x_ = true; - acceleration_x_ = acceleration_x; - } - bool can_provide_acceleration_x() const { - return can_provide_acceleration_x_; - } - double acceleration_x() const { return acceleration_x_; } - - void set_acceleration_y(double acceleration_y) { - can_provide_acceleration_y_ = true; - acceleration_y_ = acceleration_y; - } - bool can_provide_acceleration_y() const { - return can_provide_acceleration_y_; - } - double acceleration_y() const { return acceleration_y_; } - - void set_acceleration_z(double acceleration_z) { - can_provide_acceleration_z_ = true; - acceleration_z_ = acceleration_z; - } - bool can_provide_acceleration_z() const { - return can_provide_acceleration_z_; - } - double acceleration_z() const { return acceleration_z_; } - - void set_acceleration_including_gravity_x( - double acceleration_including_gravity_x) { - can_provide_acceleration_including_gravity_x_ = true; - acceleration_including_gravity_x_ = acceleration_including_gravity_x; - } - bool can_provide_acceleration_including_gravity_x() const { - return can_provide_acceleration_x_; - } - double acceleration_including_gravity_x() const { - return acceleration_including_gravity_x_; - } - - void set_acceleration_including_gravity_y( - double acceleration_including_gravity_y) { - can_provide_acceleration_including_gravity_y_ = true; - acceleration_including_gravity_y_ = acceleration_including_gravity_y; - } - bool can_provide_acceleration_including_gravity_y() const { - return can_provide_acceleration_y_; - } - double acceleration_including_gravity_y() const { - return acceleration_including_gravity_y_; - } - - void set_acceleration_including_gravity_z( - double acceleration_including_gravity_z) { - can_provide_acceleration_including_gravity_z_ = true; - acceleration_including_gravity_z_ = acceleration_including_gravity_z; - } - bool can_provide_acceleration_including_gravity_z() const { - return can_provide_acceleration_z_; - } - double acceleration_including_gravity_z() const { - return acceleration_including_gravity_z_; - } - - void set_rotation_rate_alpha(double rotation_rate_alpha) { - can_provide_rotation_rate_alpha_ = true; - rotation_rate_alpha_ = rotation_rate_alpha; - } - bool can_provide_rotation_rate_alpha() const { - return can_provide_rotation_rate_alpha_; - } - double rotation_rate_alpha() const { return rotation_rate_alpha_; } - - void set_rotation_rate_beta(double rotation_rate_beta) { - can_provide_rotation_rate_beta_ = true; - rotation_rate_beta_ = rotation_rate_beta; - } - bool can_provide_rotation_rate_beta() const { - return can_provide_rotation_rate_beta_; - } - double rotation_rate_beta() const { return rotation_rate_beta_; } - - void set_rotation_rate_gamma(double rotation_rate_gamma) { - can_provide_rotation_rate_gamma_ = true; - rotation_rate_gamma_ = rotation_rate_gamma; - } - bool can_provide_rotation_rate_gamma() const { - return can_provide_rotation_rate_gamma_; - } - double rotation_rate_gamma() const { return rotation_rate_gamma_; } - - void set_interval(double interval) { - can_provide_interval_ = true; - interval_ = interval; - } - bool can_provide_interval() const { return can_provide_interval_; } - double interval() const { return interval_; } - - private: - virtual ~Motion(); - - double acceleration_x_; - double acceleration_y_; - double acceleration_z_; - double acceleration_including_gravity_x_; - double acceleration_including_gravity_y_; - double acceleration_including_gravity_z_; - double rotation_rate_alpha_; - double rotation_rate_beta_; - double rotation_rate_gamma_; - double interval_; - bool can_provide_acceleration_x_; - bool can_provide_acceleration_y_; - bool can_provide_acceleration_z_; - bool can_provide_acceleration_including_gravity_x_; - bool can_provide_acceleration_including_gravity_y_; - bool can_provide_acceleration_including_gravity_z_; - bool can_provide_rotation_rate_alpha_; - bool can_provide_rotation_rate_beta_; - bool can_provide_rotation_rate_gamma_; - bool can_provide_interval_; -}; - -} // namespace content - -#endif // CONTENT_BROWSER_DEVICE_ORIENTATION_MOTION_H_ diff --git a/content/browser/device_orientation/motion_message_filter.cc b/content/browser/device_orientation/motion_message_filter.cc deleted file mode 100644 index e837ed3b82..0000000000 --- a/content/browser/device_orientation/motion_message_filter.cc +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/device_orientation/motion_message_filter.h" - -#include "content/browser/device_orientation/device_data.h" -#include "content/common/device_motion_messages.h" -#include "content/public/browser/browser_thread.h" - -namespace content { - -MotionMessageFilter::MotionMessageFilter() - : DeviceOrientationMessageFilter(DeviceData::kTypeMotion) { -} - -MotionMessageFilter::~MotionMessageFilter() { -} - -bool MotionMessageFilter::OnMessageReceived(const IPC::Message& message, - bool* message_was_ok) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - bool handled = true; - IPC_BEGIN_MESSAGE_MAP_EX(MotionMessageFilter, message, *message_was_ok) - IPC_MESSAGE_HANDLER(DeviceMotionHostMsg_StartUpdating, OnStartUpdating) - IPC_MESSAGE_HANDLER(DeviceMotionHostMsg_StopUpdating, OnStopUpdating) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -} // namespace content diff --git a/content/browser/device_orientation/motion_message_filter.h b/content/browser/device_orientation/motion_message_filter.h deleted file mode 100644 index cc50f6765f..0000000000 --- a/content/browser/device_orientation/motion_message_filter.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_DEVICE_ORIENTATION_MOTION_MESSAGE_FILTER_H_ -#define CONTENT_BROWSER_DEVICE_ORIENTATION_MOTION_MESSAGE_FILTER_H_ - -#include <map> - -#include "content/browser/device_orientation/message_filter.h" - -namespace content { - -class MotionMessageFilter : public DeviceOrientationMessageFilter { - public: - MotionMessageFilter(); - - // DeviceOrientationMessageFilter implementation. - virtual bool OnMessageReceived(const IPC::Message& message, - bool* message_was_ok) OVERRIDE; - - private: - virtual ~MotionMessageFilter(); - - DISALLOW_COPY_AND_ASSIGN(MotionMessageFilter); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_DEVICE_ORIENTATION_MOTION_MESSAGE_FILTER_H_ diff --git a/content/browser/device_orientation/observer_delegate.cc b/content/browser/device_orientation/observer_delegate.cc index 1ffe07a774..5c233109dd 100644 --- a/content/browser/device_orientation/observer_delegate.cc +++ b/content/browser/device_orientation/observer_delegate.cc @@ -6,7 +6,6 @@ #include "base/logging.h" #include "content/browser/device_orientation/device_data.h" -#include "content/browser/device_orientation/motion.h" #include "content/browser/device_orientation/orientation.h" #include "ipc/ipc_sender.h" @@ -37,10 +36,9 @@ void ObserverDelegate::OnDeviceDataUpdate( DeviceData* ObserverDelegate::EmptyDeviceData(DeviceData::Type type) { switch (type) { - case DeviceData::kTypeMotion: - return new Motion(); case DeviceData::kTypeOrientation: return new Orientation(); + case DeviceData::kTypeMotion: case DeviceData::kTypeTest: NOTREACHED(); } diff --git a/content/browser/device_orientation/provider_unittest.cc b/content/browser/device_orientation/provider_unittest.cc index cc502486ef..1f310ea3ad 100644 --- a/content/browser/device_orientation/provider_unittest.cc +++ b/content/browser/device_orientation/provider_unittest.cc @@ -9,7 +9,6 @@ #include "base/synchronization/lock.h" #include "content/browser/device_orientation/data_fetcher.h" #include "content/browser/device_orientation/device_data.h" -#include "content/browser/device_orientation/motion.h" #include "content/browser/device_orientation/orientation.h" #include "content/browser/device_orientation/provider.h" #include "content/browser/device_orientation/provider_impl.h" @@ -71,91 +70,6 @@ class UpdateChecker : public Provider::Observer { std::queue<scoped_refptr<const DeviceData> > expectations_queue_; }; -// Class for checking expectations on motion updates from the Provider. -class MotionUpdateChecker : public UpdateChecker { - public: - explicit MotionUpdateChecker(int* expectations_count_ptr) - : UpdateChecker(DeviceData::kTypeMotion, expectations_count_ptr) { - } - - virtual ~MotionUpdateChecker() {} - - // From UpdateChecker. - virtual void OnDeviceDataUpdate(const DeviceData* device_data, - DeviceData::Type device_data_type) OVERRIDE { - ASSERT_FALSE(expectations_queue_.empty()); - ASSERT_EQ(DeviceData::kTypeMotion, device_data_type); - - scoped_refptr<const Motion> motion(static_cast<const Motion*>(device_data)); - if (motion.get() == NULL) - motion = new Motion(); - - scoped_refptr<const Motion> expected(static_cast<const Motion*>( - (expectations_queue_.front().get()))); - expectations_queue_.pop(); - - EXPECT_EQ(expected->can_provide_acceleration_x(), - motion->can_provide_acceleration_x()); - EXPECT_EQ(expected->can_provide_acceleration_y(), - motion->can_provide_acceleration_y()); - EXPECT_EQ(expected->can_provide_acceleration_z(), - motion->can_provide_acceleration_z()); - - EXPECT_EQ(expected->can_provide_acceleration_including_gravity_x(), - motion->can_provide_acceleration_including_gravity_x()); - EXPECT_EQ(expected->can_provide_acceleration_including_gravity_y(), - motion->can_provide_acceleration_including_gravity_y()); - EXPECT_EQ(expected->can_provide_acceleration_including_gravity_z(), - motion->can_provide_acceleration_including_gravity_z()); - - EXPECT_EQ(expected->can_provide_rotation_rate_alpha(), - motion->can_provide_rotation_rate_alpha()); - EXPECT_EQ(expected->can_provide_rotation_rate_beta(), - motion->can_provide_rotation_rate_beta()); - EXPECT_EQ(expected->can_provide_rotation_rate_gamma(), - motion->can_provide_rotation_rate_gamma()); - - EXPECT_EQ(expected->can_provide_interval(), motion->can_provide_interval()); - - if (expected->can_provide_acceleration_x()) - EXPECT_EQ(expected->acceleration_x(), motion->acceleration_x()); - if (expected->can_provide_acceleration_y()) - EXPECT_EQ(expected->acceleration_y(), motion->acceleration_y()); - if (expected->can_provide_acceleration_z()) - EXPECT_EQ(expected->acceleration_z(), motion->acceleration_z()); - - if (expected->can_provide_acceleration_including_gravity_x()) - EXPECT_EQ(expected->acceleration_including_gravity_x(), - motion->acceleration_including_gravity_x()); - if (expected->can_provide_acceleration_including_gravity_y()) - EXPECT_EQ(expected->acceleration_including_gravity_y(), - motion->acceleration_including_gravity_y()); - if (expected->can_provide_acceleration_including_gravity_z()) - EXPECT_EQ(expected->acceleration_including_gravity_z(), - motion->acceleration_including_gravity_z()); - - if (expected->can_provide_rotation_rate_alpha()) - EXPECT_EQ(expected->rotation_rate_alpha(), - motion->rotation_rate_alpha()); - if (expected->can_provide_rotation_rate_beta()) - EXPECT_EQ(expected->rotation_rate_beta(), - motion->rotation_rate_beta()); - if (expected->can_provide_rotation_rate_gamma()) - EXPECT_EQ(expected->rotation_rate_gamma(), - motion->rotation_rate_gamma()); - - if (expected->can_provide_interval()) - EXPECT_EQ(expected->interval(), motion->interval()); - - --(*expectations_count_ptr_); - - if (*expectations_count_ptr_ == 0) { - base::MessageLoop::current()->PostTask(FROM_HERE, - base::MessageLoop::QuitClosure()); - } - } -}; - // Class for checking expectations on orientation updates from the Provider. class OrientationUpdateChecker : public UpdateChecker { public: @@ -612,44 +526,6 @@ TEST_F(DeviceOrientationProviderTest, StartStopStart) { MockDeviceDataFactory::SetCurInstance(NULL); } -// Tests that Motion events always fire, even if the motion is unchanged. -TEST_F(DeviceOrientationProviderTest, FLAKY_MotionAlwaysFires) { - scoped_refptr<MockDeviceDataFactory> device_data_factory( - new MockDeviceDataFactory()); - MockDeviceDataFactory::SetCurInstance(device_data_factory.get()); - Init(MockDeviceDataFactory::CreateDataFetcher); - - scoped_refptr<Motion> test_motion(new Motion()); - test_motion->set_acceleration_x(1); - test_motion->set_acceleration_y(2); - test_motion->set_acceleration_z(3); - test_motion->set_acceleration_including_gravity_x(4); - test_motion->set_acceleration_including_gravity_y(5); - test_motion->set_acceleration_including_gravity_z(6); - test_motion->set_rotation_rate_alpha(7); - test_motion->set_rotation_rate_beta(8); - test_motion->set_rotation_rate_gamma(9); - test_motion->set_interval(10); - - scoped_ptr<MotionUpdateChecker> checker(new MotionUpdateChecker( - &pending_expectations_)); - - device_data_factory->SetDeviceData(test_motion.get(), - DeviceData::kTypeMotion); - checker->AddExpectation(test_motion.get()); - provider_->AddObserver(checker.get()); - base::MessageLoop::current()->Run(); - - // The observer should receive the same motion again. - device_data_factory->SetDeviceData(test_motion.get(), - DeviceData::kTypeMotion); - checker->AddExpectation(test_motion.get()); - base::MessageLoop::current()->Run(); - - provider_->RemoveObserver(checker.get()); - MockDeviceDataFactory::SetCurInstance(NULL); -} - // Tests that Orientation events only fire if the change is significant. TEST_F(DeviceOrientationProviderTest, OrientationSignificantlyDifferent) { scoped_refptr<MockDeviceDataFactory> device_data_factory( diff --git a/content/browser/devtools/devtools_http_handler_impl.cc b/content/browser/devtools/devtools_http_handler_impl.cc index 6afc65d6dd..0893547f3f 100644 --- a/content/browser/devtools/devtools_http_handler_impl.cc +++ b/content/browser/devtools/devtools_http_handler_impl.cc @@ -542,7 +542,7 @@ void DevToolsHttpHandlerImpl::OnJsonRequestUI( std::sort(page_list.begin(), page_list.end(), TimeComparator); base::ListValue* target_list = new base::ListValue(); - std::string host = info.headers["Host"]; + std::string host = info.headers["host"]; for (PageList::iterator i = page_list.begin(); i != page_list.end(); ++i) target_list->Append(SerializePageInfo(i->first, host)); @@ -570,7 +570,7 @@ void DevToolsHttpHandlerImpl::OnJsonRequestUI( "Could not create new page"); return; } - std::string host = info.headers["Host"]; + std::string host = info.headers["host"]; scoped_ptr<base::DictionaryValue> dictionary(SerializePageInfo(rvh, host)); SendJson(connection_id, net::HTTP_OK, dictionary.get(), std::string()); return; diff --git a/content/browser/download/download_file_impl.cc b/content/browser/download/download_file_impl.cc index edd7fed527..bbe317b13a 100644 --- a/content/browser/download/download_file_impl.cc +++ b/content/browser/download/download_file_impl.cc @@ -232,7 +232,8 @@ void DownloadFileImpl::StreamActive() { break; case ByteStreamReader::STREAM_COMPLETE: { - reason = stream_reader_->GetStatus(); + reason = static_cast<DownloadInterruptReason>( + stream_reader_->GetStatus()); SendUpdate(); base::TimeTicks close_start(base::TimeTicks::Now()); file_.Finish(); diff --git a/content/browser/download/download_file_unittest.cc b/content/browser/download/download_file_unittest.cc index a3aafffbcc..ebf501d92c 100644 --- a/content/browser/download/download_file_unittest.cc +++ b/content/browser/download/download_file_unittest.cc @@ -41,7 +41,7 @@ class MockByteStreamReader : public ByteStreamReader { // ByteStream functions MOCK_METHOD2(Read, ByteStreamReader::StreamState( scoped_refptr<net::IOBuffer>*, size_t*)); - MOCK_CONST_METHOD0(GetStatus, DownloadInterruptReason()); + MOCK_CONST_METHOD0(GetStatus, int()); MOCK_METHOD1(RegisterCallback, void(const base::Closure&)); }; diff --git a/content/browser/download/download_item_impl.cc b/content/browser/download/download_item_impl.cc index b49a256f31..e54ab9e90b 100644 --- a/content/browser/download/download_item_impl.cc +++ b/content/browser/download/download_item_impl.cc @@ -1398,6 +1398,8 @@ void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) { TransitionTo(INTERRUPTED_INTERNAL, DONT_UPDATE_OBSERVERS); RecordDownloadInterrupted(reason, received_bytes_, total_bytes_); + if (!GetWebContents()) + RecordDownloadCount(INTERRUPTED_WITHOUT_WEBCONTENTS); AutoResumeIfValid(); UpdateObservers(); diff --git a/content/browser/download/download_item_impl_unittest.cc b/content/browser/download/download_item_impl_unittest.cc index 7d348372c2..ff5d32602f 100644 --- a/content/browser/download/download_item_impl_unittest.cc +++ b/content/browser/download/download_item_impl_unittest.cc @@ -496,7 +496,7 @@ TEST_F(DownloadItemTest, LimitRestartsAfterInterrupted) { // to be callled, so we simply verify that GetWebContents() is called. if (i < (DownloadItemImpl::kMaxAutoResumeAttempts - 1)) { EXPECT_CALL(*mock_request_handle, GetWebContents()) - .WillOnce(Return(static_cast<WebContents*>(NULL))); + .WillRepeatedly(Return(static_cast<WebContents*>(NULL))); } // Copied key parts of DoIntermediateRename & AddDownloadFileToDownloadItem diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc index 47e3aaa494..58fe952217 100644 --- a/content/browser/download/download_manager_impl.cc +++ b/content/browser/download/download_manager_impl.cc @@ -524,6 +524,7 @@ void DownloadManagerImpl::OnSavePackageSuccessfullyFinished( void DownloadManagerImpl::ResumeInterruptedDownload( scoped_ptr<content::DownloadUrlParameters> params, uint32 id) { + RecordDownloadSource(INITIATED_BY_RESUMPTION); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, diff --git a/content/browser/download/download_resource_handler.cc b/content/browser/download/download_resource_handler.cc index 2a02cf926d..3b4844e6e6 100644 --- a/content/browser/download/download_resource_handler.cc +++ b/content/browser/download/download_resource_handler.cc @@ -171,11 +171,10 @@ bool DownloadResourceHandler::OnResponseStarted( const net::HttpResponseHeaders* headers = request_->response_headers(); if (headers) { std::string last_modified_hdr; - std::string etag; if (headers->EnumerateHeader(NULL, "Last-Modified", &last_modified_hdr)) info->last_modified = last_modified_hdr; - if (headers->EnumerateHeader(NULL, "ETag", &etag)) - info->etag = etag; + if (headers->EnumerateHeader(NULL, "ETag", &etag_)) + info->etag = etag_; int status = headers->response_code(); if (2 == status / 100 && status != net::HTTP_PARTIAL_CONTENT) { @@ -373,7 +372,7 @@ bool DownloadResourceHandler::OnResponseCompleted( } } - RecordAcceptsRanges(accept_ranges_, bytes_read_); + RecordAcceptsRanges(accept_ranges_, bytes_read_, etag_); RecordNetworkBlockage( base::TimeTicks::Now() - download_start_time_, total_pause_time_); diff --git a/content/browser/download/download_resource_handler.h b/content/browser/download/download_resource_handler.h index 866bffb6a9..d38068d548 100644 --- a/content/browser/download/download_resource_handler.h +++ b/content/browser/download/download_resource_handler.h @@ -126,6 +126,7 @@ class CONTENT_EXPORT DownloadResourceHandler size_t last_buffer_size_; int64 bytes_read_; std::string accept_ranges_; + std::string etag_; int pause_count_; bool was_deferred_; diff --git a/content/browser/download/download_stats.cc b/content/browser/download/download_stats.cc index c1b251d9a0..f8a1e09f19 100644 --- a/content/browser/download/download_stats.cc +++ b/content/browser/download/download_stats.cc @@ -179,7 +179,8 @@ void RecordDownloadWriteLoopCount(int count) { } void RecordAcceptsRanges(const std::string& accepts_ranges, - int64 download_len) { + int64 download_len, + const std::string& etag) { int64 max = 1024 * 1024 * 1024; // One Terabyte. download_len /= 1024; // In Kilobytes static const int kBuckets = 50; @@ -196,6 +197,10 @@ void RecordAcceptsRanges(const std::string& accepts_ranges, 1, max, kBuckets); + // ETags that start with "W/" are considered weak ETags which don't imply + // byte-wise equality. + if (!StartsWithASCII(etag, "w/", false)) + RecordDownloadCount(STRONG_ETAG_AND_ACCEPTS_RANGES); } else { UMA_HISTOGRAM_CUSTOM_COUNTS("Download.AcceptRangesMissingOrInvalid.KBytes", download_len, diff --git a/content/browser/download/download_stats.h b/content/browser/download/download_stats.h index 287b34d850..be2ae4b567 100644 --- a/content/browser/download/download_stats.h +++ b/content/browser/download/download_stats.h @@ -68,6 +68,14 @@ enum DownloadCountTypes { // successful invocation of ScanAndSaveDownloadedFile(). FILE_MISSING_AFTER_SUCCESSFUL_SCAN_COUNT, + // Count of downloads that supplies a strong ETag and has a 'Accept-Ranges: + // bytes' header. These downloads are candidates for partial resumption. + STRONG_ETAG_AND_ACCEPTS_RANGES, + + // Count of downloads that didn't have a valid WebContents at the time it was + // interrupted. + INTERRUPTED_WITHOUT_WEBCONTENTS, + DOWNLOAD_COUNT_TYPES_LAST_ENTRY }; @@ -85,6 +93,13 @@ enum DownloadSource { // (e.g. by Alt-click) through the IPC ViewHostMsg_DownloadUrl. INITIATED_BY_RENDERER, + // Fomerly INITIATED_BY_PEPPER_SAVE. + DOWNLOAD_SOURCE_UNUSED_3, + + // A request that was initiated as a result of resuming an interrupted + // download. + INITIATED_BY_RESUMPTION, + DOWNLOAD_SOURCE_LAST_ENTRY }; @@ -141,8 +156,11 @@ void RecordBandwidth(double actual_bandwidth, double potential_bandwidth); // download completed. void RecordOpen(const base::Time& end, bool first); -// Record whether or not the server accepts ranges, and the download size. -void RecordAcceptsRanges(const std::string& accepts_ranges, int64 download_len); +// Record whether or not the server accepts ranges, and the download size. Also +// counts if a strong ETag is supplied. The combination of range request support +// and ETag indicates downloads that are candidates for partial resumption. +void RecordAcceptsRanges(const std::string& accepts_ranges, int64 download_len, + const std::string& etag); // Record the number of downloads removed by ClearAll. void RecordClearAllSize(int size); diff --git a/content/browser/download/save_package.cc b/content/browser/download/save_package.cc index 1d793126b3..a386a2be0c 100644 --- a/content/browser/download/save_package.cc +++ b/content/browser/download/save_package.cc @@ -1318,7 +1318,7 @@ void SavePackage::GetSaveInfo() { // Can't use web_contents_ in the file thread, so get the data that we need // before calling to it. base::FilePath website_save_dir, download_save_dir; - bool skip_dir_check; + bool skip_dir_check = false; DCHECK(download_manager_); if (download_manager_->GetDelegate()) { download_manager_->GetDelegate()->GetSaveDir( diff --git a/content/browser/fileapi/browser_file_system_helper.cc b/content/browser/fileapi/browser_file_system_helper.cc index 1dac0f6479..e809857f08 100644 --- a/content/browser/fileapi/browser_file_system_helper.cc +++ b/content/browser/fileapi/browser_file_system_helper.cc @@ -23,7 +23,6 @@ #include "webkit/browser/fileapi/file_system_backend.h" #include "webkit/browser/fileapi/file_system_operation_runner.h" #include "webkit/browser/fileapi/file_system_options.h" -#include "webkit/browser/fileapi/file_system_task_runners.h" #include "webkit/browser/quota/quota_manager.h" namespace content { @@ -58,11 +57,6 @@ scoped_refptr<fileapi::FileSystemContext> CreateFileSystemContext( scoped_refptr<base::SequencedTaskRunner> file_task_runner = pool->GetSequencedTaskRunner(pool->GetNamedSequenceToken("FileAPI")); - scoped_ptr<fileapi::FileSystemTaskRunners> task_runners( - new fileapi::FileSystemTaskRunners( - BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO).get(), - file_task_runner.get())); - // Setting up additional filesystem backends. ScopedVector<fileapi::FileSystemBackend> additional_backends; GetContentClient()->browser()->GetAdditionalFileSystemBackends( @@ -72,7 +66,8 @@ scoped_refptr<fileapi::FileSystemContext> CreateFileSystemContext( scoped_refptr<fileapi::FileSystemContext> file_system_context = new fileapi::FileSystemContext( - task_runners.Pass(), + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO).get(), + file_task_runner.get(), BrowserContext::GetMountPoints(browser_context), browser_context->GetSpecialStoragePolicy(), quota_manager_proxy, @@ -126,7 +121,7 @@ void SyncGetPlatformPath(fileapi::FileSystemContext* context, int process_id, const GURL& path, base::FilePath* platform_path) { - DCHECK(context->task_runners()->file_task_runner()-> + DCHECK(context->default_file_task_runner()-> RunsTasksOnCurrentThread()); DCHECK(platform_path); *platform_path = base::FilePath(); diff --git a/content/browser/fileapi/fileapi_message_filter.cc b/content/browser/fileapi/fileapi_message_filter.cc index 1fbb338504..cf95b02332 100644 --- a/content/browser/fileapi/fileapi_message_filter.cc +++ b/content/browser/fileapi/fileapi_message_filter.cc @@ -29,9 +29,7 @@ #include "webkit/browser/fileapi/file_observers.h" #include "webkit/browser/fileapi/file_permission_policy.h" #include "webkit/browser/fileapi/file_system_context.h" -#include "webkit/browser/fileapi/file_system_task_runners.h" #include "webkit/browser/fileapi/isolated_context.h" -#include "webkit/browser/fileapi/local_file_system_operation.h" #include "webkit/browser/quota/quota_manager.h" #include "webkit/common/blob/blob_data.h" #include "webkit/common/blob/shareable_file_reference.h" @@ -44,7 +42,6 @@ using fileapi::FileSystemBackend; using fileapi::FileSystemOperation; using fileapi::FileSystemURL; using fileapi::FileUpdateObserver; -using fileapi::LocalFileSystemOperation; using fileapi::UpdateObserverList; using webkit_blob::BlobData; using webkit_blob::BlobStorageController; @@ -139,7 +136,7 @@ void FileAPIMessageFilter::OnChannelClosing() { base::TaskRunner* FileAPIMessageFilter::OverrideTaskRunnerForMessage( const IPC::Message& message) { if (message.type() == FileSystemHostMsg_SyncGetPlatformPath::ID) - return context_->task_runners()->file_task_runner(); + return context_->default_file_task_runner(); return NULL; } @@ -720,7 +717,7 @@ void FileAPIMessageFilter::DidCreateSnapshot( file_ref = webkit_blob::ShareableFileReference::GetOrCreate( platform_path, webkit_blob::ShareableFileReference::DONT_DELETE_ON_FINAL_RELEASE, - context_->task_runners()->file_task_runner()); + context_->default_file_task_runner()); } file_ref->AddFinalReleaseCallback( base::Bind(&RevokeFilePermission, process_id_)); diff --git a/content/browser/gpu/compositor_util.cc b/content/browser/gpu/compositor_util.cc index a0cf1e21a2..96c626427f 100644 --- a/content/browser/gpu/compositor_util.cc +++ b/content/browser/gpu/compositor_util.cc @@ -78,7 +78,7 @@ bool IsThreadedCompositingEnabled() { } bool IsForceCompositingModeEnabled() { -#if defined(OS_WIN) && defined(USE_AURA) +#if defined(OS_WIN) // We always want compositing on Aura Windows. return true; #endif diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc index 82e4369474..1bd1f6b95d 100644 --- a/content/browser/gpu/gpu_data_manager_impl_private.cc +++ b/content/browser/gpu/gpu_data_manager_impl_private.cc @@ -157,11 +157,7 @@ void UpdateStats(const gpu::GpuBlacklist* blacklist, const bool kGpuFeatureUserFlags[] = { command_line.HasSwitch(switches::kDisableAccelerated2dCanvas), command_line.HasSwitch(switches::kDisableAcceleratedCompositing), -#if defined(OS_ANDROID) - !command_line.HasSwitch(switches::kEnableExperimentalWebGL), -#else command_line.HasSwitch(switches::kDisableExperimentalWebGL), -#endif command_line.HasSwitch(switches::kDisableImageTransportSurface) }; #if defined(OS_WIN) @@ -266,6 +262,8 @@ void ApplyAndroidWorkarounds(const gpu::GPUInfo& gpu_info, gpu_info.gl_vendor.find("Broadcom") != std::string::npos; bool is_mali_t604 = is_arm && gpu_info.gl_renderer.find("Mali-T604") != std::string::npos; + bool is_nvidia = + gpu_info.gl_vendor.find("NVIDIA") != std::string::npos; bool is_vivante = gpu_info.gl_extensions.find("GL_VIV_shader_binary") != @@ -279,7 +277,7 @@ void ApplyAndroidWorkarounds(const gpu::GPUInfo& gpu_info, // IMG: avoid context switching perf problems, crashes with share groups // Mali-T604: http://crbug.com/154715 // QualComm, NVIDIA: Crashes with share groups - if (is_vivante || is_img || is_mali_t604 || is_nexus7 || is_qualcomm || + if (is_vivante || is_img || is_mali_t604 || is_nvidia || is_qualcomm || is_broadcom) command_line->AppendSwitch(switches::kEnableVirtualGLContexts); @@ -658,6 +656,17 @@ void GpuDataManagerImplPrivate::AppendRendererCommandLine( if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) && !command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode)) command_line->AppendSwitch(switches::kDisableAcceleratedVideoDecode); + + if (use_software_compositor_ && + !command_line->HasSwitch(switches::kEnableSoftwareCompositing)) + command_line->AppendSwitch(switches::kEnableSoftwareCompositing); + +#if defined(USE_AURA) + if (!CanUseGpuBrowserCompositor()) { + command_line->AppendSwitch(switches::kDisableGpuCompositing); + command_line->AppendSwitch(switches::kDisablePepper3d); + } +#endif } void GpuDataManagerImplPrivate::AppendGpuCommandLine( @@ -812,6 +821,18 @@ void GpuDataManagerImplPrivate::UpdateRendererWebPrefs( prefs->accelerated_compositing_for_3d_transforms_enabled = false; prefs->accelerated_compositing_for_plugins_enabled = false; } + + if (use_software_compositor_) { + prefs->force_compositing_mode = true; + prefs->accelerated_compositing_enabled = true; + prefs->accelerated_compositing_for_3d_transforms_enabled = true; + prefs->accelerated_compositing_for_plugins_enabled = true; + } + +#if defined(USE_AURA) + if (!CanUseGpuBrowserCompositor()) + prefs->accelerated_2d_canvas_enabled = false; +#endif } gpu::GpuSwitchingOption @@ -914,7 +935,9 @@ bool GpuDataManagerImplPrivate::IsUsingAcceleratedSurface() const { #endif bool GpuDataManagerImplPrivate::CanUseGpuBrowserCompositor() const { - return !IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING); + return !ShouldUseSwiftShader() && + !IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) && + !IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FORCE_COMPOSITING_MODE); } void GpuDataManagerImplPrivate::BlockDomainFrom3DAPIs( @@ -963,7 +986,8 @@ GpuDataManagerImplPrivate::GpuDataManagerImplPrivate( domain_blocking_enabled_(true), owner_(owner), display_count_(0), - gpu_process_accessible_(true) { + gpu_process_accessible_(true), + use_software_compositor_(false) { DCHECK(owner_); CommandLine* command_line = CommandLine::ForCurrentProcess(); if (command_line->HasSwitch(switches::kDisableAcceleratedCompositing)) { @@ -972,6 +996,8 @@ GpuDataManagerImplPrivate::GpuDataManagerImplPrivate( } if (command_line->HasSwitch(switches::kDisableGpu)) DisableHardwareAcceleration(); + if (command_line->HasSwitch(switches::kEnableSoftwareCompositing)) + use_software_compositor_ = true; if (command_line->HasSwitch(switches::kGpuSwitching)) { std::string option_string = command_line->GetSwitchValueASCII( switches::kGpuSwitching); diff --git a/content/browser/gpu/gpu_data_manager_impl_private.h b/content/browser/gpu/gpu_data_manager_impl_private.h index b4b7805010..eb226e863d 100644 --- a/content/browser/gpu/gpu_data_manager_impl_private.h +++ b/content/browser/gpu/gpu_data_manager_impl_private.h @@ -244,6 +244,8 @@ class CONTENT_EXPORT GpuDataManagerImplPrivate { bool gpu_process_accessible_; + bool use_software_compositor_; + DISALLOW_COPY_AND_ASSIGN(GpuDataManagerImplPrivate); }; diff --git a/content/browser/gpu/gpu_internals_ui.cc b/content/browser/gpu/gpu_internals_ui.cc index cbc2472bd2..0e778c277b 100644 --- a/content/browser/gpu/gpu_internals_ui.cc +++ b/content/browser/gpu/gpu_internals_ui.cc @@ -162,6 +162,10 @@ base::DictionaryValue* GpuInfoAsDictionaryValue() { gpu_info.gl_ws_version)); basic_info->Append(NewDescriptionValuePair("Window system binding extensions", gpu_info.gl_ws_extensions)); + std::string reset_strategy = + base::StringPrintf("0x%04x", gpu_info.gl_reset_notification_strategy); + basic_info->Append(NewDescriptionValuePair( + "Reset notification strategy", reset_strategy)); base::DictionaryValue* info = new base::DictionaryValue(); info->Set("basic_info", basic_info); @@ -249,11 +253,7 @@ base::Value* GetFeatureStatus() { { "webgl", manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL), -#if defined(OS_ANDROID) - !command_line.HasSwitch(switches::kEnableExperimentalWebGL), -#else command_line.HasSwitch(switches::kDisableExperimentalWebGL), -#endif "WebGL has been disabled, either via about:flags or command line.", false }, diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc index c7b4666d29..892583d3c5 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc @@ -1150,6 +1150,7 @@ bool GpuProcessHost::LaunchGpuProcess(const std::string& channel_id) { switches::kEnableShareGroupAsyncTextureUpload, switches::kEnableVirtualGLContexts, switches::kGpuStartupDialog, + switches::kGpuSandboxAllowSysVShm, switches::kLoggingLevel, switches::kNoSandbox, switches::kReduceGpuSandbox, diff --git a/content/browser/gpu/shader_disk_cache.cc b/content/browser/gpu/shader_disk_cache.cc index 25e616ddf3..fc578bc4bf 100644 --- a/content/browser/gpu/shader_disk_cache.cc +++ b/content/browser/gpu/shader_disk_cache.cc @@ -507,15 +507,12 @@ ShaderDiskCache::ShaderDiskCache(const base::FilePath& cache_path) : cache_available_(false), host_id_(0), cache_path_(cache_path), - is_initialized_(false), - backend_(NULL) { + is_initialized_(false) { ShaderCacheFactory::GetInstance()->AddToCache(cache_path_, this); } ShaderDiskCache::~ShaderDiskCache() { ShaderCacheFactory::GetInstance()->RemoveFromCache(cache_path_); - if (backend_) - delete backend_; } void ShaderDiskCache::Init() { diff --git a/content/browser/gpu/shader_disk_cache.h b/content/browser/gpu/shader_disk_cache.h index d06434ad98..051be5876e 100644 --- a/content/browser/gpu/shader_disk_cache.h +++ b/content/browser/gpu/shader_disk_cache.h @@ -75,7 +75,7 @@ class CONTENT_EXPORT ShaderDiskCache void CacheCreatedCallback(int rv); - disk_cache::Backend* backend() { return backend_; } + disk_cache::Backend* backend() { return backend_.get(); } void EntryComplete(void* entry); void ReadComplete(); @@ -87,7 +87,7 @@ class CONTENT_EXPORT ShaderDiskCache net::CompletionCallback available_callback_; net::CompletionCallback cache_complete_callback_; - disk_cache::Backend* backend_; + scoped_ptr<disk_cache::Backend> backend_; scoped_refptr<ShaderDiskReadHelper> helper_; std::map<void*, scoped_refptr<ShaderDiskCacheEntry> > entry_map_; diff --git a/content/browser/gpu/test_support_gpu.gypi b/content/browser/gpu/test_support_gpu.gypi index f141069dbf..4892e9a38e 100644 --- a/content/browser/gpu/test_support_gpu.gypi +++ b/content/browser/gpu/test_support_gpu.gypi @@ -29,7 +29,6 @@ '<(SHARED_INTERMEDIATE_DIR)/content/content_resources.rc', '<(SHARED_INTERMEDIATE_DIR)/net/net_resources.rc', '<(SHARED_INTERMEDIATE_DIR)/webkit/blink_resources.rc', - '<(SHARED_INTERMEDIATE_DIR)/webkit/webkit_chromium_resources.rc', ], 'conditions': [ ['win_use_allocator_shim==1', { diff --git a/content/browser/gpu/webgl_conformance_test.cc b/content/browser/gpu/webgl_conformance_test.cc index c58653cd63..79f3078283 100644 --- a/content/browser/gpu/webgl_conformance_test.cc +++ b/content/browser/gpu/webgl_conformance_test.cc @@ -27,7 +27,6 @@ class WebGLConformanceTest : public ContentBrowserTest { // Allow privileged WebGL extensions. command_line->AppendSwitch(switches::kEnablePrivilegedWebGLExtensions); #if defined(OS_ANDROID) - command_line->AppendSwitch(switches::kEnableExperimentalWebGL); command_line->AppendSwitch( switches::kDisableGestureRequirementForMediaPlayback); #endif diff --git a/content/browser/hyphenator/hyphenator_message_filter.cc b/content/browser/hyphenator/hyphenator_message_filter.cc deleted file mode 100644 index 5e580d82ca..0000000000 --- a/content/browser/hyphenator/hyphenator_message_filter.cc +++ /dev/null @@ -1,120 +0,0 @@ -// 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 "base/base_paths.h" -#include "base/bind.h" -#include "base/logging.h" -#include "base/path_service.h" -#include "base/strings/string16.h" -#include "content/browser/hyphenator/hyphenator_message_filter.h" -#include "content/common/hyphenator_messages.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/content_browser_client.h" -#include "content/public/browser/render_process_host.h" - -namespace content { - -namespace { - -// A helper function that closes the specified file in the FILE thread. This -// function may be called after the HyphenatorMessageFilter object that owns the -// specified file is deleted, i.e. this function must not depend on the object. -void CloseDictionary(base::PlatformFile file) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - base::ClosePlatformFile(file); -} - -} // namespace - -HyphenatorMessageFilter::HyphenatorMessageFilter( - RenderProcessHost* render_process_host) - : render_process_host_(render_process_host), - dictionary_file_(base::kInvalidPlatformFileValue), - weak_factory_(this) { -} - -HyphenatorMessageFilter::~HyphenatorMessageFilter() { - // Post a FILE task that deletes the dictionary file. This message filter is - // usually deleted on the IO thread, which does not allow file operations. - if (dictionary_file_ != base::kInvalidPlatformFileValue) { - BrowserThread::PostTask( - BrowserThread::FILE, - FROM_HERE, - base::Bind(&CloseDictionary, dictionary_file_)); - } -} - -void HyphenatorMessageFilter::SetDictionaryBase(const base::FilePath& base) { - dictionary_base_ = base; -} - -void HyphenatorMessageFilter::OverrideThreadForMessage( - const IPC::Message& message, - BrowserThread::ID* thread) { - if (message.type() == HyphenatorHostMsg_OpenDictionary::ID) - *thread = BrowserThread::UI; -} - -bool HyphenatorMessageFilter::OnMessageReceived( - const IPC::Message& message, - bool* message_was_ok) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP_EX(HyphenatorMessageFilter, - message, - *message_was_ok) - IPC_MESSAGE_HANDLER(HyphenatorHostMsg_OpenDictionary, OnOpenDictionary) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP_EX() - return handled; -} - -void HyphenatorMessageFilter::OnOpenDictionary(const string16& locale) { - if (dictionary_file_ != base::kInvalidPlatformFileValue) { - SendDictionary(); - return; - } - BrowserThread::PostTaskAndReply( - BrowserThread::FILE, - FROM_HERE, - base::Bind(&HyphenatorMessageFilter::OpenDictionary, this, locale), - base::Bind(&HyphenatorMessageFilter::SendDictionary, - weak_factory_.GetWeakPtr())); -} - -void HyphenatorMessageFilter::OpenDictionary(const string16& locale) { - DCHECK(dictionary_file_ == base::kInvalidPlatformFileValue); - - if (dictionary_base_.empty()) { - dictionary_base_ = - GetContentClient()->browser()->GetHyphenDictionaryDirectory(); - } - std::string rule_file = locale.empty() ? "en-US" : UTF16ToASCII(locale); - - // Currently, only en-US is hyphenated. This is a quick fix for - // http://crbug.com/167122. - // TODO(groby): The proper fix entails validating if locale is a properly - // formatted locale string, but knowledge about valid locales currently - // resides in chrome, not content. - if (rule_file != "en-US") - return; - rule_file.append("-1-0.dic"); - base::FilePath rule_path = dictionary_base_.AppendASCII(rule_file); - dictionary_file_ = base::CreatePlatformFile( - rule_path, - base::PLATFORM_FILE_READ | base::PLATFORM_FILE_OPEN, - NULL, NULL); -} - -void HyphenatorMessageFilter::SendDictionary() { - IPC::PlatformFileForTransit file = IPC::InvalidPlatformFileForTransit(); - if (dictionary_file_ != base::kInvalidPlatformFileValue) { - file = IPC::GetFileHandleForProcess( - dictionary_file_, - render_process_host_->GetHandle(), - false); - } - Send(new HyphenatorMsg_SetDictionary(file)); -} - -} // namespace content diff --git a/content/browser/hyphenator/hyphenator_message_filter.h b/content/browser/hyphenator/hyphenator_message_filter.h deleted file mode 100644 index a5ed21ce40..0000000000 --- a/content/browser/hyphenator/hyphenator_message_filter.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_HYPHENATOR_HYPHENATOR_MESSAGE_FILTER_H_ -#define CONTENT_BROWSER_HYPHENATOR_HYPHENATOR_MESSAGE_FILTER_H_ - -#include "base/compiler_specific.h" -#include "base/files/file_path.h" -#include "base/memory/weak_ptr.h" -#include "base/platform_file.h" -#include "content/common/content_export.h" -#include "content/public/browser/browser_message_filter.h" - -namespace content { -class RenderProcessHost; - -// This class is a message filter that handles a HyphenatorHost message. When -// this class receives a HyphenatorHostMsg_OpenDictionary message, it opens the -// specified dictionary and sends its file handle. -class CONTENT_EXPORT HyphenatorMessageFilter : public BrowserMessageFilter { - public: - explicit HyphenatorMessageFilter(RenderProcessHost* render_process_host); - - // Changes the directory that includes dictionary files. This function - // provides a method that allows applications to change the directory - // containing hyphenation dictionaries. When a renderer requests a hyphnation - // dictionary, this class appends a file name (which consists of a locale, a - // version number, and an extension) and use it as a dictionary file. - void SetDictionaryBase(const base::FilePath& directory); - - // BrowserMessageFilter implementation. - virtual void OverrideThreadForMessage( - const IPC::Message& message, - BrowserThread::ID* thread) OVERRIDE; - virtual bool OnMessageReceived(const IPC::Message& message, - bool* message_was_ok) OVERRIDE; - - private: - friend class TestHyphenatorMessageFilter; - - virtual ~HyphenatorMessageFilter(); - - virtual void OnOpenDictionary(const string16& locale); - - // Opens a hyphenation dictionary for the specified locale. When this locale - // is an empty string, this function uses US English ("en-US"). - void OpenDictionary(const string16& locale); - - // Sends the hyphenation dictionary file to a renderer in response to its - // request. If this class cannot open the specified dictionary file, this - // function sends an IPC::InvalidPlatformFileForTransit value to tell the - // renderer that a browser cannot open the file. - void SendDictionary(); - - // The RenderProcessHost object that owns this filter. This class uses this - // object to retrieve the process handle used for creating - // PlatformFileForTransit objects. - RenderProcessHost* render_process_host_; - - // The directory that includes dictionary files. The default value is the - // directory containing the executable file. - base::FilePath dictionary_base_; - - // A cached dictionary file. - base::PlatformFile dictionary_file_; - - base::WeakPtrFactory<HyphenatorMessageFilter> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(HyphenatorMessageFilter); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_HYPHENATOR_HYPHENATOR_MESSAGE_FILTER_H_ diff --git a/content/browser/hyphenator/hyphenator_message_filter_unittest.cc b/content/browser/hyphenator/hyphenator_message_filter_unittest.cc deleted file mode 100644 index e62210d995..0000000000 --- a/content/browser/hyphenator/hyphenator_message_filter_unittest.cc +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/hyphenator/hyphenator_message_filter.h" - -#include "base/base_paths.h" -#include "base/files/file_path.h" -#include "base/path_service.h" -#include "base/strings/string16.h" -#include "base/strings/utf_string_conversions.h" -#include "content/common/hyphenator_messages.h" -#include "content/public/test/mock_render_process_host.h" -#include "content/public/test/test_browser_context.h" -#include "ipc/ipc_message_utils.h" -#include "ipc/ipc_platform_file.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace content { - -// A class derived from the HyphenatorMessageFilter class used in unit tests. -// This class overrides some methods so we can test the HyphenatorMessageFilter -// class without posting tasks. -class TestHyphenatorMessageFilter : public HyphenatorMessageFilter { - public: - explicit TestHyphenatorMessageFilter(RenderProcessHost* host) - : HyphenatorMessageFilter(host), - type_(0), - file_(base::kInvalidPlatformFileValue) { - } - - const string16& locale() const { return locale_; } - uint32 type() const { return type_; } - base::PlatformFile file() const { return file_; } - - // BrowserMessageFilter implementation. - virtual bool Send(IPC::Message* message) OVERRIDE { - if (message->type() != HyphenatorMsg_SetDictionary::ID) - return false; - - // Read the PlatformFileForTransit object and check if its value is - // kInvalidPlatformFileValue. Close the incoming file if it is not - // kInvalidPlatformFileValue to prevent leaving the dictionary file open. - type_ = message->type(); - PickleIterator iter(*message); - IPC::PlatformFileForTransit file; - IPC::ParamTraits<IPC::PlatformFileForTransit>::Read(message, &iter, &file); - file_ = IPC::PlatformFileForTransitToPlatformFile(file); - delete message; - return true; - } - - void SetDictionary(base::PlatformFile file) { - dictionary_file_ = file; - } - - void Reset() { - if (dictionary_file_ != base::kInvalidPlatformFileValue) { - base::ClosePlatformFile(dictionary_file_); - dictionary_file_ = base::kInvalidPlatformFileValue; - } - locale_.clear(); - type_ = 0; - if (file_ != base::kInvalidPlatformFileValue) { - base::ClosePlatformFile(file_); - file_ = base::kInvalidPlatformFileValue; - } - } - - private: - virtual ~TestHyphenatorMessageFilter() { - } - - // HyphenatorMessageFilter implementation. This function emulates the - // original implementation without posting a task. - virtual void OnOpenDictionary(const string16& locale) OVERRIDE { - locale_ = locale; - if (dictionary_file_ == base::kInvalidPlatformFileValue) - OpenDictionary(locale); - SendDictionary(); - } - - string16 locale_; - uint32 type_; - base::PlatformFile file_; -}; - -class HyphenatorMessageFilterTest : public testing::Test { - public: - HyphenatorMessageFilterTest() { - context_.reset(new TestBrowserContext); - host_.reset(new MockRenderProcessHost(context_.get())); - filter_ = new TestHyphenatorMessageFilter(host_.get()); - } - - virtual ~HyphenatorMessageFilterTest() {} - - scoped_ptr<TestBrowserContext> context_; - scoped_ptr<MockRenderProcessHost> host_; - scoped_refptr<TestHyphenatorMessageFilter> filter_; -}; - -// Verifies IPC messages sent by the HyphenatorMessageFilter class when it -// receives IPC messages (HyphenatorHostMsg_OpenDictionary). -TEST_F(HyphenatorMessageFilterTest, OpenDictionary) { - // Send a HyphenatorHostMsg_OpenDictionary message with an invalid locale and - // verify it sends a HyphenatorMsg_SetDictionary message with an invalid file. - string16 invalid_locale(ASCIIToUTF16("xx-xx")); - IPC::Message invalid_message( - 0, HyphenatorHostMsg_OpenDictionary::ID, IPC::Message::PRIORITY_NORMAL); - invalid_message.WriteString16(invalid_locale); - - bool message_was_ok = false; - filter_->OnMessageReceived(invalid_message, &message_was_ok); - EXPECT_TRUE(message_was_ok); - EXPECT_EQ(invalid_locale, filter_->locale()); - EXPECT_EQ(HyphenatorMsg_SetDictionary::ID, filter_->type()); - EXPECT_EQ(base::kInvalidPlatformFileValue, filter_->file()); - - filter_->Reset(); - - // Open a sample dictionary file and attach it to the - // HyphenatorMessageFilter class so it can return a valid file. - base::FilePath path; - PathService::Get(base::DIR_SOURCE_ROOT, &path); - path = path.Append(FILE_PATH_LITERAL("third_party")); - path = path.Append(FILE_PATH_LITERAL("hyphen")); - path = path.Append(FILE_PATH_LITERAL("hyph_en_US.dic")); - base::PlatformFile file = base::CreatePlatformFile( - path, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, - NULL, NULL); - EXPECT_NE(base::kInvalidPlatformFileValue, file); - filter_->SetDictionary(file); - file = base::kInvalidPlatformFileValue; // Ownership has been transferred. - - // Send a HyphenatorHostMsg_OpenDictionary message with an empty locale and - // verify it sends a HyphenatorMsg_SetDictionary message with a valid file. - string16 empty_locale; - IPC::Message valid_message( - 0, HyphenatorHostMsg_OpenDictionary::ID, IPC::Message::PRIORITY_NORMAL); - valid_message.WriteString16(empty_locale); - - message_was_ok = false; - filter_->OnMessageReceived(valid_message, &message_was_ok); - EXPECT_TRUE(message_was_ok); - EXPECT_EQ(empty_locale, filter_->locale()); - EXPECT_EQ(HyphenatorMsg_SetDictionary::ID, filter_->type()); - EXPECT_NE(base::kInvalidPlatformFileValue, filter_->file()); - - // Delete all resources used by this test. - filter_->Reset(); -} - -} // namespace content diff --git a/content/browser/media/encrypted_media_browsertest.cc b/content/browser/media/encrypted_media_browsertest.cc index 615fba90af..ce5dc4e6ba 100644 --- a/content/browser/media/encrypted_media_browsertest.cc +++ b/content/browser/media/encrypted_media_browsertest.cc @@ -269,8 +269,6 @@ IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioOnly_MP4) { // Run only when WV CDM is available. #if defined(WIDEVINE_CDM_AVAILABLE) -// See http://crbug.com/237636. -#if !defined(DISABLE_WIDEVINE_CDM_BROWSERTESTS) IN_PROC_BROWSER_TEST_F(WVEncryptedMediaTest, Playback_AudioOnly_WebM) { TestMSESimplePlayback("bear-a-enc_a.webm", kWebMAudioOnly, kWidevineKeySystem); @@ -307,7 +305,6 @@ IN_PROC_BROWSER_TEST_F(WVEncryptedMediaTest, Playback_AudioOnly_MP4) { kWidevineKeySystem); } #endif // defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS) -#endif // !defined(DISABLE_WIDEVINE_CDM_BROWSERTESTS) #endif // defined(WIDEVINE_CDM_AVAILABLE) } // namespace content diff --git a/content/browser/media/webrtc_browsertest.cc b/content/browser/media/webrtc_browsertest.cc index 7b3a29cb03..8ab977d63f 100644 --- a/content/browser/media/webrtc_browsertest.cc +++ b/content/browser/media/webrtc_browsertest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/command_line.h" +#include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/common/content_switches.h" @@ -16,6 +17,27 @@ #include "base/win/windows_version.h" #endif +namespace { + +std::string GenerateGetUserMediaCall(int min_width, + int max_width, + int min_height, + int max_height, + int min_frame_rate, + int max_frame_rate) { + return base::StringPrintf( + "getUserMedia({video: {mandatory: {minWidth: %d, maxWidth: %d, " + "minHeight: %d, maxHeight: %d, minFrameRate: %d, maxFrameRate: %d}, " + "optional: []}});", + min_width, + max_width, + min_height, + max_height, + min_frame_rate, + max_frame_rate); +} +} + namespace content { class WebrtcBrowserTest: public ContentBrowserTest { @@ -230,4 +252,34 @@ IN_PROC_BROWSER_TEST_F(WebrtcBrowserTest, MANUAL_CallAndModifyStream) { ExpectTitle("OK"); } +// This test calls getUserMedia in sequence with different constraints. +IN_PROC_BROWSER_TEST_F(WebrtcBrowserTest, TestGetUserMediaConstraints) { + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); + + std::vector<std::string> list_of_get_user_media_calls; + list_of_get_user_media_calls.push_back( + GenerateGetUserMediaCall(320, 320, 180, 180, 30, 30)); + list_of_get_user_media_calls.push_back( + GenerateGetUserMediaCall(320, 320, 240, 240, 30, 30)); + list_of_get_user_media_calls.push_back( + GenerateGetUserMediaCall(640, 640, 360, 360, 30, 30)); + list_of_get_user_media_calls.push_back( + GenerateGetUserMediaCall(640, 640, 480, 480, 30, 30)); + list_of_get_user_media_calls.push_back( + GenerateGetUserMediaCall(960, 960, 720, 720, 30, 30)); + list_of_get_user_media_calls.push_back( + GenerateGetUserMediaCall(1280, 1280, 720, 720, 30, 30)); + list_of_get_user_media_calls.push_back( + GenerateGetUserMediaCall(1920, 1920, 1080, 1080, 30, 30)); + + for (std::vector<std::string>::iterator const_iterator = + list_of_get_user_media_calls.begin(); + const_iterator != list_of_get_user_media_calls.end(); + ++const_iterator) { + DVLOG(1) << "Calling getUserMedia: " << *const_iterator; + NavigateToURL(shell(), url); + EXPECT_TRUE(ExecuteJavascript(*const_iterator)); + ExpectTitle("OK"); + } +} } // namespace content diff --git a/content/browser/power_monitor_message_broadcaster.cc b/content/browser/power_monitor_message_broadcaster.cc new file mode 100644 index 0000000000..77abcb959f --- /dev/null +++ b/content/browser/power_monitor_message_broadcaster.cc @@ -0,0 +1,39 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/power_monitor_message_broadcaster.h" + +#include "base/power_monitor/power_monitor.h" +#include "content/common/power_monitor_messages.h" +#include "ipc/ipc_sender.h" + +namespace content { + +PowerMonitorMessageBroadcaster::PowerMonitorMessageBroadcaster( + IPC::Sender* sender) + : sender_(sender) { + base::PowerMonitor* power_monitor = base::PowerMonitor::Get(); + if (power_monitor) + power_monitor->AddObserver(this); +} + +PowerMonitorMessageBroadcaster::~PowerMonitorMessageBroadcaster() { + base::PowerMonitor* power_monitor = base::PowerMonitor::Get(); + if (power_monitor) + power_monitor->RemoveObserver(this); +} + +void PowerMonitorMessageBroadcaster::OnPowerStateChange(bool on_battery_power) { + sender_->Send(new PowerMonitorMsg_PowerStateChange(on_battery_power)); +} + +void PowerMonitorMessageBroadcaster::OnSuspend() { + sender_->Send(new PowerMonitorMsg_Suspend()); +} + +void PowerMonitorMessageBroadcaster::OnResume() { + sender_->Send(new PowerMonitorMsg_Resume()); +} + +} // namespace content
\ No newline at end of file diff --git a/content/browser/power_monitor_message_broadcaster.h b/content/browser/power_monitor_message_broadcaster.h new file mode 100644 index 0000000000..f0e3a207e2 --- /dev/null +++ b/content/browser/power_monitor_message_broadcaster.h @@ -0,0 +1,41 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_POWER_MONITOR_MESSAGE_BROADCASTER_H_ +#define CONTENT_BROWSER_POWER_MONITOR_MESSAGE_BROADCASTER_H_ + +#include "base/basictypes.h" +#include "base/memory/ref_counted.h" +#include "base/power_monitor/power_observer.h" +#include "content/common/content_export.h" +#include "content/public/browser/browser_thread.h" + +namespace IPC { + class Sender; +} + +namespace content { + +// A class used to monitor the power state change and communicate it to child +// processes via IPC. +class CONTENT_EXPORT PowerMonitorMessageBroadcaster + : public base::PowerObserver { + public: + explicit PowerMonitorMessageBroadcaster(IPC::Sender* sender); + virtual ~PowerMonitorMessageBroadcaster(); + + // Implement PowerObserver. + virtual void OnPowerStateChange(bool on_battery_power) OVERRIDE; + virtual void OnSuspend() OVERRIDE; + virtual void OnResume() OVERRIDE; + + private: + IPC::Sender* sender_; + + DISALLOW_COPY_AND_ASSIGN(PowerMonitorMessageBroadcaster); +}; + +} // namespace base + +#endif // CONTENT_BROWSER_POWER_MONITOR_MESSAGE_BROADCASTER_H_
\ No newline at end of file diff --git a/content/browser/power_monitor_message_broadcaster_unittest.cc b/content/browser/power_monitor_message_broadcaster_unittest.cc new file mode 100644 index 0000000000..6eb0cb4a61 --- /dev/null +++ b/content/browser/power_monitor_message_broadcaster_unittest.cc @@ -0,0 +1,109 @@ +// Copyright 2013 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 "base/power_monitor/power_monitor_test_base.h" +#include "content/browser/power_monitor_message_broadcaster.h" +#include "content/common/power_monitor_messages.h" +#include "ipc/ipc_sender.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace content { + +class PowerMonitorMessageSender : public IPC::Sender { + public: + PowerMonitorMessageSender() + : power_state_changes_(0), + suspends_(0), + resumes_(0) { + } + virtual ~PowerMonitorMessageSender() {} + + virtual bool Send(IPC::Message* msg) OVERRIDE { + switch (msg->type()) { + case PowerMonitorMsg_Suspend::ID: + suspends_++; + break; + case PowerMonitorMsg_Resume::ID: + resumes_++; + break; + case PowerMonitorMsg_PowerStateChange::ID: + power_state_changes_++; + break; + } + delete msg; + return true; + }; + + // Test status counts. + int power_state_changes() { return power_state_changes_; } + int suspends() { return suspends_; } + int resumes() { return resumes_; } + + private: + int power_state_changes_; // Count of OnPowerStateChange notifications. + int suspends_; // Count of OnSuspend notifications. + int resumes_; // Count of OnResume notifications. +}; + +class PowerMonitorMessageBroadcasterTest : public testing::Test { + protected: + PowerMonitorMessageBroadcasterTest() { + power_monitor_source_ = new base::PowerMonitorTestSource(); + power_monitor_.reset(new base::PowerMonitor( + scoped_ptr<base::PowerMonitorSource>(power_monitor_source_))); + } + virtual ~PowerMonitorMessageBroadcasterTest() {}; + + base::PowerMonitorTestSource* source() { return power_monitor_source_; } + base::PowerMonitor* monitor() { return power_monitor_.get(); } + + private: + base::PowerMonitorTestSource* power_monitor_source_; + scoped_ptr<base::PowerMonitor> power_monitor_; + + DISALLOW_COPY_AND_ASSIGN(PowerMonitorMessageBroadcasterTest); +}; + +TEST_F(PowerMonitorMessageBroadcasterTest, PowerMessageBroadcast) { + PowerMonitorMessageSender sender; + PowerMonitorMessageBroadcaster broadcaster(&sender); + + // Sending resume when not suspended should have no effect. + source()->GenerateResumeEvent(); + EXPECT_EQ(sender.resumes(), 0); + + // Pretend we suspended. + source()->GenerateSuspendEvent(); + EXPECT_EQ(sender.suspends(), 1); + + // Send a second suspend notification. This should be suppressed. + source()->GenerateSuspendEvent(); + EXPECT_EQ(sender.suspends(), 1); + + // Pretend we were awakened. + source()->GenerateResumeEvent(); + EXPECT_EQ(sender.resumes(), 1); + + // Send a duplicate resume notification. This should be suppressed. + source()->GenerateResumeEvent(); + EXPECT_EQ(sender.resumes(), 1); + + // Pretend the device has gone on battery power + source()->GeneratePowerStateEvent(true); + EXPECT_EQ(sender.power_state_changes(), 1); + + // Repeated indications the device is on battery power should be suppressed. + source()->GeneratePowerStateEvent(true); + EXPECT_EQ(sender.power_state_changes(), 1); + + // Pretend the device has gone off battery power + source()->GeneratePowerStateEvent(false); + EXPECT_EQ(sender.power_state_changes(), 2); + + // Repeated indications the device is off battery power should be suppressed. + source()->GeneratePowerStateEvent(false); + EXPECT_EQ(sender.power_state_changes(), 2); +} + +} // namespace base diff --git a/content/browser/renderer_host/DEPS b/content/browser/renderer_host/DEPS index 363a59c139..34decdb022 100644 --- a/content/browser/renderer_host/DEPS +++ b/content/browser/renderer_host/DEPS @@ -24,6 +24,7 @@ specific_include_rules = { "+media/filters", ], "render_sandbox_host_linux\.cc": [ - "+third_party/WebKit/public/web/WebKit.h" + "+third_party/WebKit/public/web/WebKit.h", + "+third_party/WebKit/public/web/linux/WebFontInfo.h", ], } diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc index 086b8b2a0c..94ab1393c8 100644 --- a/content/browser/renderer_host/compositor_impl_android.cc +++ b/content/browser/renderer_host/compositor_impl_android.cc @@ -358,7 +358,8 @@ bool CompositorImpl::CopyTextureToBitmap(WebKit::WebGLId texture_id, return true; } -scoped_ptr<cc::OutputSurface> CompositorImpl::CreateOutputSurface() { +scoped_ptr<cc::OutputSurface> CompositorImpl::CreateOutputSurface( + bool fallback) { WebKit::WebGraphicsContext3D::Attributes attrs; attrs.shareResources = true; attrs.noAutomaticFlushes = true; diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h index ba004f9d01..845e830aad 100644 --- a/content/browser/renderer_host/compositor_impl_android.h +++ b/content/browser/renderer_host/compositor_impl_android.h @@ -77,7 +77,8 @@ class CONTENT_EXPORT CompositorImpl virtual void Layout() OVERRIDE {} virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta, float page_scale) OVERRIDE {} - virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface() OVERRIDE; + virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface(bool fallback) + OVERRIDE; virtual void DidInitializeOutputSurface(bool success) OVERRIDE {} virtual void WillCommit() OVERRIDE {} virtual void DidCommit() OVERRIDE {} diff --git a/content/browser/renderer_host/file_utilities_message_filter.cc b/content/browser/renderer_host/file_utilities_message_filter.cc index bae1079a7d..65645e014e 100644 --- a/content/browser/renderer_host/file_utilities_message_filter.cc +++ b/content/browser/renderer_host/file_utilities_message_filter.cc @@ -29,7 +29,6 @@ bool FileUtilitiesMessageFilter::OnMessageReceived(const IPC::Message& message, bool handled = true; IPC_BEGIN_MESSAGE_MAP_EX(FileUtilitiesMessageFilter, message, *message_was_ok) IPC_MESSAGE_HANDLER(FileUtilitiesMsg_GetFileInfo, OnGetFileInfo) - IPC_MESSAGE_HANDLER(FileUtilitiesMsg_OpenFile, OnOpenFile) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -53,41 +52,4 @@ void FileUtilitiesMessageFilter::OnGetFileInfo( *status = base::PLATFORM_FILE_ERROR_FAILED; } -void FileUtilitiesMessageFilter::OnOpenFile( - const base::FilePath& path, - int mode, - IPC::PlatformFileForTransit* result) { - // Open the file only when the child process has been granted permission to - // upload the file. - // TODO(jianli): Do we need separate permission to control opening the file? - if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile( - process_id_, path)) { -#if defined(OS_WIN) - *result = base::kInvalidPlatformFileValue; -#elif defined(OS_POSIX) - *result = base::FileDescriptor(base::kInvalidPlatformFileValue, true); -#endif - return; - } - - base::PlatformFile file_handle = base::CreatePlatformFile( - path, - (mode == 0) ? (base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ) - : (base::PLATFORM_FILE_CREATE_ALWAYS | - base::PLATFORM_FILE_WRITE), - NULL, NULL); - -#if defined(OS_WIN) - // Duplicate the file handle so that the renderer process can access the file. - if (!DuplicateHandle(GetCurrentProcess(), file_handle, - PeerHandle(), result, 0, false, - DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { - // file_handle is closed whether or not DuplicateHandle succeeds. - *result = INVALID_HANDLE_VALUE; - } -#else - *result = base::FileDescriptor(file_handle, true); -#endif -} - } // namespace content diff --git a/content/browser/renderer_host/file_utilities_message_filter.h b/content/browser/renderer_host/file_utilities_message_filter.h index 1b5640a0d7..948e6c20b4 100644 --- a/content/browser/renderer_host/file_utilities_message_filter.h +++ b/content/browser/renderer_host/file_utilities_message_filter.h @@ -39,9 +39,6 @@ class FileUtilitiesMessageFilter : public BrowserMessageFilter { void OnGetFileInfo(const base::FilePath& path, base::PlatformFileInfo* result, base::PlatformFileError* status); - void OnOpenFile(const base::FilePath& path, - int mode, - IPC::PlatformFileForTransit* result); // The ID of this process. int process_id_; diff --git a/content/browser/renderer_host/input/touch_event_queue.cc b/content/browser/renderer_host/input/touch_event_queue.cc index 0a7b1d4fd9..56500e60fe 100644 --- a/content/browser/renderer_host/input/touch_event_queue.cc +++ b/content/browser/renderer_host/input/touch_event_queue.cc @@ -188,12 +188,13 @@ void TouchEventQueue::PopTouchEventWithAck(InputEventAckState ack_result) { // to the renderer, or touch-events being queued. base::AutoReset<bool> dispatching_touch_ack(&dispatching_touch_ack_, true); + base::TimeTicks now = base::TimeTicks::HighResNow(); for (WebTouchEventWithLatencyList::const_iterator iter = acked_event->begin(), end = acked_event->end(); iter != end; ++iter) { ui::LatencyInfo* latency = const_cast<ui::LatencyInfo*>(&(iter->latency)); - latency->AddLatencyNumber( - ui::INPUT_EVENT_LATENCY_ACKED_COMPONENT, 0, 0); + latency->AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_LATENCY_ACKED_COMPONENT, 0, 0, now, 1); client_->OnTouchEventAck((*iter), ack_result); } } diff --git a/content/browser/renderer_host/java/DEPS b/content/browser/renderer_host/java/DEPS index 430199d518..0551243588 100644 --- a/content/browser/renderer_host/java/DEPS +++ b/content/browser/renderer_host/java/DEPS @@ -1,3 +1,4 @@ include_rules = [ "+content/child", # For java bridge bindings + "+third_party/WebKit/public/web/WebBindings.h", # For java bridge bindings ] diff --git a/content/browser/renderer_host/media/audio_input_renderer_host.cc b/content/browser/renderer_host/media/audio_input_renderer_host.cc index 4a2f731a81..37d93ef8ca 100644 --- a/content/browser/renderer_host/media/audio_input_renderer_host.cc +++ b/content/browser/renderer_host/media/audio_input_renderer_host.cc @@ -15,6 +15,10 @@ #include "content/browser/renderer_host/media/web_contents_capture_util.h" #include "media/audio/audio_manager_base.h" +#if defined(USE_CRAS) +#include "media/audio/cras/audio_manager_cras.h" +#endif + namespace content { struct AudioInputRendererHost::AudioEntry { @@ -237,7 +241,18 @@ void AudioInputRendererHost::OnCreateStream( return; } - device_id = info->device.id; + if (info->device.type == content::MEDIA_SYSTEM_AUDIO_CAPTURE) { +#if defined(USE_CRAS) + // Use the special loopback device ID for system audio capture. + device_id = media::AudioManagerCras::kLoopbackDeviceId; +#else + SendErrorMessage(stream_id); + DLOG(WARNING) << "Loopback device is not supported on this platform"; + return; +#endif + } else { + device_id = info->device.id; + } } // Create a new AudioEntry structure. diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc index 3e322c5a43..e4e46b5ac9 100644 --- a/content/browser/renderer_host/media/media_stream_manager.cc +++ b/content/browser/renderer_host/media/media_stream_manager.cc @@ -265,10 +265,16 @@ std::string MediaStreamManager::GenerateStream( DCHECK(found_match || translated_video_device_id.empty()); } - if (options.video_type == MEDIA_SCREEN_VIDEO_CAPTURE) { - if (options.audio_type != MEDIA_NO_SERVICE) { + if (options.video_type == MEDIA_SCREEN_VIDEO_CAPTURE || + options.audio_type == MEDIA_SYSTEM_AUDIO_CAPTURE) { + // For screen capture we only support two valid combinations: + // (1) screen video capture only, or + // (2) screen video capture with system audio capture. + if (options.video_type != MEDIA_SCREEN_VIDEO_CAPTURE || + (options.audio_type != MEDIA_NO_SERVICE && + options.audio_type != MEDIA_SYSTEM_AUDIO_CAPTURE)) { // TODO(sergeyu): Surface error message to the calling JS code. - LOG(ERROR) << "Audio is not supported for screen capture streams."; + LOG(ERROR) << "Invalid screen capture request."; return std::string(); } diff --git a/content/browser/renderer_host/media/midi_dispatcher_host.cc b/content/browser/renderer_host/media/midi_dispatcher_host.cc new file mode 100644 index 0000000000..4771eb58cc --- /dev/null +++ b/content/browser/renderer_host/media/midi_dispatcher_host.cc @@ -0,0 +1,68 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/renderer_host/media/midi_dispatcher_host.h" + +#include "base/bind.h" +#include "content/browser/renderer_host/render_view_host_impl.h" +#include "content/common/media/midi_messages.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_thread.h" +#include "url/gurl.h" + +namespace content { + +MIDIDispatcherHost::MIDIDispatcherHost(int render_process_id, + BrowserContext* browser_context) + : render_process_id_(render_process_id), + browser_context_(browser_context) { +} + +MIDIDispatcherHost::~MIDIDispatcherHost() { +} + +bool MIDIDispatcherHost::OnMessageReceived(const IPC::Message& message, + bool* message_was_ok) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP_EX(MIDIDispatcherHost, message, *message_was_ok) + IPC_MESSAGE_HANDLER(MIDIHostMsg_RequestSysExPermission, + OnRequestSysExPermission) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP_EX() + return handled; +} + +void MIDIDispatcherHost::OverrideThreadForMessage( + const IPC::Message& message, BrowserThread::ID* thread) { + if (message.type() == MIDIHostMsg_RequestSysExPermission::ID) + *thread = BrowserThread::UI; +} + +void MIDIDispatcherHost::OnRequestSysExPermission(int render_view_id, + int client_id, + const GURL& origin) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + browser_context_->RequestMIDISysExPermission( + render_process_id_, + render_view_id, + origin, + base::Bind(&MIDIDispatcherHost::WasSysExPermissionGranted, + base::Unretained(this), + render_view_id, + client_id)); +} + +void MIDIDispatcherHost::WasSysExPermissionGranted(int render_view_id, + int client_id, + bool success) { + RenderViewHostImpl* r = + RenderViewHostImpl::FromID(render_process_id_, render_view_id); + if (!r) + return; + r->Send( + new MIDIMsg_SysExPermissionApproved(render_view_id, client_id, success)); +} + +} // namespace content diff --git a/content/browser/renderer_host/media/midi_dispatcher_host.h b/content/browser/renderer_host/media/midi_dispatcher_host.h new file mode 100644 index 0000000000..ee861551b4 --- /dev/null +++ b/content/browser/renderer_host/media/midi_dispatcher_host.h @@ -0,0 +1,48 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_MIDI_DISPATCHER_HOST_H_ +#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_MIDI_DISPATCHER_HOST_H_ + +#include "content/public/browser/browser_message_filter.h" + +class GURL; + +namespace content { + +class BrowserContext; + +// MIDIDispatcherHost handles permissions for using system exclusive messages. +// It works as BrowserMessageFilter to handle IPC messages between +// MIDIDispatcher running as a RenderViewObserver. +class MIDIDispatcherHost : public BrowserMessageFilter { + public: + MIDIDispatcherHost(int render_process_id, BrowserContext* browser_context); + + // BrowserMessageFilter implementation. + virtual bool OnMessageReceived(const IPC::Message& message, + bool* message_was_ok) OVERRIDE; + virtual void OverrideThreadForMessage( + const IPC::Message& message, BrowserThread::ID* thread) OVERRIDE; + + protected: + virtual ~MIDIDispatcherHost(); + + private: + void OnRequestSysExPermission(int render_view_id, + int client_id, + const GURL& origin); + void WasSysExPermissionGranted(int render_view_id, + int client_id, + bool success); + + int render_process_id_; + BrowserContext* browser_context_; + + DISALLOW_COPY_AND_ASSIGN(MIDIDispatcherHost); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_MIDI_DISPATCHER_HOST_H_ diff --git a/content/browser/renderer_host/media/midi_host.cc b/content/browser/renderer_host/media/midi_host.cc index aeb481c05c..6ed473afef 100644 --- a/content/browser/renderer_host/media/midi_host.cc +++ b/content/browser/renderer_host/media/midi_host.cc @@ -18,10 +18,24 @@ using media::MIDIManager; using media::MIDIPortInfoList; +// The total number of bytes which we're allowed to send to the OS +// before knowing that they have been successfully sent. +static const size_t kMaxInFlightBytes = 10 * 1024 * 1024; // 10 MB. + +// We keep track of the number of bytes successfully sent to +// the hardware. Every once in a while we report back to the renderer +// the number of bytes sent since the last report. This threshold determines +// how many bytes will be sent before reporting back to the renderer. +static const size_t kAcknowledgementThresholdBytes = 1024 * 1024; // 1 MB. + +static const uint8 kSysExMessage = 0xf0; + namespace content { MIDIHost::MIDIHost(media::MIDIManager* midi_manager) - : midi_manager_(midi_manager) { + : midi_manager_(midi_manager), + sent_bytes_in_flight_(0), + bytes_sent_since_last_acknowledgement_(0) { } MIDIHost::~MIDIHost() { @@ -77,11 +91,38 @@ void MIDIHost::OnStartSession(int client_id) { void MIDIHost::OnSendData(int port, const std::vector<uint8>& data, double timestamp) { - // TODO(crogers): we need to post this to a dedicated thread for - // sending MIDI. For now, we will not implement the sending of MIDI data. + if (!midi_manager_) + return; + + base::AutoLock auto_lock(in_flight_lock_); + + // Sanity check that we won't send too much. + if (sent_bytes_in_flight_ > kMaxInFlightBytes || + data.size() > kMaxInFlightBytes || + data.size() + sent_bytes_in_flight_ > kMaxInFlightBytes) + return; + + // For now disallow all System Exclusive messages even if we + // have permission. + // TODO(toyoshim): allow System Exclusive if browser has granted + // this client access. We'll likely need to pass a GURL + // here to compare against our permissions. + if (data.size() > 0 && data[0] >= kSysExMessage) + return; + +#if defined(OS_ANDROID) + // TODO(toyoshim): figure out why data() method does not compile on Android. NOTIMPLEMENTED(); - // if (midi_manager_) - // midi_manager_->SendMIDIData(port, data.data(), data.size(), timestamp); +#else + midi_manager_->DispatchSendMIDIData( + this, + port, + data.data(), + data.size(), + timestamp); +#endif + + sent_bytes_in_flight_ += data.size(); } void MIDIHost::ReceiveMIDIData( @@ -90,9 +131,37 @@ void MIDIHost::ReceiveMIDIData( size_t length, double timestamp) { TRACE_EVENT0("midi", "MIDIHost::ReceiveMIDIData"); + + // For now disallow all System Exclusive messages even if we + // have permission. + // TODO(toyoshim): allow System Exclusive if browser has granted + // this client access. We'll likely need to pass a GURL + // here to compare against our permissions. + if (length > 0 && data[0] >= kSysExMessage) + return; + // Send to the renderer. std::vector<uint8> v(data, data + length); Send(new MIDIMsg_DataReceived(port_index, v, timestamp)); } +void MIDIHost::AccumulateMIDIBytesSent(size_t n) { + { + base::AutoLock auto_lock(in_flight_lock_); + if (n <= sent_bytes_in_flight_) + sent_bytes_in_flight_ -= n; + } + + if (bytes_sent_since_last_acknowledgement_ + n >= + bytes_sent_since_last_acknowledgement_) + bytes_sent_since_last_acknowledgement_ += n; + + if (bytes_sent_since_last_acknowledgement_ >= + kAcknowledgementThresholdBytes) { + Send(new MIDIMsg_AcknowledgeSentData( + bytes_sent_since_last_acknowledgement_)); + bytes_sent_since_last_acknowledgement_ = 0; + } +} + } // namespace content diff --git a/content/browser/renderer_host/media/midi_host.h b/content/browser/renderer_host/media/midi_host.h index db9d937dc8..f6b2813264 100644 --- a/content/browser/renderer_host/media/midi_host.h +++ b/content/browser/renderer_host/media/midi_host.h @@ -37,6 +37,7 @@ class CONTENT_EXPORT MIDIHost const uint8* data, size_t length, double timestamp) OVERRIDE; + virtual void AccumulateMIDIBytesSent(size_t n) OVERRIDE; // Start session to access MIDI hardware. void OnStartSession(int client_id); @@ -52,8 +53,24 @@ class CONTENT_EXPORT MIDIHost virtual ~MIDIHost(); + // |midi_manager_| talks to the platform-specific MIDI APIs. + // It can be NULL if the platform (or our current implementation) + // does not support MIDI. If not supported then a call to + // OnRequestAccess() will always refuse access and a call to + // OnSendData() will do nothing. media::MIDIManager* const midi_manager_; + // The number of bytes sent to the platform-specific MIDI sending + // system, but not yet completed. + size_t sent_bytes_in_flight_; + + // The number of bytes successfully sent since the last time + // we've acknowledged back to the renderer. + size_t bytes_sent_since_last_acknowledgement_; + + // Protects access to |sent_bytes_in_flight_|. + base::Lock in_flight_lock_; + DISALLOW_COPY_AND_ASSIGN(MIDIHost); }; diff --git a/content/browser/renderer_host/media/screen_capture_device.cc b/content/browser/renderer_host/media/screen_capture_device.cc index e455c48f06..3edd6ccd91 100644 --- a/content/browser/renderer_host/media/screen_capture_device.cc +++ b/content/browser/renderer_host/media/screen_capture_device.cc @@ -359,10 +359,13 @@ void ScreenCaptureDevice::SetScreenCapturerForTest( core_->SetScreenCapturerForTest(capturer.Pass()); } -void ScreenCaptureDevice::Allocate(int width, int height, - int frame_rate, - EventHandler* event_handler) { - core_->Allocate(width, height, frame_rate, event_handler); +void ScreenCaptureDevice::Allocate( + const media::VideoCaptureCapability& capture_format, + EventHandler* observer) { + core_->Allocate(capture_format.width, + capture_format.height, + capture_format.frame_rate, + observer); } void ScreenCaptureDevice::Start() { diff --git a/content/browser/renderer_host/media/screen_capture_device.h b/content/browser/renderer_host/media/screen_capture_device.h index c8b47aab78..df338d7219 100644 --- a/content/browser/renderer_host/media/screen_capture_device.h +++ b/content/browser/renderer_host/media/screen_capture_device.h @@ -33,9 +33,8 @@ class CONTENT_EXPORT ScreenCaptureDevice : public media::VideoCaptureDevice { scoped_ptr<webrtc::ScreenCapturer> capturer); // VideoCaptureDevice interface. - virtual void Allocate(int width, int height, - int frame_rate, - EventHandler* event_handler) OVERRIDE; + virtual void Allocate(const media::VideoCaptureCapability& capture_format, + EventHandler* observer) OVERRIDE; virtual void Start() OVERRIDE; virtual void Stop() OVERRIDE; virtual void DeAllocate() OVERRIDE; diff --git a/content/browser/renderer_host/media/screen_capture_device_unittest.cc b/content/browser/renderer_host/media/screen_capture_device_unittest.cc index 224c872a7f..c3ca06f8bb 100644 --- a/content/browser/renderer_host/media/screen_capture_device_unittest.cc +++ b/content/browser/renderer_host/media/screen_capture_device_unittest.cc @@ -120,7 +120,15 @@ TEST_F(ScreenCaptureDeviceTest, MAYBE_Capture) { SaveArg<1>(&frame_size), InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal))); - capture_device.Allocate(640, 480, kFrameRate, &frame_observer); + media::VideoCaptureCapability capture_format( + 640, + 480, + kFrameRate, + media::VideoCaptureCapability::kI420, + 0, + false, + media::ConstantResolutionVideoCaptureDevice); + capture_device.Allocate(capture_format, &frame_observer); capture_device.Start(); EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout())); capture_device.Stop(); @@ -158,8 +166,15 @@ TEST_F(ScreenCaptureDeviceTest, ScreenResolutionChange) { SaveArg<1>(&frame_size), InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal))); - capture_device.Allocate(kTestFrameWidth1, kTestFrameHeight1, - kFrameRate, &frame_observer); + media::VideoCaptureCapability capture_format( + kTestFrameWidth1, + kTestFrameHeight1, + kFrameRate, + media::VideoCaptureCapability::kI420, + 0, + false, + media::ConstantResolutionVideoCaptureDevice); + capture_device.Allocate(capture_format, &frame_observer); capture_device.Start(); // Capture first frame. EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout())); diff --git a/content/browser/renderer_host/media/video_capture_controller.cc b/content/browser/renderer_host/media/video_capture_controller.cc index feae74a190..bac43289a2 100644 --- a/content/browser/renderer_host/media/video_capture_controller.cc +++ b/content/browser/renderer_host/media/video_capture_controller.cc @@ -601,6 +601,8 @@ void VideoCaptureController::DoFrameInfoOnIOThread() { void VideoCaptureController::DoFrameInfoChangedOnIOThread( const media::VideoCaptureCapability& info) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + // TODO(mcasas): Here we should reallocate the VideoCaptureBufferPool, if + // needed, to support the new video capture format. See crbug.com/266082. for (ControllerClients::iterator client_it = controller_clients_.begin(); client_it != controller_clients_.end(); ++client_it) { (*client_it)->event_handler->OnFrameInfoChanged( @@ -637,11 +639,7 @@ void VideoCaptureController::SendFrameInfoAndBuffers(ControllerClient* client) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DCHECK(frame_info_available_); client->event_handler->OnFrameInfo(client->controller_id, - frame_info_.width, frame_info_.height, - frame_info_.frame_rate); - if (!buffer_pool_.get()) - return; - + frame_info_); for (int buffer_id = 0; buffer_id < buffer_pool_->count(); ++buffer_id) { base::SharedMemoryHandle remote_handle = buffer_pool_->ShareToProcess(buffer_id, client->render_process_handle); diff --git a/content/browser/renderer_host/media/video_capture_controller_event_handler.h b/content/browser/renderer_host/media/video_capture_controller_event_handler.h index 3d28c44097..c4844af2f7 100644 --- a/content/browser/renderer_host/media/video_capture_controller_event_handler.h +++ b/content/browser/renderer_host/media/video_capture_controller_event_handler.h @@ -9,6 +9,10 @@ #include "base/time/time.h" #include "content/common/content_export.h" +namespace media { +struct VideoCaptureCapability; +} + namespace content { // ID used for identifying an object of VideoCaptureController. @@ -41,9 +45,7 @@ class CONTENT_EXPORT VideoCaptureControllerEventHandler { // The frame resolution the VideoCaptureDevice capture video in. virtual void OnFrameInfo(const VideoCaptureControllerID& id, - int width, - int height, - int frame_rate) = 0; + const media::VideoCaptureCapability& format) = 0; // The frame resolution the VideoCaptureDevice capture video in. virtual void OnFrameInfoChanged(const VideoCaptureControllerID& id, diff --git a/content/browser/renderer_host/media/video_capture_controller_unittest.cc b/content/browser/renderer_host/media/video_capture_controller_unittest.cc index 58b9564b7a..c4b716d2e3 100644 --- a/content/browser/renderer_host/media/video_capture_controller_unittest.cc +++ b/content/browser/renderer_host/media/video_capture_controller_unittest.cc @@ -78,10 +78,9 @@ class MockVideoCaptureControllerEventHandler base::Bind(&VideoCaptureController::ReturnBuffer, controller_, controller_id_, this, buffer_id)); } - virtual void OnFrameInfo(const VideoCaptureControllerID& id, - int width, - int height, - int frame_per_second) OVERRIDE { + virtual void OnFrameInfo( + const VideoCaptureControllerID& id, + const media::VideoCaptureCapability& format) OVERRIDE { EXPECT_EQ(id, controller_id_); DoFrameInfo(id); } @@ -115,9 +114,17 @@ class MockVideoCaptureManager : public VideoCaptureManager { void Start(const media::VideoCaptureParams& capture_params, media::VideoCaptureDevice::EventHandler* vc_receiver) OVERRIDE { StartCapture(capture_params.width, capture_params.height, vc_receiver); - video_capture_device_->Allocate(capture_params.width, capture_params.height, - capture_params.frame_per_second, - vc_receiver); + // TODO(mcasas): Add testing for variable resolution video capture devices, + // supported by FakeVideoCaptureDevice. See crbug.com/261410, second part. + media::VideoCaptureCapability capture_format( + capture_params.width, + capture_params.height, + capture_params.frame_per_second, + media::VideoCaptureCapability::kI420, + 0, + false, + media::ConstantResolutionVideoCaptureDevice); + video_capture_device_->Allocate(capture_format, vc_receiver); video_capture_device_->Start(); } diff --git a/content/browser/renderer_host/media/video_capture_host.cc b/content/browser/renderer_host/media/video_capture_host.cc index 1d2379d068..bc7c8c19d7 100644 --- a/content/browser/renderer_host/media/video_capture_host.cc +++ b/content/browser/renderer_host/media/video_capture_host.cc @@ -83,13 +83,12 @@ void VideoCaptureHost::OnBufferReady( void VideoCaptureHost::OnFrameInfo( const VideoCaptureControllerID& controller_id, - int width, - int height, - int frame_per_second) { + const media::VideoCaptureCapability& format) { BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, + BrowserThread::IO, + FROM_HERE, base::Bind(&VideoCaptureHost::DoSendFrameInfoOnIOThread, - this, controller_id, width, height, frame_per_second)); + this, controller_id, format)); } void VideoCaptureHost::OnFrameInfoChanged( @@ -162,18 +161,17 @@ void VideoCaptureHost::DoEndedOnIOThread( void VideoCaptureHost::DoSendFrameInfoOnIOThread( const VideoCaptureControllerID& controller_id, - int width, - int height, - int frame_per_second) { + const media::VideoCaptureCapability& format) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); if (entries_.find(controller_id) == entries_.end()) return; media::VideoCaptureParams params; - params.width = width; - params.height = height; - params.frame_per_second = frame_per_second; + params.width = format.width; + params.height = format.height; + params.frame_per_second = format.frame_rate; + params.frame_size_type = format.frame_size_type; Send(new VideoCaptureMsg_DeviceInfo(controller_id.device_id, params)); Send(new VideoCaptureMsg_StateChanged(controller_id.device_id, VIDEO_CAPTURE_STATE_STARTED)); @@ -216,11 +214,12 @@ void VideoCaptureHost::OnStartCapture(int device_id, const media::VideoCaptureParams& params) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DVLOG(1) << "VideoCaptureHost::OnStartCapture, device_id " << device_id - << ", (" << params.width - << ", " << params.height - << ", " << params.frame_per_second - << ", " << params.session_id - << ")"; + << ", (" << params.width << ", " << params.height << ", " + << params.frame_per_second << ", " << params.session_id + << ", variable resolution device:" + << ((params.frame_size_type == + media::VariableResolutionVideoCaptureDevice) ? "yes" : "no") + << ")"; VideoCaptureControllerID controller_id(device_id); DCHECK(entries_.find(controller_id) == entries_.end()); diff --git a/content/browser/renderer_host/media/video_capture_host.h b/content/browser/renderer_host/media/video_capture_host.h index 3ce428b8a5..025b849de9 100644 --- a/content/browser/renderer_host/media/video_capture_host.h +++ b/content/browser/renderer_host/media/video_capture_host.h @@ -45,6 +45,10 @@ #include "content/public/browser/browser_message_filter.h" #include "ipc/ipc_message.h" +namespace media { +struct VideoCaptureCapability; +} + namespace content { class MediaStreamManager; @@ -68,10 +72,9 @@ class CONTENT_EXPORT VideoCaptureHost virtual void OnBufferReady(const VideoCaptureControllerID& id, int buffer_id, base::Time timestamp) OVERRIDE; - virtual void OnFrameInfo(const VideoCaptureControllerID& id, - int width, - int height, - int frame_per_second) OVERRIDE; + virtual void OnFrameInfo( + const VideoCaptureControllerID& id, + const media::VideoCaptureCapability& format) OVERRIDE; virtual void OnFrameInfoChanged(const VideoCaptureControllerID& id, int width, int height, @@ -122,13 +125,10 @@ class CONTENT_EXPORT VideoCaptureHost int buffer_id, base::Time timestamp); - // Send information about frame resolution and frame rate + // Send information about the capture parameters (resolution, frame rate etc) // to the VideoCaptureMessageFilter. - void DoSendFrameInfoOnIOThread( - const VideoCaptureControllerID& controller_id, - int width, - int height, - int frame_per_second); + void DoSendFrameInfoOnIOThread(const VideoCaptureControllerID& controller_id, + const media::VideoCaptureCapability& format); // Send newly changed information about frame resolution and frame rate // to the VideoCaptureMessageFilter. diff --git a/content/browser/renderer_host/media/video_capture_manager.cc b/content/browser/renderer_host/media/video_capture_manager.cc index 61574a2626..aa27e12803 100644 --- a/content/browser/renderer_host/media/video_capture_manager.cc +++ b/content/browser/renderer_host/media/video_capture_manager.cc @@ -269,6 +269,14 @@ void VideoCaptureManager::OnStart( video_capture_receiver->OnError(); return; } + // TODO(mcasas): Variable resolution video capture devices, are not yet + // fully supported, see crbug.com/261410, second part, and crbug.com/266082 . + if (capture_params.frame_size_type != + media::ConstantResolutionVideoCaptureDevice) { + LOG(DFATAL) << "Only constant Video Capture resolution device supported."; + video_capture_receiver->OnError(); + return; + } Controllers::iterator cit = controllers_.find(video_capture_device); if (cit != controllers_.end()) { cit->second->ready_to_delete = false; @@ -276,8 +284,13 @@ void VideoCaptureManager::OnStart( // Possible errors are signaled to video_capture_receiver by // video_capture_device. video_capture_receiver to perform actions. - video_capture_device->Allocate(capture_params.width, capture_params.height, - capture_params.frame_per_second, + media::VideoCaptureCapability params_as_capability_copy; + params_as_capability_copy.width = capture_params.width; + params_as_capability_copy.height = capture_params.height; + params_as_capability_copy.frame_rate = capture_params.frame_per_second; + params_as_capability_copy.session_id = capture_params.session_id; + params_as_capability_copy.frame_size_type = capture_params.frame_size_type; + video_capture_device->Allocate(params_as_capability_copy, video_capture_receiver); video_capture_device->Start(); } diff --git a/content/browser/renderer_host/media/web_contents_video_capture_device.cc b/content/browser/renderer_host/media/web_contents_video_capture_device.cc index 8a6757aa75..2e63e94172 100644 --- a/content/browser/renderer_host/media/web_contents_video_capture_device.cc +++ b/content/browser/renderer_host/media/web_contents_video_capture_device.cc @@ -1069,7 +1069,7 @@ void WebContentsVideoCaptureDevice::Impl::Allocate( // Initialize capture settings which will be consistent for the // duration of the capture. - media::VideoCaptureCapability settings = { 0 }; + media::VideoCaptureCapability settings; settings.width = width; settings.height = height; @@ -1248,9 +1248,14 @@ media::VideoCaptureDevice* WebContentsVideoCaptureDevice::Create( } void WebContentsVideoCaptureDevice::Allocate( - int width, int height, int frame_rate, - VideoCaptureDevice::EventHandler* consumer) { - impl_->Allocate(width, height, frame_rate, consumer); + const media::VideoCaptureCapability& capture_format, + VideoCaptureDevice::EventHandler* observer) { + DVLOG(1) << "Allocating " << capture_format.width << "x" + << capture_format.height; + impl_->Allocate(capture_format.width, + capture_format.height, + capture_format.frame_rate, + observer); } void WebContentsVideoCaptureDevice::Start() { diff --git a/content/browser/renderer_host/media/web_contents_video_capture_device.h b/content/browser/renderer_host/media/web_contents_video_capture_device.h index 44c1a8f4ba..94ac0680f6 100644 --- a/content/browser/renderer_host/media/web_contents_video_capture_device.h +++ b/content/browser/renderer_host/media/web_contents_video_capture_device.h @@ -42,10 +42,8 @@ class CONTENT_EXPORT WebContentsVideoCaptureDevice virtual ~WebContentsVideoCaptureDevice(); // VideoCaptureDevice implementation. - virtual void Allocate(int width, - int height, - int frame_rate, - VideoCaptureDevice::EventHandler* consumer) OVERRIDE; + virtual void Allocate(const media::VideoCaptureCapability& capture_format, + VideoCaptureDevice::EventHandler* observer) OVERRIDE; virtual void Start() OVERRIDE; virtual void Stop() OVERRIDE; virtual void DeAllocate() OVERRIDE; diff --git a/content/browser/renderer_host/media/web_contents_video_capture_device_unittest.cc b/content/browser/renderer_host/media/web_contents_video_capture_device_unittest.cc index deb8741ee4..7eb28eac39 100644 --- a/content/browser/renderer_host/media/web_contents_video_capture_device_unittest.cc +++ b/content/browser/renderer_host/media/web_contents_video_capture_device_unittest.cc @@ -541,7 +541,15 @@ TEST_F(WebContentsVideoCaptureDeviceTest, InvalidInitialWebContentsError) { // practice; we should be able to recover gracefully. ResetWebContents(); - device()->Allocate(kTestWidth, kTestHeight, kTestFramesPerSecond, consumer()); + media::VideoCaptureCapability capture_format( + kTestWidth, + kTestHeight, + kTestFramesPerSecond, + media::VideoCaptureCapability::kI420, + 0, + false, + media::ConstantResolutionVideoCaptureDevice); + device()->Allocate(capture_format, consumer()); device()->Start(); ASSERT_NO_FATAL_FAILURE(consumer()->WaitForError()); device()->DeAllocate(); @@ -550,7 +558,15 @@ TEST_F(WebContentsVideoCaptureDeviceTest, InvalidInitialWebContentsError) { TEST_F(WebContentsVideoCaptureDeviceTest, WebContentsDestroyed) { // We'll simulate the tab being closed after the capture pipeline is up and // running. - device()->Allocate(kTestWidth, kTestHeight, kTestFramesPerSecond, consumer()); + media::VideoCaptureCapability capture_format( + kTestWidth, + kTestHeight, + kTestFramesPerSecond, + media::VideoCaptureCapability::kI420, + 0, + false, + media::ConstantResolutionVideoCaptureDevice); + device()->Allocate(capture_format, consumer()); device()->Start(); // Do one capture to prove @@ -571,7 +587,15 @@ TEST_F(WebContentsVideoCaptureDeviceTest, WebContentsDestroyed) { TEST_F(WebContentsVideoCaptureDeviceTest, StopDeviceBeforeCaptureMachineCreation) { - device()->Allocate(kTestWidth, kTestHeight, kTestFramesPerSecond, consumer()); + media::VideoCaptureCapability capture_format( + kTestWidth, + kTestHeight, + kTestFramesPerSecond, + media::VideoCaptureCapability::kI420, + 0, + false, + media::ConstantResolutionVideoCaptureDevice); + device()->Allocate(capture_format, consumer()); device()->Start(); // Make a point of not running the UI messageloop here. device()->Stop(); @@ -589,8 +613,16 @@ TEST_F(WebContentsVideoCaptureDeviceTest, StopWithRendererWorkToDo) { // Set up the test to use RGB copies and an normal source()->SetCanCopyToVideoFrame(false); source()->SetUseFrameSubscriber(false); - device()->Allocate(kTestWidth, kTestHeight, kTestFramesPerSecond, - consumer()); + media::VideoCaptureCapability capture_format( + kTestWidth, + kTestHeight, + kTestFramesPerSecond, + media::VideoCaptureCapability::kI420, + 0, + false, + media::ConstantResolutionVideoCaptureDevice); + device()->Allocate(capture_format, consumer()); + device()->Start(); // Make a point of not running the UI messageloop here. // TODO(ajwong): Why do we care? @@ -611,7 +643,15 @@ TEST_F(WebContentsVideoCaptureDeviceTest, StopWithRendererWorkToDo) { } TEST_F(WebContentsVideoCaptureDeviceTest, DeviceRestart) { - device()->Allocate(kTestWidth, kTestHeight, kTestFramesPerSecond, consumer()); + media::VideoCaptureCapability capture_format( + kTestWidth, + kTestHeight, + kTestFramesPerSecond, + media::VideoCaptureCapability::kI420, + 0, + false, + media::ConstantResolutionVideoCaptureDevice); + device()->Allocate(capture_format, consumer()); device()->Start(); base::RunLoop().RunUntilIdle(); source()->SetSolidColor(SK_ColorRED); @@ -645,7 +685,15 @@ TEST_F(WebContentsVideoCaptureDeviceTest, DeviceRestart) { // consumer. The test will alternate between the three capture paths, simulating // falling in and out of accelerated compositing. TEST_F(WebContentsVideoCaptureDeviceTest, GoesThroughAllTheMotions) { - device()->Allocate(kTestWidth, kTestHeight, kTestFramesPerSecond, consumer()); + media::VideoCaptureCapability capture_format( + kTestWidth, + kTestHeight, + kTestFramesPerSecond, + media::VideoCaptureCapability::kI420, + 0, + false, + media::ConstantResolutionVideoCaptureDevice); + device()->Allocate(capture_format, consumer()); device()->Start(); @@ -693,14 +741,33 @@ TEST_F(WebContentsVideoCaptureDeviceTest, GoesThroughAllTheMotions) { } TEST_F(WebContentsVideoCaptureDeviceTest, RejectsInvalidAllocateParams) { - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(&media::VideoCaptureDevice::Allocate, - base::Unretained(device()), 1280, 720, -2, consumer())); + media::VideoCaptureCapability capture_format( + 1280, + 720, + -2, + media::VideoCaptureCapability::kI420, + 0, + false, + media::ConstantResolutionVideoCaptureDevice); + BrowserThread::PostTask(BrowserThread::UI, + FROM_HERE, + base::Bind(&media::VideoCaptureDevice::Allocate, + base::Unretained(device()), + capture_format, + consumer())); ASSERT_NO_FATAL_FAILURE(consumer()->WaitForError()); } TEST_F(WebContentsVideoCaptureDeviceTest, BadFramesGoodFrames) { - device()->Allocate(kTestWidth, kTestHeight, kTestFramesPerSecond, consumer()); + media::VideoCaptureCapability capture_format( + kTestWidth, + kTestHeight, + kTestFramesPerSecond, + media::VideoCaptureCapability::kI420, + 0, + false, + media::ConstantResolutionVideoCaptureDevice); + device()->Allocate(capture_format, consumer()); // 1x1 is too small to process; we intend for this to result in an error. source()->SetCopyResultSize(1, 1); diff --git a/content/browser/renderer_host/pepper/pepper_file_ref_host.cc b/content/browser/renderer_host/pepper/pepper_file_ref_host.cc index 59d2c08221..5370af9d85 100644 --- a/content/browser/renderer_host/pepper/pepper_file_ref_host.cc +++ b/content/browser/renderer_host/pepper/pepper_file_ref_host.cc @@ -53,8 +53,9 @@ PepperFileRefHost::PepperFileRefHost(BrowserPpapiHost* host, return; } - PepperFileSystemBrowserHost* fs_host = - fs_resource_host->AsPepperFileSystemBrowserHost(); + PepperFileSystemBrowserHost* fs_host = NULL; + if (fs_resource_host->IsFileSystemHost()) + fs_host = static_cast<PepperFileSystemBrowserHost*>(fs_resource_host); if (fs_host == NULL) { DLOG(ERROR) << "Filesystem PP_Resource is not PepperFileSystemBrowserHost"; return; @@ -101,8 +102,8 @@ PepperFileRefHost::PepperFileRefHost(BrowserPpapiHost* host, PepperFileRefHost::~PepperFileRefHost() { } -PepperFileRefHost* PepperFileRefHost::AsPepperFileRefHost() { - return this; +bool PepperFileRefHost::IsFileRefHost() { + return true; } PP_FileSystemType PepperFileRefHost::GetFileSystemType() const { @@ -219,7 +220,9 @@ int32_t PepperFileRefHost::OnRename(ppapi::host::HostMessageContext* context, if (!resource_host) return PP_ERROR_BADRESOURCE; - PepperFileRefHost* file_ref_host = resource_host->AsPepperFileRefHost(); + PepperFileRefHost* file_ref_host = NULL; + if (resource_host->IsFileRefHost()) + file_ref_host = static_cast<PepperFileRefHost*>(resource_host); if (!file_ref_host) return PP_ERROR_BADRESOURCE; diff --git a/content/browser/renderer_host/pepper/pepper_file_ref_host.h b/content/browser/renderer_host/pepper/pepper_file_ref_host.h index ce742faebf..5d76576432 100644 --- a/content/browser/renderer_host/pepper/pepper_file_ref_host.h +++ b/content/browser/renderer_host/pepper/pepper_file_ref_host.h @@ -73,7 +73,7 @@ class CONTENT_EXPORT PepperFileRefHost virtual int32_t OnResourceMessageReceived( const IPC::Message& msg, ppapi::host::HostMessageContext* context) OVERRIDE; - virtual PepperFileRefHost* AsPepperFileRefHost() OVERRIDE; + virtual bool IsFileRefHost() OVERRIDE; // Required to support Rename(). PP_FileSystemType GetFileSystemType() const; diff --git a/content/browser/renderer_host/pepper/pepper_file_system_browser_host.cc b/content/browser/renderer_host/pepper/pepper_file_system_browser_host.cc index 4189741d34..1a10da77b8 100644 --- a/content/browser/renderer_host/pepper/pepper_file_system_browser_host.cc +++ b/content/browser/renderer_host/pepper/pepper_file_system_browser_host.cc @@ -84,9 +84,8 @@ int32_t PepperFileSystemBrowserHost::OnResourceMessageReceived( return PP_ERROR_FAILED; } -PepperFileSystemBrowserHost* -PepperFileSystemBrowserHost::AsPepperFileSystemBrowserHost() { - return this; +bool PepperFileSystemBrowserHost::IsFileSystemHost() { + return true; } int32_t PepperFileSystemBrowserHost::OnHostMsgOpen( diff --git a/content/browser/renderer_host/pepper/pepper_file_system_browser_host.h b/content/browser/renderer_host/pepper/pepper_file_system_browser_host.h index 61db917863..3eb146e5b7 100644 --- a/content/browser/renderer_host/pepper/pepper_file_system_browser_host.h +++ b/content/browser/renderer_host/pepper/pepper_file_system_browser_host.h @@ -32,7 +32,7 @@ class PepperFileSystemBrowserHost : virtual int32_t OnResourceMessageReceived( const IPC::Message& msg, ppapi::host::HostMessageContext* context) OVERRIDE; - virtual PepperFileSystemBrowserHost* AsPepperFileSystemBrowserHost() OVERRIDE; + virtual bool IsFileSystemHost() OVERRIDE; // Supports FileRefs direct access on the host side. PP_FileSystemType GetType() const { return type_; } diff --git a/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.cc b/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.cc index 4695386820..ef740625bd 100644 --- a/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.cc +++ b/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.cc @@ -9,6 +9,7 @@ #include "base/files/file_enumerator.h" #include "base/threading/sequenced_worker_pool.h" #include "content/browser/child_process_security_policy_impl.h" +#include "content/browser/renderer_host/pepper/pepper_security_helper.h" #include "content/public/browser/browser_ppapi_host.h" #include "content/public/browser/browser_thread.h" #include "content/public/common/content_constants.h" @@ -24,19 +25,24 @@ namespace content { namespace { -// Used to check if the renderer has permission for the requested operation. -// TODO(viettrungluu): Verify these. They don't necessarily quite make sense, -// but it seems to be approximately what the file system code does. -const int kReadPermissions = base::PLATFORM_FILE_OPEN | - base::PLATFORM_FILE_READ | - base::PLATFORM_FILE_EXCLUSIVE_READ; -const int kWritePermissions = base::PLATFORM_FILE_OPEN | - base::PLATFORM_FILE_CREATE | - base::PLATFORM_FILE_CREATE_ALWAYS | - base::PLATFORM_FILE_OPEN_TRUNCATED | - base::PLATFORM_FILE_WRITE | - base::PLATFORM_FILE_EXCLUSIVE_WRITE | - base::PLATFORM_FILE_WRITE_ATTRIBUTES; + +bool CanRead(int process_id, const base::FilePath& path) { + return ChildProcessSecurityPolicyImpl::GetInstance()-> + CanReadFile(process_id, path); +} + +bool CanWrite(int process_id, const base::FilePath& path) { + return ChildProcessSecurityPolicyImpl::GetInstance()-> + CanWriteFile(process_id, path); +} + +bool CanReadWrite(int process_id, const base::FilePath& path) { + ChildProcessSecurityPolicyImpl* policy = + ChildProcessSecurityPolicyImpl::GetInstance(); + return policy->CanReadFile(process_id, path) && + policy->CanWriteFile(process_id, path); +} + } // namespace PepperFlashFileMessageFilter::PepperFlashFileMessageFilter( @@ -109,16 +115,24 @@ int32_t PepperFlashFileMessageFilter::OnResourceMessageReceived( int32_t PepperFlashFileMessageFilter::OnOpenFile( ppapi::host::HostMessageContext* context, const ppapi::PepperFilePath& path, - int flags) { - base::FilePath full_path = ValidateAndConvertPepperFilePath(path, flags); + int pp_open_flags) { + base::FilePath full_path = ValidateAndConvertPepperFilePath( + path, + base::Bind(&CanOpenWithPepperFlags, pp_open_flags)); if (full_path.empty()) { return ppapi::PlatformFileErrorToPepperError( base::PLATFORM_FILE_ERROR_ACCESS_DENIED); } + int platform_file_flags = 0; + if (!ppapi::PepperFileOpenFlagsToPlatformFileFlags( + pp_open_flags, &platform_file_flags)) { + return base::PLATFORM_FILE_ERROR_FAILED; + } + base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED; base::PlatformFile file_handle = base::CreatePlatformFile( - full_path, flags, NULL, &error); + full_path, platform_file_flags, NULL, &error); if (error != base::PLATFORM_FILE_OK) { DCHECK_EQ(file_handle, base::kInvalidPlatformFileValue); return ppapi::PlatformFileErrorToPepperError(error); @@ -149,9 +163,9 @@ int32_t PepperFlashFileMessageFilter::OnRenameFile( const ppapi::PepperFilePath& from_path, const ppapi::PepperFilePath& to_path) { base::FilePath from_full_path = ValidateAndConvertPepperFilePath( - from_path, kWritePermissions); + from_path, base::Bind(&CanWrite)); base::FilePath to_full_path = ValidateAndConvertPepperFilePath( - to_path, kWritePermissions); + to_path, base::Bind(&CanWrite)); if (from_full_path.empty() || to_full_path.empty()) { return ppapi::PlatformFileErrorToPepperError( base::PLATFORM_FILE_ERROR_ACCESS_DENIED); @@ -167,7 +181,7 @@ int32_t PepperFlashFileMessageFilter::OnDeleteFileOrDir( const ppapi::PepperFilePath& path, bool recursive) { base::FilePath full_path = ValidateAndConvertPepperFilePath( - path, kWritePermissions); + path, base::Bind(&CanWrite)); if (full_path.empty()) { return ppapi::PlatformFileErrorToPepperError( base::PLATFORM_FILE_ERROR_ACCESS_DENIED); @@ -181,7 +195,7 @@ int32_t PepperFlashFileMessageFilter::OnCreateDir( ppapi::host::HostMessageContext* context, const ppapi::PepperFilePath& path) { base::FilePath full_path = ValidateAndConvertPepperFilePath( - path, kWritePermissions); + path, base::Bind(&CanWrite)); if (full_path.empty()) { return ppapi::PlatformFileErrorToPepperError( base::PLATFORM_FILE_ERROR_ACCESS_DENIED); @@ -196,7 +210,7 @@ int32_t PepperFlashFileMessageFilter::OnQueryFile( ppapi::host::HostMessageContext* context, const ppapi::PepperFilePath& path) { base::FilePath full_path = ValidateAndConvertPepperFilePath( - path, kReadPermissions); + path, base::Bind(&CanRead)); if (full_path.empty()) { return ppapi::PlatformFileErrorToPepperError( base::PLATFORM_FILE_ERROR_ACCESS_DENIED); @@ -213,7 +227,7 @@ int32_t PepperFlashFileMessageFilter::OnGetDirContents( ppapi::host::HostMessageContext* context, const ppapi::PepperFilePath& path) { base::FilePath full_path = ValidateAndConvertPepperFilePath( - path, kReadPermissions); + path, base::Bind(&CanRead)); if (full_path.empty()) { return ppapi::PlatformFileErrorToPepperError( base::PLATFORM_FILE_ERROR_ACCESS_DENIED); @@ -243,7 +257,7 @@ int32_t PepperFlashFileMessageFilter::OnCreateTemporaryFile( ppapi::PepperFilePath dir_path( ppapi::PepperFilePath::DOMAIN_MODULE_LOCAL, base::FilePath()); base::FilePath validated_dir_path = ValidateAndConvertPepperFilePath( - dir_path, kReadPermissions | kWritePermissions); + dir_path, base::Bind(&CanReadWrite)); if (validated_dir_path.empty() || (!base::DirectoryExists(validated_dir_path) && !file_util::CreateDirectory(validated_dir_path))) { @@ -282,13 +296,13 @@ int32_t PepperFlashFileMessageFilter::OnCreateTemporaryFile( base::FilePath PepperFlashFileMessageFilter::ValidateAndConvertPepperFilePath( const ppapi::PepperFilePath& pepper_path, - int flags) { + const CheckPermissionsCallback& check_permissions_callback) const { base::FilePath file_path; // Empty path returned on error. switch (pepper_path.domain()) { case ppapi::PepperFilePath::DOMAIN_ABSOLUTE: if (pepper_path.path().IsAbsolute() && - ChildProcessSecurityPolicyImpl::GetInstance()->HasPermissionsForFile( - render_process_id_, pepper_path.path(), flags)) + check_permissions_callback.Run(render_process_id_, + pepper_path.path())) file_path = pepper_path.path(); break; case ppapi::PepperFilePath::DOMAIN_MODULE_LOCAL: diff --git a/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.h b/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.h index 7931764cce..f89d7cf590 100644 --- a/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.h +++ b/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.h @@ -5,6 +5,7 @@ #ifndef CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FLASH_FILE_MESSAGE_FILTER_H_ #define CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FLASH_FILE_MESSAGE_FILTER_H_ +#include "base/callback_forward.h" #include "base/compiler_specific.h" #include "base/files/file_path.h" #include "base/memory/ref_counted.h" @@ -40,6 +41,9 @@ class PepperFlashFileMessageFilter : public ppapi::host::ResourceMessageFilter { static base::FilePath GetDataDirName(const base::FilePath& profile_path); private: + typedef base::Callback<bool(int, const base::FilePath&)> + CheckPermissionsCallback; + virtual ~PepperFlashFileMessageFilter(); // ppapi::host::ResourceMessageFilter overrides. @@ -51,7 +55,7 @@ class PepperFlashFileMessageFilter : public ppapi::host::ResourceMessageFilter { int32_t OnOpenFile(ppapi::host::HostMessageContext* context, const ppapi::PepperFilePath& path, - int flags); + int pp_open_flags); int32_t OnRenameFile(ppapi::host::HostMessageContext* context, const ppapi::PepperFilePath& from_path, const ppapi::PepperFilePath& to_path); @@ -68,7 +72,7 @@ class PepperFlashFileMessageFilter : public ppapi::host::ResourceMessageFilter { base::FilePath ValidateAndConvertPepperFilePath( const ppapi::PepperFilePath& pepper_path, - int flags); + const CheckPermissionsCallback& check_permissions_callback) const; base::FilePath plugin_data_directory_; int render_process_id_; diff --git a/content/browser/renderer_host/pepper/pepper_internal_file_ref_backend.h b/content/browser/renderer_host/pepper/pepper_internal_file_ref_backend.h index dce7889466..fb8a6cf760 100644 --- a/content/browser/renderer_host/pepper/pepper_internal_file_ref_backend.h +++ b/content/browser/renderer_host/pepper/pepper_internal_file_ref_backend.h @@ -18,6 +18,8 @@ namespace content { +class PepperFileSystemBrowserHost; + // Implementations of FileRef operations for internal filesystems. class PepperInternalFileRefBackend : public PepperFileRefBackend { public: diff --git a/content/browser/renderer_host/pepper/pepper_renderer_connection.cc b/content/browser/renderer_host/pepper/pepper_renderer_connection.cc index 8703bed9fa..55b5ab6e7e 100644 --- a/content/browser/renderer_host/pepper/pepper_renderer_connection.cc +++ b/content/browser/renderer_host/pepper/pepper_renderer_connection.cc @@ -7,6 +7,8 @@ #include "content/browser/browser_child_process_host_impl.h" #include "content/browser/ppapi_plugin_process_host.h" #include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h" +#include "content/common/pepper_renderer_instance_data.h" +#include "content/common/view_messages.h" #include "content/browser/renderer_host/pepper/pepper_file_ref_host.h" #include "content/public/browser/content_browser_client.h" #include "content/public/common/content_client.h" @@ -16,12 +18,24 @@ #include "ppapi/proxy/ppapi_messages.h" #include "ppapi/proxy/resource_message_params.h" -#include "content/common/view_messages.h" - namespace content { -namespace { -BrowserPpapiHostImpl* GetHostForChildProcess(int child_process_id) { +PepperRendererConnection::PepperRendererConnection(int render_process_id) + : render_process_id_(render_process_id) { + // Only give the renderer permission for stable APIs. + in_process_host_.reset(new BrowserPpapiHostImpl(this, + ppapi::PpapiPermissions(), + "", + base::FilePath(), + base::FilePath(), + false)); +} + +PepperRendererConnection::~PepperRendererConnection() { +} + +BrowserPpapiHostImpl* PepperRendererConnection::GetHostForChildProcess( + int child_process_id) const { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); // Find the plugin which this message refers to. Check NaCl plugins first. @@ -40,24 +54,31 @@ BrowserPpapiHostImpl* GetHostForChildProcess(int child_process_id) { } } } - return host; -} -} // namespace -PepperRendererConnection::PepperRendererConnection() { -} + // If the message is being sent from an in-process plugin, we own the + // BrowserPpapiHost. + if (!host && child_process_id == 0) { + host = in_process_host_.get(); + } -PepperRendererConnection::~PepperRendererConnection() { + return host; } bool PepperRendererConnection::OnMessageReceived(const IPC::Message& msg, bool* message_was_ok) { + if (in_process_host_->GetPpapiHost()->OnMessageReceived(msg)) + return true; + bool handled = true; IPC_BEGIN_MESSAGE_MAP_EX(PepperRendererConnection, msg, *message_was_ok) IPC_MESSAGE_HANDLER(PpapiHostMsg_CreateResourceHostFromHost, OnMsgCreateResourceHostFromHost) IPC_MESSAGE_HANDLER(PpapiHostMsg_FileRef_GetInfoForRenderer, OnMsgFileRefGetInfoForRenderer) + IPC_MESSAGE_HANDLER(ViewHostMsg_DidCreateInProcessInstance, + OnMsgDidCreateInProcessInstance) + IPC_MESSAGE_HANDLER(ViewHostMsg_DidDeleteInProcessInstance, + OnMsgDidDeleteInProcessInstance) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP_EX() @@ -71,6 +92,7 @@ void PepperRendererConnection::OnMsgCreateResourceHostFromHost( PP_Instance instance, const IPC::Message& nested_msg) { BrowserPpapiHostImpl* host = GetHostForChildProcess(child_process_id); + int pending_resource_host_id; if (!host) { DLOG(ERROR) << "Invalid plugin process ID."; @@ -107,29 +129,48 @@ void PepperRendererConnection::OnMsgCreateResourceHostFromHost( void PepperRendererConnection::OnMsgFileRefGetInfoForRenderer( int routing_id, int child_process_id, - const ppapi::proxy::ResourceMessageCallParams& params) { - PP_FileSystemType fs_type = PP_FILESYSTEMTYPE_INVALID; - std::string file_system_url_spec; - base::FilePath external_path; + int32_t sequence, + const std::vector<PP_Resource>& resources) { + std::vector<PP_Resource> out_resources; + std::vector<PP_FileSystemType> fs_types; + std::vector<std::string> file_system_url_specs; + std::vector<base::FilePath> external_paths; + BrowserPpapiHostImpl* host = GetHostForChildProcess(child_process_id); if (host) { - ppapi::host::ResourceHost* resource_host = - host->GetPpapiHost()->GetResourceHost(params.pp_resource()); - if (resource_host) { - PepperFileRefHost* file_ref_host = resource_host->AsPepperFileRefHost(); - if (file_ref_host) { - fs_type = file_ref_host->GetFileSystemType(); - file_system_url_spec = file_ref_host->GetFileSystemURLSpec(); - external_path = file_ref_host->GetExternalPath(); + for (size_t i = 0; i < resources.size(); ++i) { + ppapi::host::ResourceHost* resource_host = + host->GetPpapiHost()->GetResourceHost(resources[i]); + if (resource_host && resource_host->IsFileRefHost()) { + PepperFileRefHost* file_ref_host = + static_cast<PepperFileRefHost*>(resource_host); + out_resources.push_back(resources[i]); + fs_types.push_back(file_ref_host->GetFileSystemType()); + file_system_url_specs.push_back(file_ref_host->GetFileSystemURLSpec()); + external_paths.push_back(file_ref_host->GetExternalPath()); } } } Send(new PpapiHostMsg_FileRef_GetInfoForRendererReply( routing_id, - params.sequence(), - fs_type, - file_system_url_spec, - external_path)); + sequence, + out_resources, + fs_types, + file_system_url_specs, + external_paths)); +} + +void PepperRendererConnection::OnMsgDidCreateInProcessInstance( + PP_Instance instance, + const PepperRendererInstanceData& instance_data) { + PepperRendererInstanceData data = instance_data; + data.render_process_id = render_process_id_; + in_process_host_->AddInstance(instance, data); +} + +void PepperRendererConnection::OnMsgDidDeleteInProcessInstance( + PP_Instance instance) { + in_process_host_->DeleteInstance(instance); } } // namespace content diff --git a/content/browser/renderer_host/pepper/pepper_renderer_connection.h b/content/browser/renderer_host/pepper/pepper_renderer_connection.h index 5b2054ee83..43923465d0 100644 --- a/content/browser/renderer_host/pepper/pepper_renderer_connection.h +++ b/content/browser/renderer_host/pepper/pepper_renderer_connection.h @@ -7,10 +7,13 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" #include "content/public/browser/browser_message_filter.h" #include "ppapi/c/pp_instance.h" #include "ppapi/c/pp_resource.h" +class GURL; + namespace ppapi { namespace proxy { class ResourceMessageCallParams; @@ -19,13 +22,16 @@ class ResourceMessageCallParams; namespace content { +class BrowserPpapiHostImpl; +struct PepperRendererInstanceData; + // This class represents a connection from the browser to the renderer for // sending/receiving pepper ResourceHost related messages. When the browser // and renderer communicate about ResourceHosts, they should pass the plugin // process ID to identify which plugin they are talking about. class PepperRendererConnection : public BrowserMessageFilter { public: - PepperRendererConnection(); + explicit PepperRendererConnection(int render_process_id); // BrowserMessageFilter overrides. virtual bool OnMessageReceived(const IPC::Message& msg, @@ -34,6 +40,11 @@ class PepperRendererConnection : public BrowserMessageFilter { private: virtual ~PepperRendererConnection(); + // Returns the host for the child process for the given |child_process_id|. + // If |child_process_id| is 0, returns the host owned by this + // PepperRendererConnection, which serves as the host for in-process plugins. + BrowserPpapiHostImpl* GetHostForChildProcess(int child_process_id) const; + void OnMsgCreateResourceHostFromHost( int routing_id, int child_process_id, @@ -44,7 +55,21 @@ class PepperRendererConnection : public BrowserMessageFilter { void OnMsgFileRefGetInfoForRenderer( int routing_id, int child_process_id, - const ppapi::proxy::ResourceMessageCallParams& params); + int32_t sequence_num, + const std::vector<PP_Resource>& resources); + + void OnMsgDidCreateInProcessInstance( + PP_Instance instance, + const PepperRendererInstanceData& instance_data); + void OnMsgDidDeleteInProcessInstance(PP_Instance instance); + + int render_process_id_; + + // We have a single BrowserPpapiHost per-renderer for all in-process plugins + // running. This is just a work-around allowing new style resources to work + // with the browser when running in-process but it means that plugin-specific + // information (like the plugin name) won't be available. + scoped_ptr<BrowserPpapiHostImpl> in_process_host_; DISALLOW_COPY_AND_ASSIGN(PepperRendererConnection); }; diff --git a/content/browser/renderer_host/pepper/pepper_security_helper.cc b/content/browser/renderer_host/pepper/pepper_security_helper.cc new file mode 100644 index 0000000000..5402823f01 --- /dev/null +++ b/content/browser/renderer_host/pepper/pepper_security_helper.cc @@ -0,0 +1,54 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/renderer_host/pepper/pepper_security_helper.h" + +#include "base/logging.h" +#include "content/browser/child_process_security_policy_impl.h" +#include "ppapi/c/ppb_file_io.h" + +namespace content { + +bool CanOpenWithPepperFlags(int pp_open_flags, int child_id, + const base::FilePath& file) { + ChildProcessSecurityPolicyImpl* policy = + ChildProcessSecurityPolicyImpl::GetInstance(); + + bool pp_read = !!(pp_open_flags & PP_FILEOPENFLAG_READ); + bool pp_write = !!(pp_open_flags & PP_FILEOPENFLAG_WRITE); + bool pp_create = !!(pp_open_flags & PP_FILEOPENFLAG_CREATE); + bool pp_truncate = !!(pp_open_flags & PP_FILEOPENFLAG_TRUNCATE); + bool pp_exclusive = !!(pp_open_flags & PP_FILEOPENFLAG_EXCLUSIVE); + bool pp_append = !!(pp_open_flags & PP_FILEOPENFLAG_APPEND); + + if (pp_read && !policy->CanReadFile(child_id, file)) + return false; + + if (pp_write && !policy->CanWriteFile(child_id, file)) + return false; + + if (pp_append) { + // Given ChildSecurityPolicyImpl's current definition of permissions, + // APPEND is never supported. + return false; + } + + if (pp_truncate && !pp_write) + return false; + + if (pp_create) { + if (pp_exclusive) { + return policy->CanCreateFile(child_id, file); + } else { + // Asks for too much, but this is the only grant that allows overwrite. + return policy->CanCreateWriteFile(child_id, file); + } + } else if (pp_truncate) { + return policy->CanCreateWriteFile(child_id, file); + } + + return true; +} + +} // namespace content diff --git a/content/browser/renderer_host/pepper/pepper_security_helper.h b/content/browser/renderer_host/pepper/pepper_security_helper.h new file mode 100644 index 0000000000..4a3cea5874 --- /dev/null +++ b/content/browser/renderer_host/pepper/pepper_security_helper.h @@ -0,0 +1,21 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_SECURITY_HELPER_H_ +#define CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_SECURITY_HELPER_H_ + +#include "base/files/file_path.h" +#include "content/common/content_export.h" + +namespace content { + +// Helper method that returns whether or not the child process is allowed to +// open the specified |file| with the specified |pp_open_flags|. +CONTENT_EXPORT bool CanOpenWithPepperFlags(int pp_open_flags, + int child_id, + const base::FilePath& file); + +} // namespace content + +#endif // CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_SECURITY_HELPER_H_ diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc index 3f2f100b84..daab4ed75e 100644 --- a/content/browser/renderer_host/render_message_filter.cc +++ b/content/browser/renderer_host/render_message_filter.cc @@ -25,6 +25,7 @@ #include "content/browser/plugin_process_host.h" #include "content/browser/plugin_service_impl.h" #include "content/browser/ppapi_plugin_process_host.h" +#include "content/browser/renderer_host/pepper/pepper_security_helper.h" #include "content/browser/renderer_host/render_process_host_impl.h" #include "content/browser/renderer_host/render_view_host_delegate.h" #include "content/browser/renderer_host/render_widget_helper.h" @@ -61,6 +62,7 @@ #include "net/http/http_cache.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_getter.h" +#include "ppapi/shared_impl/file_type_conversion.h" #include "third_party/WebKit/public/web/WebNotificationPresenter.h" #include "ui/gfx/color_profile.h" #include "webkit/plugins/plugin_constants.h" @@ -393,6 +395,7 @@ bool RenderMessageFilter::OnMessageReceived(const IPC::Message& message, OnDidDeleteOutOfProcessPepperInstance) IPC_MESSAGE_HANDLER(ViewHostMsg_OpenChannelToPpapiBroker, OnOpenChannelToPpapiBroker) + IPC_MESSAGE_HANDLER(ViewHostMsg_AsyncOpenPepperFile, OnAsyncOpenPepperFile) #endif IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_UpdateRect, render_widget_helper_->DidReceiveBackingStoreMsg(message)) @@ -408,7 +411,6 @@ bool RenderMessageFilter::OnMessageReceived(const IPC::Message& message, IPC_MESSAGE_HANDLER(ViewHostMsg_DidGenerateCacheableMetadata, OnCacheableMetadataAvailable) IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_Keygen, OnKeygen) - IPC_MESSAGE_HANDLER(ViewHostMsg_AsyncOpenFile, OnAsyncOpenFile) IPC_MESSAGE_HANDLER(ViewHostMsg_GetCPUUsage, OnGetCPUUsage) IPC_MESSAGE_HANDLER(ViewHostMsg_GetAudioHardwareConfig, OnGetAudioHardwareConfig) @@ -987,15 +989,19 @@ void RenderMessageFilter::OnKeygenOnWorkerThread( Send(reply_msg); } -void RenderMessageFilter::OnAsyncOpenFile(const IPC::Message& msg, - const base::FilePath& path, - int flags, - int message_id) { +void RenderMessageFilter::OnAsyncOpenPepperFile(const IPC::Message& msg, + const base::FilePath& path, + int pp_open_flags, + int message_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - if (!ChildProcessSecurityPolicyImpl::GetInstance()->HasPermissionsForFile( - render_process_id_, path, flags)) { - DLOG(ERROR) << "Bad flags in ViewMsgHost_AsyncOpenFile message: " << flags; + int platform_file_flags = 0; + if (!CanOpenWithPepperFlags(pp_open_flags, render_process_id_, path) || + !ppapi::PepperFileOpenFlagsToPlatformFileFlags( + pp_open_flags, &platform_file_flags)) { + DLOG(ERROR) << + "Bad pp_open_flags in ViewMsgHost_AsyncOpenPepperFile message: " << + pp_open_flags; RecordAction(UserMetricsAction("BadMessageTerminate_AOF")); BadMessageReceived(); return; @@ -1003,25 +1009,29 @@ void RenderMessageFilter::OnAsyncOpenFile(const IPC::Message& msg, BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, base::Bind( - &RenderMessageFilter::AsyncOpenFileOnFileThread, this, - path, flags, message_id, msg.routing_id())); + &RenderMessageFilter::AsyncOpenPepperFileOnFileThread, this, + path, platform_file_flags, message_id, msg.routing_id())); } -void RenderMessageFilter::AsyncOpenFileOnFileThread(const base::FilePath& path, - int flags, - int message_id, - int routing_id) { +void RenderMessageFilter::AsyncOpenPepperFileOnFileThread( + const base::FilePath& path, + int platform_file_flags, + int message_id, + int routing_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); base::PlatformFileError error_code = base::PLATFORM_FILE_OK; base::PlatformFile file = base::CreatePlatformFile( - path, flags, NULL, &error_code); + path, platform_file_flags, NULL, &error_code); IPC::PlatformFileForTransit file_for_transit = file != base::kInvalidPlatformFileValue ? IPC::GetFileHandleForProcess(file, PeerHandle(), true) : IPC::InvalidPlatformFileForTransit(); - IPC::Message* reply = new ViewMsg_AsyncOpenFile_ACK( - routing_id, error_code, file_for_transit, message_id); + IPC::Message* reply = new ViewMsg_AsyncOpenPepperFile_ACK( + routing_id, + error_code, + file_for_transit, + message_id); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(base::IgnoreResult(&RenderMessageFilter::Send), this, reply)); diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h index 00cdc6a0d8..e6f19957d1 100644 --- a/content/browser/renderer_host/render_message_filter.h +++ b/content/browser/renderer_host/render_message_filter.h @@ -224,14 +224,14 @@ class RenderMessageFilter : public BrowserMessageFilter { const std::string& challenge_string, const GURL& url, IPC::Message* reply_msg); - void OnAsyncOpenFile(const IPC::Message& msg, - const base::FilePath& path, - int flags, - int message_id); - void AsyncOpenFileOnFileThread(const base::FilePath& path, - int flags, - int message_id, - int routing_id); + void OnAsyncOpenPepperFile(const IPC::Message& msg, + const base::FilePath& path, + int pp_open_flags, + int message_id); + void AsyncOpenPepperFileOnFileThread(const base::FilePath& path, + int platform_file_flags, + int message_id, + int routing_id); void OnMediaLogEvents(const std::vector<media::MediaLogEvent>&); // Check the policy for getting cookies. Gets the cookies if allowed. diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index a9ea4d9f6b..22b27e987d 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc @@ -54,7 +54,6 @@ #include "content/browser/gpu/gpu_process_host.h" #include "content/browser/gpu/shader_disk_cache.h" #include "content/browser/histogram_message_filter.h" -#include "content/browser/hyphenator/hyphenator_message_filter.h" #include "content/browser/indexed_db/indexed_db_context_impl.h" #include "content/browser/indexed_db/indexed_db_dispatcher_host.h" #include "content/browser/loader/resource_message_filter.h" @@ -75,6 +74,7 @@ #include "content/browser/renderer_host/media/audio_renderer_host.h" #include "content/browser/renderer_host/media/device_request_message_filter.h" #include "content/browser/renderer_host/media/media_stream_dispatcher_host.h" +#include "content/browser/renderer_host/media/midi_dispatcher_host.h" #include "content/browser/renderer_host/media/midi_host.h" #include "content/browser/renderer_host/media/peer_connection_tracker_host.h" #include "content/browser/renderer_host/media/video_capture_host.h" @@ -410,7 +410,8 @@ RenderProcessHostImpl::RenderProcessHostImpl( ignore_input_events_(false), supports_browser_plugin_(supports_browser_plugin), is_guest_(is_guest), - gpu_observer_registered_(false) { + gpu_observer_registered_(false), + power_monitor_broadcaster_(this) { widget_helper_ = new RenderWidgetHelper(); ChildProcessSecurityPolicyImpl::GetInstance()->Add(GetID()); @@ -622,6 +623,7 @@ void RenderProcessHostImpl::CreateMessageFilters() { media_internals, media_stream_manager)); channel_->AddFilter( new MIDIHost(BrowserMainLoop::GetInstance()->midi_manager())); + channel_->AddFilter(new MIDIDispatcherHost(GetID(), browser_context)); channel_->AddFilter(new VideoCaptureHost(media_stream_manager)); channel_->AddFilter(new AppCacheDispatcherHost( storage_partition_impl_->GetAppCacheService(), @@ -658,7 +660,7 @@ void RenderProcessHostImpl::CreateMessageFilters() { #if defined(ENABLE_PLUGINS) // TODO(raymes): PepperMessageFilter should be removed from here. channel_->AddFilter(new PepperMessageFilter(GetID(), browser_context)); - channel_->AddFilter(new PepperRendererConnection); + channel_->AddFilter(new PepperRendererConnection(GetID())); #endif #if defined(ENABLE_INPUT_SPEECH) channel_->AddFilter(new InputTagSpeechDispatcherHost( @@ -719,7 +721,6 @@ void RenderProcessHostImpl::CreateMessageFilters() { channel_->AddFilter(new DeviceMotionBrowserMessageFilter()); channel_->AddFilter(new ProfilerMessageFilter(PROCESS_TYPE_RENDERER)); channel_->AddFilter(new HistogramMessageFilter()); - channel_->AddFilter(new HyphenatorMessageFilter(this)); #if defined(USE_TCMALLOC) && (defined(OS_LINUX) || defined(OS_ANDROID)) if (CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableMemoryBenchmarking)) @@ -884,6 +885,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer( switches::kDisableGLMultisampling, switches::kDisableGpuVsync, switches::kDisableGpu, + switches::kDisableGpuCompositing, switches::kDisableHistogramCustomizer, switches::kDisableLocalStorage, switches::kDisableLogging, @@ -900,7 +902,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer( #endif switches::kDisableWebAudio, #if defined(ENABLE_WEBRTC) - switches::kEnableDeviceEnumeration, + switches::kDisableDeviceEnumeration, switches::kEnableSCTPDataChannels, #endif switches::kEnableWebAnimationsCSS, @@ -953,7 +955,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer( // Allow this to be set when invoking the browser and relayed along. switches::kEnableSandboxLogging, #endif - switches::kEnableSoftwareCompositingGLAdapter, + switches::kEnableSoftwareCompositing, switches::kEnableStatsTable, switches::kEnableThreadedCompositing, switches::kEnableCompositingForFixedPosition, @@ -1026,6 +1028,9 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer( switches::kEnableWebGLDraftExtensions, switches::kTraceToConsole, switches::kEnableDeviceMotion, +#if defined(OS_ANDROID) + switches::kDisableDeviceMotion, +#endif // Please keep these in alphabetical order. Compositor switches here should // also be added to chrome/browser/chromeos/login/chrome_restart_request.cc. cc::switches::kBackgroundColorInsteadOfCheckerboard, diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h index 65d85a00b3..72ec846303 100644 --- a/content/browser/renderer_host/render_process_host_impl.h +++ b/content/browser/renderer_host/render_process_host_impl.h @@ -13,6 +13,7 @@ #include "base/process/process.h" #include "base/timer/timer.h" #include "content/browser/child_process_launcher.h" +#include "content/browser/power_monitor_message_broadcaster.h" #include "content/common/content_export.h" #include "content/public/browser/global_request_id.h" #include "content/public/browser/gpu_data_manager_observer.h" @@ -320,6 +321,9 @@ class CONTENT_EXPORT RenderProcessHostImpl // than once. bool gpu_observer_registered_; + // Forwards power state messages to the renderer process. + PowerMonitorMessageBroadcaster power_monitor_broadcaster_; + DISALLOW_COPY_AND_ASSIGN(RenderProcessHostImpl); }; diff --git a/content/browser/renderer_host/render_sandbox_host_linux.cc b/content/browser/renderer_host/render_sandbox_host_linux.cc index d2b45923ce..87d31dca88 100644 --- a/content/browser/renderer_host/render_sandbox_host_linux.cc +++ b/content/browser/renderer_host/render_sandbox_host_linux.cc @@ -40,6 +40,7 @@ using WebKit::WebCString; using WebKit::WebFontInfo; using WebKit::WebUChar; +using WebKit::WebUChar32; namespace content { @@ -142,8 +143,8 @@ class SandboxIPCProcess { HandleFontMatchRequest(fd, pickle, iter, fds); } else if (kind == FontConfigIPC::METHOD_OPEN) { HandleFontOpenRequest(fd, pickle, iter, fds); - } else if (kind == LinuxSandbox::METHOD_GET_FONT_FAMILY_FOR_CHARS) { - HandleGetFontFamilyForChars(fd, pickle, iter, fds); + } else if (kind == LinuxSandbox::METHOD_GET_FONT_FAMILY_FOR_CHAR) { + HandleGetFontFamilyForChar(fd, pickle, iter, fds); } else if (kind == LinuxSandbox::METHOD_LOCALTIME) { HandleLocaltime(fd, pickle, iter, fds); } else if (kind == LinuxSandbox::METHOD_GET_CHILD_WITH_INODE) { @@ -233,46 +234,23 @@ class SandboxIPCProcess { } } - void HandleGetFontFamilyForChars(int fd, const Pickle& pickle, - PickleIterator iter, - std::vector<int>& fds) { + void HandleGetFontFamilyForChar(int fd, const Pickle& pickle, + PickleIterator iter, + std::vector<int>& fds) { // The other side of this call is // chrome/renderer/renderer_sandbox_support_linux.cc - int num_chars; - if (!pickle.ReadInt(&iter, &num_chars)) - return; - - // We don't want a corrupt renderer asking too much of us, it might - // overflow later in the code. - static const int kMaxChars = 4096; - if (num_chars < 1 || num_chars > kMaxChars) { - LOG(WARNING) << "HandleGetFontFamilyForChars: too many chars: " - << num_chars; - return; - } - EnsureWebKitInitialized(); - scoped_ptr<WebUChar[]> chars(new WebUChar[num_chars]); - - for (int i = 0; i < num_chars; ++i) { - uint32_t c; - if (!pickle.ReadUInt32(&iter, &c)) { - return; - } - - chars[i] = c; - } + WebUChar32 c; + if (!pickle.ReadInt(&iter, &c)) + return; std::string preferred_locale; if (!pickle.ReadString(&iter, &preferred_locale)) return; WebKit::WebFontFamily family; - WebFontInfo::familyForChars(chars.get(), - num_chars, - preferred_locale.c_str(), - &family); + WebFontInfo::familyForChar(c, preferred_locale.c_str(), &family); Pickle reply; if (family.name.data()) { diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index c08d897f86..edd21fe598 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc @@ -2107,7 +2107,7 @@ void RenderWidgetHostImpl::OnGestureEventAck( overscroll_controller_->ReceivedEventACK(event, processed); if (view_) - view_->GestureEventAck(event.type); + view_->GestureEventAck(event.type, ack_result); } void RenderWidgetHostImpl::OnTouchEventAck( @@ -2439,12 +2439,14 @@ void RenderWidgetHostImpl::FrameSwapped(const ui::LatencyInfo& latency_info) { // results in final frame swap. base::TimeDelta delta = latency_info.swap_timestamp - original_component.event_time; - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Event.Latency.TouchToScrollUpdateSwap", - delta.InMicroseconds(), - 0, - 1000000, - 100); + for (size_t i = 0; i < original_component.event_count; i++) { + UMA_HISTOGRAM_CUSTOM_COUNTS( + "Event.Latency.TouchToScrollUpdateSwap", + delta.InMicroseconds(), + 0, + 1000000, + 100); + } rendering_stats_.scroll_update_count += original_component.event_count; rendering_stats_.total_scroll_update_latency += original_component.event_count * diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index 806f35ff2f..3282ca90a8 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc @@ -46,6 +46,8 @@ namespace content { namespace { +const int kUndefinedOutputSurfaceId = -1; + void InsertSyncPointAndAckForGpu( int gpu_host_id, int route_id, const std::string& return_mailbox) { uint32 sync_point = @@ -87,6 +89,7 @@ RenderWidgetHostViewAndroid::RenderWidgetHostViewAndroid( ime_adapter_android_(this), cached_background_color_(SK_ColorWHITE), texture_id_in_layer_(0), + current_mailbox_output_surface_id_(kUndefinedOutputSurfaceId), weak_ptr_factory_(this), overscroll_effect_enabled_(true) { if (CompositorImpl::UsesDirectGL()) { @@ -632,6 +635,11 @@ void RenderWidgetHostViewAndroid::OnSwapCompositorFrame( if (!frame->gl_frame_data || frame->gl_frame_data->mailbox.IsZero()) return; + if (output_surface_id != current_mailbox_output_surface_id_) { + current_mailbox_ = gpu::Mailbox(); + current_mailbox_output_surface_id_ = kUndefinedOutputSurfaceId; + } + base::Closure callback = base::Bind(&InsertSyncPointAndAckForCompositor, host_->GetProcess()->GetID(), output_surface_id, @@ -647,7 +655,7 @@ void RenderWidgetHostViewAndroid::OnSwapCompositorFrame( if (layer_->layer_tree_host()) layer_->layer_tree_host()->SetLatencyInfo(frame->metadata.latency_info); - BuffersSwapped(frame->gl_frame_data->mailbox, callback); + BuffersSwapped(frame->gl_frame_data->mailbox, output_surface_id, callback); } void RenderWidgetHostViewAndroid::SynchronousFrameMetadata( @@ -702,11 +710,12 @@ void RenderWidgetHostViewAndroid::AcceleratedSurfaceBuffersSwapped( texture_size_in_layer_ = params.size; content_size_in_layer_ = params.size; - BuffersSwapped(mailbox, callback); + BuffersSwapped(mailbox, kUndefinedOutputSurfaceId, callback); } void RenderWidgetHostViewAndroid::BuffersSwapped( const gpu::Mailbox& mailbox, + uint32_t output_surface_id, const base::Closure& ack_callback) { ImageTransportFactoryAndroid* factory = ImageTransportFactoryAndroid::GetInstance(); @@ -727,6 +736,7 @@ void RenderWidgetHostViewAndroid::BuffersSwapped( ResetClipping(); current_mailbox_ = mailbox; + current_mailbox_output_surface_id_ = output_surface_id; if (host_->is_hidden()) ack_callback.Run(); @@ -814,6 +824,7 @@ void RenderWidgetHostViewAndroid::AcceleratedSurfaceRelease() { texture_id_in_layer_); texture_id_in_layer_ = 0; current_mailbox_ = gpu::Mailbox(); + current_mailbox_output_surface_id_ = kUndefinedOutputSurfaceId; } } @@ -864,6 +875,15 @@ void RenderWidgetHostViewAndroid::UnhandledWheelEvent( // intentionally empty, like RenderWidgetHostViewViews } +void RenderWidgetHostViewAndroid::GestureEventAck( + int gesture_event_type, + InputEventAckState ack_result) { + if (gesture_event_type == WebKit::WebInputEvent::GestureFlingStart && + ack_result == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) { + content_view_core_->UnhandledFlingStartEvent(); + } +} + InputEventAckState RenderWidgetHostViewAndroid::FilterInputEvent( const WebKit::WebInputEvent& input_event) { if (host_) { @@ -878,6 +898,12 @@ InputEventAckState RenderWidgetHostViewAndroid::FilterInputEvent( void RenderWidgetHostViewAndroid::OnAccessibilityNotifications( const std::vector<AccessibilityHostMsg_NotificationParams>& params) { + if (!host_ || + host_->accessibility_mode() != AccessibilityModeComplete || + !content_view_core_) { + return; + } + if (!GetBrowserAccessibilityManager()) { SetBrowserAccessibilityManager( new BrowserAccessibilityManagerAndroid( @@ -1111,7 +1137,6 @@ void RenderWidgetHostViewAndroid::OnLostResources() { if (texture_layer_) texture_layer_->SetIsDrawable(false); texture_id_in_layer_ = 0; - current_mailbox_ = gpu::Mailbox(); RunAckCallbacks(); } diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h index 630ead9b0c..d9b0d97248 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.h +++ b/content/browser/renderer_host/render_widget_host_view_android.h @@ -149,6 +149,8 @@ class RenderWidgetHostViewAndroid const WebKit::WebMouseWheelEvent& event) OVERRIDE; virtual InputEventAckState FilterInputEvent( const WebKit::WebInputEvent& input_event) OVERRIDE; + virtual void GestureEventAck(int gesture_event_type, + InputEventAckState ack_result) OVERRIDE; virtual void OnAccessibilityNotifications( const std::vector<AccessibilityHostMsg_NotificationParams>& params) OVERRIDE; @@ -232,6 +234,7 @@ class RenderWidgetHostViewAndroid private: void BuffersSwapped(const gpu::Mailbox& mailbox, + uint32_t output_surface_id, const base::Closure& ack_callback); void RunAckCallbacks(); @@ -297,6 +300,7 @@ class RenderWidgetHostViewAndroid // The mailbox of the previously received frame. gpu::Mailbox current_mailbox_; + uint32_t current_mailbox_output_surface_id_; base::WeakPtrFactory<RenderWidgetHostViewAndroid> weak_ptr_factory_; diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index f95a70e40e..dc239349e4 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc @@ -979,8 +979,7 @@ bool RenderWidgetHostViewAura::HasFocus() const { } bool RenderWidgetHostViewAura::IsSurfaceAvailableForCopy() const { - return window_->layer()->has_external_content() || - !!host_->GetBackingStore(false); + return CanCopyToBitmap() || !!host_->GetBackingStore(false); } void RenderWidgetHostViewAura::Show() { @@ -1198,7 +1197,7 @@ void RenderWidgetHostViewAura::CopyFromCompositingSurface( const gfx::Rect& src_subrect, const gfx::Size& dst_size, const base::Callback<void(bool, const SkBitmap&)>& callback) { - if (!window_->layer()->has_external_content()) { + if (!CanCopyToBitmap()) { callback.Run(false, SkBitmap()); return; } @@ -1219,7 +1218,7 @@ void RenderWidgetHostViewAura::CopyFromCompositingSurfaceToVideoFrame( const gfx::Rect& src_subrect, const scoped_refptr<media::VideoFrame>& target, const base::Callback<void(bool)>& callback) { - if (!window_->layer()->has_external_content()) { + if (!CanCopyToVideoFrame()) { callback.Run(false); return; } @@ -1237,9 +1236,15 @@ void RenderWidgetHostViewAura::CopyFromCompositingSurfaceToVideoFrame( window_->layer()->RequestCopyOfOutput(request.Pass()); } +bool RenderWidgetHostViewAura::CanCopyToBitmap() const { + return GetCompositor() && window_->layer()->has_external_content(); +} + bool RenderWidgetHostViewAura::CanCopyToVideoFrame() const { - // TODO(skaslev): Implement this path for s/w compositing. - return window_->layer()->has_external_content() && + // TODO(skaslev): Implement this path for s/w compositing by handling software + // CopyOutputResult in CopyFromCompositingSurfaceHasResultForVideo(). + return GetCompositor() && + window_->layer()->has_external_content() && host_->is_accelerated_compositing_active(); } @@ -1363,8 +1368,18 @@ void RenderWidgetHostViewAura::SwapBuffersCompleted( const BufferPresentedCallback& ack_callback, const scoped_refptr<ui::Texture>& texture_to_return) { ui::Compositor* compositor = GetCompositor(); + if (!compositor) { + ack_callback.Run(false, texture_to_return); + } else { + AddOnCommitCallbackAndDisableLocks( + base::Bind(ack_callback, false, texture_to_return)); + } + + DidReceiveFrameFromRenderer(); +} - if (frame_subscriber() && current_surface_.get() != NULL) { +void RenderWidgetHostViewAura::DidReceiveFrameFromRenderer() { + if (frame_subscriber() && CanCopyToVideoFrame()) { const base::Time present_time = base::Time::Now(); scoped_refptr<media::VideoFrame> frame; RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback; @@ -1377,13 +1392,6 @@ void RenderWidgetHostViewAura::SwapBuffersCompleted( base::Bind(callback, present_time)); } } - - if (!compositor) { - ack_callback.Run(false, texture_to_return); - } else { - AddOnCommitCallbackAndDisableLocks( - base::Bind(ack_callback, false, texture_to_return)); - } } #if defined(OS_WIN) @@ -1468,6 +1476,7 @@ void RenderWidgetHostViewAura::SwapDelegatedFrame( AsWeakPtr(), output_surface_id)); } + DidReceiveFrameFromRenderer(); } void RenderWidgetHostViewAura::SendDelegatedFrameAck(uint32 output_surface_id) { @@ -1537,6 +1546,7 @@ void RenderWidgetHostViewAura::SwapSoftwareFrame( compositor->SetLatencyInfo(latency_info); if (paint_observer_) paint_observer_->OnUpdateCompositorContent(); + DidReceiveFrameFromRenderer(); } void RenderWidgetHostViewAura::SendSoftwareFrameAck( @@ -1945,7 +1955,8 @@ gfx::Rect RenderWidgetHostViewAura::GetBoundsInRootWindow() { return window_->GetToplevelWindow()->GetBoundsInScreen(); } -void RenderWidgetHostViewAura::GestureEventAck(int gesture_event_type) { +void RenderWidgetHostViewAura::GestureEventAck(int gesture_event_type, + InputEventAckState ack_result) { if (touch_editing_client_) touch_editing_client_->GestureEventAck(gesture_event_type); } @@ -2004,7 +2015,8 @@ gfx::GLSurfaceHandle RenderWidgetHostViewAura::GetCompositingSurface() { if (shared_surface_handle_.is_null()) { ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); shared_surface_handle_ = factory->CreateSharedSurfaceHandle(); - factory->AddObserver(this); + if (!shared_surface_handle_.is_null()) + factory->AddObserver(this); } return shared_surface_handle_; } @@ -2480,6 +2492,32 @@ void RenderWidgetHostViewAura::OnKeyEvent(ui::KeyEvent* event) { host_->Shutdown(); } } else { + // Windows does not have a specific key code for AltGr and sends + // left-Control and right-Alt when the AltGr key is pressed. Also + // Windows translates AltGr modifier to Ctrl+Alt modifier. To be compatible + // with this behavior, we re-write keyboard event from AltGr to Alt + Ctrl + // key event here. + if (event->key_code() == ui::VKEY_ALTGR) { + // Synthesize Ctrl & Alt events. + NativeWebKeyboardEvent ctrl_webkit_event( + event->type(), + false, + ui::VKEY_CONTROL, + event->flags(), + ui::EventTimeForNow().InSecondsF()); + host_->ForwardKeyboardEvent(ctrl_webkit_event); + + NativeWebKeyboardEvent alt_webkit_event( + event->type(), + false, + ui::VKEY_MENU, + event->flags(), + ui::EventTimeForNow().InSecondsF()); + host_->ForwardKeyboardEvent(alt_webkit_event); + event->SetHandled(); + return; + } + // We don't have to communicate with an input method here. if (!event->HasNativeEvent()) { NativeWebKeyboardEvent webkit_event( @@ -3151,7 +3189,7 @@ void RenderWidgetHostViewAura::RemovingFromRootWindow() { compositor->RemoveObserver(this); } -ui::Compositor* RenderWidgetHostViewAura::GetCompositor() { +ui::Compositor* RenderWidgetHostViewAura::GetCompositor() const { aura::RootWindow* root_window = window_->GetRootWindow(); return root_window ? root_window->compositor() : NULL; } diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h index 428da9469d..dafe42f447 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.h +++ b/content/browser/renderer_host/render_widget_host_view_aura.h @@ -222,7 +222,8 @@ class RenderWidgetHostViewAura virtual bool HasAcceleratedSurface(const gfx::Size& desired_size) OVERRIDE; virtual void GetScreenInfo(WebKit::WebScreenInfo* results) OVERRIDE; virtual gfx::Rect GetBoundsInRootWindow() OVERRIDE; - virtual void GestureEventAck(int gesture_event_type) OVERRIDE; + virtual void GestureEventAck(int gesture_event_type, + InputEventAckState ack_result) OVERRIDE; virtual void ProcessAckedTouchEvent( const TouchEventWithLatencyInfo& touch, InputEventAckState ack_result) OVERRIDE; @@ -327,6 +328,8 @@ class RenderWidgetHostViewAura virtual void OnRootWindowHostMoved(const aura::RootWindow* root, const gfx::Point& new_origin) OVERRIDE; + bool CanCopyToBitmap() const; + #if defined(OS_WIN) // Sets the cutout rects from constrained windows. These are rectangles that // windowed NPAPI plugins shouldn't paint in. Overwrites any previous cutout @@ -457,7 +460,7 @@ class RenderWidgetHostViewAura const base::Callback<void(bool)>& callback, scoped_ptr<cc::CopyOutputResult> result); - ui::Compositor* GetCompositor(); + ui::Compositor* GetCompositor() const; // Detaches |this| from the input method object. void DetachFromInputMethod(); @@ -508,6 +511,8 @@ class RenderWidgetHostViewAura void SendSoftwareFrameAck(uint32 output_surface_id, unsigned software_frame_id); + void DidReceiveFrameFromRenderer(); + BrowserAccessibilityManager* GetOrCreateBrowserAccessibilityManager(); #if defined(OS_WIN) diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc index 815b9446c0..b35d5b389b 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.cc +++ b/content/browser/renderer_host/render_widget_host_view_base.cc @@ -6,6 +6,7 @@ #include "base/logging.h" #include "content/browser/accessibility/browser_accessibility_manager.h" +#include "content/browser/gpu/gpu_data_manager_impl.h" #include "content/browser/renderer_host/basic_mouse_wheel_smooth_scroll_gesture.h" #include "content/browser/renderer_host/render_process_host_impl.h" #include "content/browser/renderer_host/render_widget_host_impl.h" @@ -265,15 +266,17 @@ void RenderWidgetHostViewBase::MovePluginWindowsHelper( flags |= SWP_HIDEWINDOW; #if defined(USE_AURA) - // Without this flag, Windows repaints the parent area uncovered by this - // move. However it only looks at the plugin rectangle and ignores the - // clipping region. In Aura, the browser chrome could be under the plugin, - // and if Windows tries to paint it synchronously inside EndDeferWindowsPos - // then it won't have the data and it will flash white. So instead we - // manually redraw the plugin. - // Why not do this for native Windows? Not sure if there are any performance - // issues with this. - flags |= SWP_NOREDRAW; + if (GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) { + // Without this flag, Windows repaints the parent area uncovered by this + // move. However when software compositing is used the clipping region is + // ignored. Since in Aura the browser chrome could be under the plugin, if + // if Windows tries to paint it synchronously inside EndDeferWindowsPos + // then it won't have the data and it will flash white. So instead we + // manually redraw the plugin. + // Why not do this for native Windows? Not sure if there are any + // performance issues with this. + flags |= SWP_NOREDRAW; + } #endif if (move.rects_valid) { @@ -311,12 +314,14 @@ void RenderWidgetHostViewBase::MovePluginWindowsHelper( ::EndDeferWindowPos(defer_window_pos_info); #if defined(USE_AURA) - for (size_t i = 0; i < moves.size(); ++i) { - const WebPluginGeometry& move = moves[i]; - RECT r; - GetWindowRect(move.window, &r); - gfx::Rect gr(r); - PaintEnumChildProc(move.window, reinterpret_cast<LPARAM>(&gr)); + if (GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) { + for (size_t i = 0; i < moves.size(); ++i) { + const WebPluginGeometry& move = moves[i]; + RECT r; + GetWindowRect(move.window, &r); + gfx::Rect gr(r); + PaintEnumChildProc(move.window, reinterpret_cast<LPARAM>(&gr)); + } } #endif } @@ -427,8 +432,8 @@ InputEventAckState RenderWidgetHostViewBase::FilterInputEvent( return INPUT_EVENT_ACK_STATE_NOT_CONSUMED; } -void RenderWidgetHostViewBase::GestureEventAck(int gesture_event_type) { -} +void RenderWidgetHostViewBase::GestureEventAck(int gesture_event_type, + InputEventAckState ack_result) {} void RenderWidgetHostViewBase::SetPopupType(WebKit::WebPopupType popup_type) { popup_type_ = popup_type; diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h index 2efd132aba..68fcaffaea 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.h +++ b/content/browser/renderer_host/render_widget_host_view_base.h @@ -61,7 +61,8 @@ class CONTENT_EXPORT RenderWidgetHostViewBase const WebKit::WebMouseWheelEvent& event) OVERRIDE; virtual InputEventAckState FilterInputEvent( const WebKit::WebInputEvent& input_event) OVERRIDE; - virtual void GestureEventAck(int gesture_event_type) OVERRIDE; + virtual void GestureEventAck(int gesture_event_type, + InputEventAckState ack_result) OVERRIDE; virtual void SetPopupType(WebKit::WebPopupType popup_type) OVERRIDE; virtual WebKit::WebPopupType GetPopupType() OVERRIDE; virtual BrowserAccessibilityManager* diff --git a/content/browser/renderer_host/render_widget_host_view_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_browsertest.cc index 25dd8ce884..78091320ad 100644 --- a/content/browser/renderer_host/render_widget_host_view_browsertest.cc +++ b/content/browser/renderer_host/render_widget_host_view_browsertest.cc @@ -855,15 +855,8 @@ class CompositingRenderWidgetHostViewTabCaptureHighDPI DISALLOW_COPY_AND_ASSIGN(CompositingRenderWidgetHostViewTabCaptureHighDPI); }; -// High-DPI doesn't work right with content-shell on linux-aura. -// http://crbug.com/265028 -#if defined(USE_AURA) && defined(OS_LINUX) && !defined(OS_CHROMEOS) -#define MAYBE_CopyFromCompositingSurface DISABLED_CopyFromCompositingSurface -#else -#define MAYBE_CopyFromCompositingSurface CopyFromCompositingSurface -#endif IN_PROC_BROWSER_TEST_F(CompositingRenderWidgetHostViewTabCaptureHighDPI, - MAYBE_CopyFromCompositingSurface) { + CopyFromCompositingSurface) { gfx::Rect copy_rect(200, 150); gfx::Size output_size = copy_rect.size(); gfx::Size expected_bitmap_size = @@ -877,17 +870,8 @@ IN_PROC_BROWSER_TEST_F(CompositingRenderWidgetHostViewTabCaptureHighDPI, video_frame); } -// High-DPI doesn't work right with content-shell on linux-aura. -// http://crbug.com/265028 -#if defined(USE_AURA) && defined(OS_LINUX) && !defined(OS_CHROMEOS) -#define MAYBE_CopyFromCompositingSurfaceVideoFrame \ - DISABLED_CopyFromCompositingSurfaceVideoFrame -#else -#define MAYBE_CopyFromCompositingSurfaceVideoFrame \ - CopyFromCompositingSurfaceVideoFrame -#endif IN_PROC_BROWSER_TEST_F(CompositingRenderWidgetHostViewTabCaptureHighDPI, - MAYBE_CopyFromCompositingSurfaceVideoFrame) { + CopyFromCompositingSurfaceVideoFrame) { gfx::Size html_rect_size(200, 150); // Grab 90x60 pixels from the center of the tab contents. gfx::Rect copy_rect = diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h index af8106c8ce..6cbe6dc7b6 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.h +++ b/content/browser/renderer_host/render_widget_host_view_mac.h @@ -463,7 +463,12 @@ class RenderWidgetHostViewMac : public RenderWidgetHostViewBase, bool CreateCompositedIOSurface(); bool CreateCompositedIOSurfaceLayer(); - void DestroyCompositedIOSurfaceAndLayer(); + enum DestroyContextBehavior { + kLeaveContextBoundToView, + kDestroyContext, + }; + void DestroyCompositedIOSurfaceAndLayer(DestroyContextBehavior + destroy_context_behavior); // Unbind the GL context (if any) that is bound to |cocoa_view_|. void ClearBoundContextDrawable(); diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm index a7338b576c..07448884b5 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac.mm @@ -4,6 +4,7 @@ #include "content/browser/renderer_host/render_widget_host_view_mac.h" +#import <objc/runtime.h> #include <QuartzCore/QuartzCore.h> #include "base/bind.h" @@ -137,6 +138,29 @@ static inline int ToWebKitModifiers(NSUInteger flags) { return modifiers; } +// This method will return YES for OS X versions 10.7.3 and later, and NO +// otherwise. +// Used to prevent a crash when building with the 10.7 SDK and accessing the +// notification below. See: http://crbug.com/260595. +static BOOL SupportsBackingPropertiesChangedNotification() { + // windowDidChangeBackingProperties: method has been added to the + // NSWindowDelegate protocol in 10.7.3, at the same time as the + // NSWindowDidChangeBackingPropertiesNotification notification was added. + // If the protocol contains this method description, the notification should + // be supported as well. + Protocol* windowDelegateProtocol = NSProtocolFromString(@"NSWindowDelegate"); + struct objc_method_description methodDescription = + protocol_getMethodDescription( + windowDelegateProtocol, + @selector(windowDidChangeBackingProperties:), + NO, + YES); + + // If the protocol does not contain the method, the returned method + // description is {NULL, NULL} + return methodDescription.name != NULL || methodDescription.types != NULL; +} + static float ScaleFactor(NSView* view) { return ui::GetScaleFactorScale(ui::GetScaleFactorForNativeView(view)); } @@ -428,7 +452,7 @@ RenderWidgetHostViewMac::~RenderWidgetHostViewMac() { UnlockMouse(); // Make sure that the layer doesn't reach into the now-invalid object. - DestroyCompositedIOSurfaceAndLayer(); + DestroyCompositedIOSurfaceAndLayer(kDestroyContext); software_layer_.reset(); // We are owned by RenderWidgetHostViewCocoa, so if we go away before the @@ -551,7 +575,8 @@ bool RenderWidgetHostViewMac::CreateCompositedIOSurfaceLayer() { (compositing_iosurface_layer_ || !use_core_animation_); } -void RenderWidgetHostViewMac::DestroyCompositedIOSurfaceAndLayer() { +void RenderWidgetHostViewMac::DestroyCompositedIOSurfaceAndLayer( + DestroyContextBehavior destroy_context_behavior) { ScopedCAActionDisabler disabler; compositing_iosurface_.reset(); @@ -561,8 +586,17 @@ void RenderWidgetHostViewMac::DestroyCompositedIOSurfaceAndLayer() { [compositing_iosurface_layer_ disableCompositing]; compositing_iosurface_layer_.reset(); } - ClearBoundContextDrawable(); - compositing_iosurface_context_ = NULL; + switch (destroy_context_behavior) { + case kLeaveContextBoundToView: + break; + case kDestroyContext: + ClearBoundContextDrawable(); + compositing_iosurface_context_ = NULL; + break; + default: + NOTREACHED(); + break; + } } void RenderWidgetHostViewMac::ClearBoundContextDrawable() { @@ -1414,7 +1448,7 @@ bool RenderWidgetHostViewMac::DrawIOSurfaceWithoutCoreAnimation() { void RenderWidgetHostViewMac::GotAcceleratedCompositingError() { AckPendingSwapBuffers(); - DestroyCompositedIOSurfaceAndLayer(); + DestroyCompositedIOSurfaceAndLayer(kDestroyContext); // The existing GL contexts may be in a bad state, so don't re-use any of the // existing ones anymore, rather, allocate new ones. CompositingIOSurfaceContext::MarkExistingContextsAsNotShareable(); @@ -1616,7 +1650,7 @@ void RenderWidgetHostViewMac::AcceleratedSurfaceSuspend() { } void RenderWidgetHostViewMac::AcceleratedSurfaceRelease() { - DestroyCompositedIOSurfaceAndLayer(); + DestroyCompositedIOSurfaceAndLayer(kDestroyContext); } bool RenderWidgetHostViewMac::HasAcceleratedSurface( @@ -1744,8 +1778,19 @@ void RenderWidgetHostViewMac::GotSoftwareFrame() { AckPendingSwapBuffers(); - // Forget IOSurface since we are drawing a software frame now. - DestroyCompositedIOSurfaceAndLayer(); + // If overlapping views are allowed, then don't unbind the context + // from the view (that is, don't call clearDrawble -- just delete the + // texture and IOSurface). Rather, let it sit behind the software frame + // that will be put up in front. This will prevent transparent + // flashes. + // http://crbug.com/154531 + // Also note that it is necessary that clearDrawable be called if + // overlapping views are not allowed, e.g, for content shell. + // http://crbug.com/178408 + if (allow_overlapping_views_) + DestroyCompositedIOSurfaceAndLayer(kLeaveContextBoundToView); + else + DestroyCompositedIOSurfaceAndLayer(kDestroyContext); } } @@ -2431,7 +2476,8 @@ void RenderWidgetHostViewMac::FrameSwapped() { // Backing property notifications crash on 10.6 when building with the 10.7 // SDK, see http://crbug.com/260595. - BOOL supportsBackingPropertiesNotification = base::mac::IsOSLionOrLater(); + static BOOL supportsBackingPropertiesNotification = + SupportsBackingPropertiesChangedNotification(); if (oldWindow) { if (supportsBackingPropertiesNotification) { diff --git a/content/browser/renderer_host/render_widget_host_view_win.cc b/content/browser/renderer_host/render_widget_host_view_win.cc index 50a658aa51..563ea65a85 100644 --- a/content/browser/renderer_host/render_widget_host_view_win.cc +++ b/content/browser/renderer_host/render_widget_host_view_win.cc @@ -48,6 +48,7 @@ #include "content/public/browser/native_web_keyboard_event.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" +#include "content/public/browser/render_view_host.h" #include "content/public/common/content_switches.h" #include "content/public/common/page_zoom.h" #include "content/public/common/process_type.h" @@ -62,6 +63,7 @@ #include "ui/base/l10n/l10n_util_win.h" #include "ui/base/text/text_elider.h" #include "ui/base/touch/touch_device.h" +#include "ui/base/touch/touch_enabled.h" #include "ui/base/ui_base_switches.h" #include "ui/base/view_prop.h" #include "ui/base/win/dpi.h" @@ -407,7 +409,7 @@ RenderWidgetHostViewWin::RenderWidgetHostViewWin(RenderWidgetHost* widget) touch_state_(new WebTouchState(this)), pointer_down_context_(false), last_touch_location_(-1, -1), - touch_events_enabled_(false), + touch_events_enabled_(ui::AreTouchEventsEnabled()), gesture_recognizer_(ui::GestureRecognizer::Create(this)) { render_widget_host_->SetView(this); registrar_.Add(this, @@ -608,8 +610,10 @@ bool RenderWidgetHostViewWin::HasFocus() const { } bool RenderWidgetHostViewWin::IsSurfaceAvailableForCopy() const { - return !!render_widget_host_->GetBackingStore(false) || - (accelerated_surface_.get() && accelerated_surface_->IsReadyForCopy()); + if (render_widget_host_->is_accelerated_compositing_active()) + return accelerated_surface_.get() && accelerated_surface_->IsReadyForCopy(); + else + return !!render_widget_host_->GetBackingStore(false); } void RenderWidgetHostViewWin::Show() { @@ -926,35 +930,10 @@ void RenderWidgetHostViewWin::ProcessAckedTouchEvent( void RenderWidgetHostViewWin::UpdateDesiredTouchMode() { // Make sure that touch events even make sense. - CommandLine* cmdline = CommandLine::ForCurrentProcess(); - static bool touch_mode = base::win::GetVersion() >= base::win::VERSION_WIN7 && - ui::IsTouchDevicePresent() && ( - !cmdline->HasSwitch(switches::kTouchEvents) || - cmdline->GetSwitchValueASCII(switches::kTouchEvents) != - switches::kTouchEventsDisabled); - - if (!touch_mode) + if (base::win::GetVersion() < base::win::VERSION_WIN7) return; - - // Now we know that the window's current state doesn't match the desired - // state. If we want touch mode, then we attempt to register for touch - // events, and otherwise to unregister. - touch_events_enabled_ = RegisterTouchWindow(m_hWnd, TWF_WANTPALM) == TRUE; - - if (!touch_events_enabled_) { - UnregisterTouchWindow(m_hWnd); - // Single finger panning is consistent with other windows applications. - const DWORD gesture_allow = GC_PAN_WITH_SINGLE_FINGER_VERTICALLY | - GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY; - const DWORD gesture_block = GC_PAN_WITH_GUTTER; - GESTURECONFIG gc[] = { - { GID_ZOOM, GC_ZOOM, 0 }, - { GID_PAN, gesture_allow , gesture_block}, - { GID_TWOFINGERTAP, GC_TWOFINGERTAP , 0}, - { GID_PRESSANDTAP, GC_PRESSANDTAP , 0} - }; - if (!SetGestureConfig(m_hWnd, 0, arraysize(gc), gc, sizeof(GESTURECONFIG))) - NOTREACHED(); + if (touch_events_enabled_) { + CHECK(RegisterTouchWindow(m_hWnd, TWF_WANTPALM)); } } @@ -2333,8 +2312,6 @@ LRESULT RenderWidgetHostViewWin::OnGestureEvent( UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnGestureEvent"); - // Note that as of M22, touch events are enabled by default on Windows. - // This code should not be reachable. DCHECK(!touch_events_enabled_); handled = FALSE; diff --git a/content/browser/renderer_host/ui_events_helper.cc b/content/browser/renderer_host/ui_events_helper.cc index 89c09794f2..afbbf99017 100644 --- a/content/browser/renderer_host/ui_events_helper.cc +++ b/content/browser/renderer_host/ui_events_helper.cc @@ -237,6 +237,12 @@ WebKit::WebGestureEvent MakeWebGestureEventFromUIEvent( int EventFlagsToWebEventModifiers(int flags) { int modifiers = 0; + + // Translate AltGr modifier to Ctrl+Alt first. + if (flags & ui::EF_ALTGR_DOWN) { + modifiers |= WebKit::WebInputEvent::ControlKey | + WebKit::WebInputEvent::AltKey; + } if (flags & ui::EF_SHIFT_DOWN) modifiers |= WebKit::WebInputEvent::ShiftKey; if (flags & ui::EF_CONTROL_DOWN) diff --git a/content/browser/resources/media/new/integration_test.html b/content/browser/resources/media/new/integration_test.html new file mode 100644 index 0000000000..3a5225cb64 --- /dev/null +++ b/content/browser/resources/media/new/integration_test.html @@ -0,0 +1,86 @@ +<!-- +Copyright 2013 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. +--> +<!DOCTYPE html> +<html> + <head> + <script src="webui_resource_test.js"></script> + <script src="util.js"></script> + <script src="player_manager.js"></script> + <script src="player_info.js"></script> + <script src="main.js"></script> + </head> + <body> + <script> + window.setUp = function() { + var doNothing = function() {}; + var mockRenderer = { + redrawList: doNothing, + update: doNothing, + select: doNothing + }; + + var manager = new PlayerManager(mockRenderer); + media.initialize(manager); + + window.playerManager = manager; + }; + + // The renderer and player ids are completely arbitrarily. + var TEST_RENDERER = 12; + var TEST_PLAYER = 4; + var TEST_NAME = TEST_RENDERER + ':' + TEST_PLAYER; + + // Correctly use the information from a media event. + window.testOnMediaEvent = function() { + var event = { + ticksMillis: 132, + renderer: TEST_RENDERER, + player: TEST_PLAYER, + params: { + fps: 60, + other: 'hi' + } + }; + + window.media.onMediaEvent(event); + var info = window.playerManager.players_[TEST_NAME]; + + assertEquals(event.ticksMillis, info.firstTimestamp_); + assertEquals(TEST_NAME, info.id); + assertEquals(event.params.fps, info.properties.fps); + }; + + // Remove a player. + window.testOnRenderTerminated = function() { + window.testOnMediaEvent(); + + window.playerManager.shouldRemovePlayer_ = function() { + return true; + }; + + window.media.onRendererTerminated(TEST_RENDERER); + assertEquals(undefined, window.playerManager.players_[TEST_NAME]); + }; + + // Audio Streams are weird, they are handled separately + window.testAddAudioStream = function() { + var event = { + id: 'ID', + status: 'created', + playing: true + }; + + window.media.addAudioStream(event); + + var player = window.playerManager.players_[event.id]; + assertTrue(undefined !== player); + assertEquals(event.playing, player.properties['playing']); + }; + + runTests(); + </script> + </body> +</html> diff --git a/content/browser/resources/media/new/main.js b/content/browser/resources/media/new/main.js new file mode 100644 index 0000000000..61f6407bcf --- /dev/null +++ b/content/browser/resources/media/new/main.js @@ -0,0 +1,134 @@ +// Copyright 2013 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. + +/** + * A global object that gets used by the C++ interface. + */ +var media = (function() { + 'use strict'; + + var manager = null; + + /** + * Users of |media| must call initialize prior to calling other methods. + */ + function initialize(playerManager) { + manager = playerManager; + } + + /** + * Call to modify or add a system property. + */ + function onSystemProperty(timestamp, key, value) { + console.log('System properties not yet implemented'); + } + + /** + * Call to modify or add a property on a player. + */ + function onPlayerProperty(id, timestamp, key, value) { + manager.updatePlayerInfo(id, timestamp, key, value); + } + + function onPlayerPropertyNoRecord(id, timestamp, key, value) { + manager.updatePlayerInfoNoRecord(id, timestamp, key, value); + } + + /** + * Call to add a player. + */ + function onPlayerOpen(id, timestamp) { + manager.addPlayer(id, timestamp); + } + + /** + * Call to remove a player. + */ + function onPlayerClose(id) { + manager.removePlayer(id); + } + + var media = { + onSystemProperty: onSystemProperty, + onPlayerProperty: onPlayerProperty, + onPlayerPropertyNoRecord: onPlayerPropertyNoRecord, + onPlayerOpen: onPlayerOpen, + onPlayerClose: onPlayerClose, + + initialize: initialize + }; + + // Everything beyond this point is for backwards compatibility reasons. + // It will go away when the backend is updated. + + media.onNetUpdate = function(update) { + // TODO(tyoverby): Implement + }; + + media.onRendererTerminated = function(renderId) { + util.object.forEach(manager.players_, function(playerInfo, id) { + if (playerInfo.properties['render_id'] == renderId) { + media.onPlayerClose(id); + } + }); + }; + + // For whatever reason, addAudioStream is also called on + // the removal of audio streams. + media.addAudioStream = function(event) { + switch (event.status) { + case 'created': + media.onPlayerOpen(event.id); + // We have to simulate the timestamp since it isn't provided to us. + media.onPlayerProperty( + event.id, (new Date()).getTime(), 'playing', event.playing); + break; + case 'closed': + media.onPlayerClose(event.id); + break; + } + }; + media.onItemDeleted = function() { + // This only gets called when an audio stream is removed, which + // for whatever reason is also handled by addAudioStream... + // Because it is already handled, we can safely ignore it. + }; + + media.onMediaEvent = function(event) { + var source = event.renderer + ':' + event.player; + + // Although this gets called on every event, there is nothing we can do + // about this because there is no onOpen event. + media.onPlayerOpen(source); + media.onPlayerPropertyNoRecord( + source, event.ticksMillis, 'render_id', event.renderer); + media.onPlayerPropertyNoRecord( + source, event.ticksMillis, 'player_id', event.player); + + var propertyCount = 0; + util.object.forEach(event.params, function(value, key) { + key = key.trim(); + + // These keys get spammed *a lot*, so put them on the display + // but don't log list. + if (key === 'buffer_start' || + key === 'buffer_end' || + key === 'buffer_current' || + key === 'is_downloading_data') { + media.onPlayerPropertyNoRecord( + source, event.ticksMillis, key, value); + } else { + media.onPlayerProperty(source, event.ticksMillis, key, value); + } + propertyCount += 1; + }); + + if (propertyCount === 0) { + media.onPlayerProperty( + source, event.ticksMillis, 'EVENT', event.type); + } + }; + + return media; +}()); diff --git a/content/browser/resources/media/new/util.js b/content/browser/resources/media/new/util.js new file mode 100644 index 0000000000..5909e9ee1e --- /dev/null +++ b/content/browser/resources/media/new/util.js @@ -0,0 +1,34 @@ +// Copyright 2013 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. + +/** + * @fileoverview Some utility functions that don't belong anywhere else in the + * code. + */ + +var util = (function() { + var util = {}; + util.object = {}; + /** + * Calls a function for each element in an object/map/hash. + * + * @param obj The object to iterate over. + * @param f The function to call on every value in the object. F should have + * the following arguments: f(value, key, object) where value is the value + * of the property, key is the corresponding key, and obj is the object that + * was passed in originally. + * @param optObj The object use as 'this' within f. + */ + util.object.forEach = function(obj, f, optObj) { + 'use strict'; + var key; + for (key in obj) { + if (obj.hasOwnProperty(key)) { + f.call(optObj, obj[key], key, obj); + } + } + }; + + return util; +}()); diff --git a/content/browser/ssl/ssl_host_state.cc b/content/browser/ssl/ssl_host_state.cc index c2fc06da1b..06c600205f 100644 --- a/content/browser/ssl/ssl_host_state.cc +++ b/content/browser/ssl/ssl_host_state.cc @@ -39,17 +39,19 @@ bool SSLHostState::DidHostRunInsecureContent(const std::string& host, } void SSLHostState::DenyCertForHost(net::X509Certificate* cert, - const std::string& host) { + const std::string& host, + net::CertStatus error) { DCHECK(CalledOnValidThread()); - cert_policy_for_host_[host].Deny(cert); + cert_policy_for_host_[host].Deny(cert, error); } void SSLHostState::AllowCertForHost(net::X509Certificate* cert, - const std::string& host) { + const std::string& host, + net::CertStatus error) { DCHECK(CalledOnValidThread()); - cert_policy_for_host_[host].Allow(cert); + cert_policy_for_host_[host].Allow(cert, error); } void SSLHostState::Clear() { @@ -58,11 +60,12 @@ void SSLHostState::Clear() { cert_policy_for_host_.clear(); } -net::CertPolicy::Judgment SSLHostState::QueryPolicy( - net::X509Certificate* cert, const std::string& host) { +net::CertPolicy::Judgment SSLHostState::QueryPolicy(net::X509Certificate* cert, + const std::string& host, + net::CertStatus error) { DCHECK(CalledOnValidThread()); - return cert_policy_for_host_[host].Check(cert); + return cert_policy_for_host_[host].Check(cert, error); } } // namespace content diff --git a/content/browser/ssl/ssl_host_state.h b/content/browser/ssl/ssl_host_state.h index b229b79b3d..820821786d 100644 --- a/content/browser/ssl/ssl_host_state.h +++ b/content/browser/ssl/ssl_host_state.h @@ -14,6 +14,7 @@ #include "base/supports_user_data.h" #include "base/threading/non_thread_safe.h" #include "content/common/content_export.h" +#include "net/cert/cert_status_flags.h" #include "net/cert/x509_certificate.h" namespace content { @@ -42,18 +43,25 @@ class CONTENT_EXPORT SSLHostState // Returns whether the specified host ran insecure content. bool DidHostRunInsecureContent(const std::string& host, int pid) const; - // Records that |cert| is permitted to be used for |host| in the future. - void DenyCertForHost(net::X509Certificate* cert, const std::string& host); + // Records that |cert| is not permitted to be used for |host| in the future, + // for a specified |error| type.. + void DenyCertForHost(net::X509Certificate* cert, + const std::string& host, + net::CertStatus error); - // Records that |cert| is not permitted to be used for |host| in the future. - void AllowCertForHost(net::X509Certificate* cert, const std::string& host); + // Records that |cert| is permitted to be used for |host| in the future, for + // a specified |error| type. + void AllowCertForHost(net::X509Certificate* cert, + const std::string& host, + net::CertStatus error); // Clear all allow/deny preferences. void Clear(); - // Queries whether |cert| is allowed or denied for |host|. - net::CertPolicy::Judgment QueryPolicy( - net::X509Certificate* cert, const std::string& host); + // Queries whether |cert| is allowed or denied for |host| and |error|. + net::CertPolicy::Judgment QueryPolicy(net::X509Certificate* cert, + const std::string& host, + net::CertStatus error); private: // A BrokenHostEntry is a pair of (host, process_id) that indicates the host diff --git a/content/browser/ssl/ssl_host_state_unittest.cc b/content/browser/ssl/ssl_host_state_unittest.cc index 7ba266b09f..5e4366d375 100644 --- a/content/browser/ssl/ssl_host_state_unittest.cc +++ b/content/browser/ssl/ssl_host_state_unittest.cc @@ -120,48 +120,84 @@ TEST_F(SSLHostStateTest, QueryPolicy) { SSLHostState state; - EXPECT_EQ(state.QueryPolicy(google_cert.get(), "www.google.com"), - net::CertPolicy::UNKNOWN); - EXPECT_EQ(state.QueryPolicy(google_cert.get(), "google.com"), - net::CertPolicy::UNKNOWN); - EXPECT_EQ(state.QueryPolicy(google_cert.get(), "example.com"), - net::CertPolicy::UNKNOWN); - - state.AllowCertForHost(google_cert.get(), "www.google.com"); - - EXPECT_EQ(state.QueryPolicy(google_cert.get(), "www.google.com"), - net::CertPolicy::ALLOWED); - EXPECT_EQ(state.QueryPolicy(google_cert.get(), "google.com"), - net::CertPolicy::UNKNOWN); - EXPECT_EQ(state.QueryPolicy(google_cert.get(), "example.com"), - net::CertPolicy::UNKNOWN); - - state.AllowCertForHost(google_cert.get(), "example.com"); - - EXPECT_EQ(state.QueryPolicy(google_cert.get(), "www.google.com"), - net::CertPolicy::ALLOWED); - EXPECT_EQ(state.QueryPolicy(google_cert.get(), "google.com"), - net::CertPolicy::UNKNOWN); - EXPECT_EQ(state.QueryPolicy(google_cert.get(), "example.com"), - net::CertPolicy::ALLOWED); - - state.DenyCertForHost(google_cert.get(), "example.com"); - - EXPECT_EQ(state.QueryPolicy(google_cert.get(), "www.google.com"), - net::CertPolicy::ALLOWED); - EXPECT_EQ(state.QueryPolicy(google_cert.get(), "google.com"), - net::CertPolicy::UNKNOWN); - EXPECT_EQ(state.QueryPolicy(google_cert.get(), "example.com"), - net::CertPolicy::DENIED); + EXPECT_EQ(net::CertPolicy::UNKNOWN, + state.QueryPolicy(google_cert.get(), + "www.google.com", + net::CERT_STATUS_DATE_INVALID)); + EXPECT_EQ(net::CertPolicy::UNKNOWN, + state.QueryPolicy(google_cert.get(), + "google.com", + net::CERT_STATUS_DATE_INVALID)); + EXPECT_EQ(net::CertPolicy::UNKNOWN, + state.QueryPolicy(google_cert.get(), + "example.com", + net::CERT_STATUS_DATE_INVALID)); + + state.AllowCertForHost(google_cert.get(), + "www.google.com", + net::CERT_STATUS_DATE_INVALID); + + EXPECT_EQ(net::CertPolicy::ALLOWED, + state.QueryPolicy(google_cert.get(), + "www.google.com", + net::CERT_STATUS_DATE_INVALID)); + EXPECT_EQ(net::CertPolicy::UNKNOWN, + state.QueryPolicy(google_cert.get(), + "google.com", + net::CERT_STATUS_DATE_INVALID)); + EXPECT_EQ(net::CertPolicy::UNKNOWN, + state.QueryPolicy(google_cert.get(), + "example.com", + net::CERT_STATUS_DATE_INVALID)); + + state.AllowCertForHost(google_cert.get(), + "example.com", + net::CERT_STATUS_DATE_INVALID); + + EXPECT_EQ(net::CertPolicy::ALLOWED, + state.QueryPolicy(google_cert.get(), + "www.google.com", + net::CERT_STATUS_DATE_INVALID)); + EXPECT_EQ(net::CertPolicy::UNKNOWN, + state.QueryPolicy(google_cert.get(), + "google.com", + net::CERT_STATUS_DATE_INVALID)); + EXPECT_EQ(net::CertPolicy::ALLOWED, + state.QueryPolicy(google_cert.get(), + "example.com", + net::CERT_STATUS_DATE_INVALID)); + + state.DenyCertForHost(google_cert.get(), + "example.com", + net::CERT_STATUS_DATE_INVALID); + + EXPECT_EQ(net::CertPolicy::ALLOWED, + state.QueryPolicy(google_cert.get(), + "www.google.com", + net::CERT_STATUS_DATE_INVALID)); + EXPECT_EQ(net::CertPolicy::UNKNOWN, + state.QueryPolicy(google_cert.get(), + "google.com", + net::CERT_STATUS_DATE_INVALID)); + EXPECT_EQ(net::CertPolicy::DENIED, + state.QueryPolicy(google_cert.get(), + "example.com", + net::CERT_STATUS_DATE_INVALID)); state.Clear(); - EXPECT_EQ(state.QueryPolicy(google_cert.get(), "www.google.com"), - net::CertPolicy::UNKNOWN); - EXPECT_EQ(state.QueryPolicy(google_cert.get(), "google.com"), - net::CertPolicy::UNKNOWN); - EXPECT_EQ(state.QueryPolicy(google_cert.get(), "example.com"), - net::CertPolicy::UNKNOWN); + EXPECT_EQ(net::CertPolicy::UNKNOWN, + state.QueryPolicy(google_cert.get(), + "www.google.com", + net::CERT_STATUS_DATE_INVALID)); + EXPECT_EQ(net::CertPolicy::UNKNOWN, + state.QueryPolicy(google_cert.get(), + "google.com", + net::CERT_STATUS_DATE_INVALID)); + EXPECT_EQ(net::CertPolicy::UNKNOWN, + state.QueryPolicy(google_cert.get(), + "example.com", + net::CERT_STATUS_DATE_INVALID)); } } // namespace content diff --git a/content/browser/ssl/ssl_policy.cc b/content/browser/ssl/ssl_policy.cc index ec55736e7e..02af3983bf 100644 --- a/content/browser/ssl/ssl_policy.cc +++ b/content/browser/ssl/ssl_policy.cc @@ -34,7 +34,9 @@ SSLPolicy::SSLPolicy(SSLPolicyBackend* backend) void SSLPolicy::OnCertError(SSLCertErrorHandler* handler) { // First we check if we know the policy for this error. net::CertPolicy::Judgment judgment = backend_->QueryPolicy( - handler->ssl_info().cert.get(), handler->request_url().host()); + handler->ssl_info().cert.get(), + handler->request_url().host(), + handler->cert_error()); if (judgment == net::CertPolicy::ALLOWED) { handler->ContinueRequest(); @@ -138,6 +140,8 @@ void SSLPolicy::UpdateEntry(NavigationEntryImpl* entry, if (web_contents->DisplayedInsecureContent()) entry->GetSSL().content_status |= SSLStatus::DISPLAYED_INSECURE_CONTENT; + else + entry->GetSSL().content_status &= ~SSLStatus::DISPLAYED_INSECURE_CONTENT; } void SSLPolicy::OnAllowCertificate(scoped_refptr<SSLCertErrorHandler> handler, @@ -154,7 +158,8 @@ void SSLPolicy::OnAllowCertificate(scoped_refptr<SSLCertErrorHandler> handler, // ContinueRequest() gets posted to a different thread. Calling // AllowCertForHost() first ensures deterministic ordering. backend_->AllowCertForHost(handler->ssl_info().cert.get(), - handler->request_url().host()); + handler->request_url().host(), + handler->cert_error()); handler->ContinueRequest(); } else { // Default behavior for rejecting a certificate. @@ -163,7 +168,8 @@ void SSLPolicy::OnAllowCertificate(scoped_refptr<SSLCertErrorHandler> handler, // CancelRequest() gets posted to a different thread. Calling // DenyCertForHost() first ensures deterministic ordering. backend_->DenyCertForHost(handler->ssl_info().cert.get(), - handler->request_url().host()); + handler->request_url().host(), + handler->cert_error()); handler->CancelRequest(); } } diff --git a/content/browser/ssl/ssl_policy_backend.cc b/content/browser/ssl/ssl_policy_backend.cc index 8aa8bc7117..57e05702c8 100644 --- a/content/browser/ssl/ssl_policy_backend.cc +++ b/content/browser/ssl/ssl_policy_backend.cc @@ -27,18 +27,22 @@ bool SSLPolicyBackend::DidHostRunInsecureContent(const std::string& host, } void SSLPolicyBackend::DenyCertForHost(net::X509Certificate* cert, - const std::string& host) { - ssl_host_state_->DenyCertForHost(cert, host); + const std::string& host, + net::CertStatus error) { + ssl_host_state_->DenyCertForHost(cert, host, error); } void SSLPolicyBackend::AllowCertForHost(net::X509Certificate* cert, - const std::string& host) { - ssl_host_state_->AllowCertForHost(cert, host); + const std::string& host, + net::CertStatus error) { + ssl_host_state_->AllowCertForHost(cert, host, error); } net::CertPolicy::Judgment SSLPolicyBackend::QueryPolicy( - net::X509Certificate* cert, const std::string& host) { - return ssl_host_state_->QueryPolicy(cert, host); + net::X509Certificate* cert, + const std::string& host, + net::CertStatus error) { + return ssl_host_state_->QueryPolicy(cert, host, error); } } // namespace content diff --git a/content/browser/ssl/ssl_policy_backend.h b/content/browser/ssl/ssl_policy_backend.h index 18ec580356..06ea23eccc 100644 --- a/content/browser/ssl/ssl_policy_backend.h +++ b/content/browser/ssl/ssl_policy_backend.h @@ -10,6 +10,7 @@ #include "base/basictypes.h" #include "base/strings/string16.h" +#include "net/cert/cert_status_flags.h" #include "net/cert/x509_certificate.h" namespace content { @@ -26,15 +27,22 @@ class SSLPolicyBackend { // Returns whether the specified host ran insecure content. bool DidHostRunInsecureContent(const std::string& host, int pid) const; - // Records that |cert| is permitted to be used for |host| in the future. - void DenyCertForHost(net::X509Certificate* cert, const std::string& host); + // Records that |cert| is not permitted to be used for |host| in the future, + // for a specific error type. + void DenyCertForHost(net::X509Certificate* cert, + const std::string& host, + net::CertStatus error); - // Records that |cert| is not permitted to be used for |host| in the future. - void AllowCertForHost(net::X509Certificate* cert, const std::string& host); + // Records that |cert| is permitted to be used for |host| in the future, for + // a specific error type. + void AllowCertForHost(net::X509Certificate* cert, + const std::string& host, + net::CertStatus error); // Queries whether |cert| is allowed or denied for |host|. - net::CertPolicy::Judgment QueryPolicy( - net::X509Certificate* cert, const std::string& host); + net::CertPolicy::Judgment QueryPolicy(net::X509Certificate* cert, + const std::string& host, + net::CertStatus error); private: // SSL state specific for each host. diff --git a/content/browser/startup_task_runner.cc b/content/browser/startup_task_runner.cc new file mode 100644 index 0000000000..a7e730e5d8 --- /dev/null +++ b/content/browser/startup_task_runner.cc @@ -0,0 +1,63 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/startup_task_runner.h" + +#include "base/bind.h" +#include "base/location.h" +#include "base/message_loop/message_loop.h" + +namespace content { + +StartupTaskRunner::StartupTaskRunner( + bool browser_may_start_asynchronously, + base::Callback<void(int)> const startup_complete_callback, + scoped_refptr<base::SingleThreadTaskRunner> proxy) + : asynchronous_startup_(browser_may_start_asynchronously), + startup_complete_callback_(startup_complete_callback), + proxy_(proxy) {} + +void StartupTaskRunner::AddTask(StartupTask& callback) { + task_list_.push_back(callback); +} + +void StartupTaskRunner::StartRunningTasks() { + DCHECK(proxy_); + int result = 0; + if (asynchronous_startup_ && !task_list_.empty()) { + const base::Closure next_task = + base::Bind(&StartupTaskRunner::WrappedTask, this); + proxy_->PostNonNestableTask(FROM_HERE, next_task); + } else { + for (std::list<StartupTask>::iterator it = task_list_.begin(); + it != task_list_.end(); + it++) { + result = it->Run(); + if (result > 0) { + break; + } + } + if (!startup_complete_callback_.is_null()) { + startup_complete_callback_.Run(result); + } + } +} + +void StartupTaskRunner::WrappedTask() { + int result = task_list_.front().Run(); + task_list_.pop_front(); + if (result > 0 || task_list_.empty()) { + if (!startup_complete_callback_.is_null()) { + startup_complete_callback_.Run(result); + } + } else { + const base::Closure next_task = + base::Bind(&StartupTaskRunner::WrappedTask, this); + proxy_->PostNonNestableTask(FROM_HERE, next_task); + } +} + +StartupTaskRunner::~StartupTaskRunner() {} + +} // namespace content diff --git a/content/browser/startup_task_runner.h b/content/browser/startup_task_runner.h new file mode 100644 index 0000000000..5f954edc88 --- /dev/null +++ b/content/browser/startup_task_runner.h @@ -0,0 +1,66 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_STARTUP_TASK_RUNNER_H_ +#define CONTENT_BROWSER_STARTUP_TASK_RUNNER_H_ + +#include <list> + +#include "base/callback.h" +#include "base/memory/ref_counted.h" +#include "base/single_thread_task_runner.h" + +#include "build/build_config.h" + +#include "content/public/browser/browser_main_runner.h" + +namespace content { + +// A startup task is a void function returning the status on completion. +// a status of > 0 indicates a failure, and that no further startup tasks should +// be run. +typedef base::Callback<int(void)> StartupTask; + +// This class runs startup tasks. The tasks are either run immediately inline, +// or are queued one at a time on the UI thread's message loop. If the events +// are queued, UI events that are received during startup will be acted upon +// between startup tasks. The motivation for this is that, on targets where the +// UI is already started, it allows us to keep the UI responsive during startup. +// +// Note that this differs from a SingleThreadedTaskRunner in that there may be +// no opportunity to handle UI events between the tasks of a +// SingleThreadedTaskRunner. + +class CONTENT_EXPORT StartupTaskRunner + : public base::RefCounted<StartupTaskRunner> { + + public: + // Constructor: Note that |startup_complete_callback| is optional. If it is + // not null it will be called once all the startup tasks have run. + StartupTaskRunner(bool browser_may_start_asynchronously, + base::Callback<void(int)> startup_complete_callback, + scoped_refptr<base::SingleThreadTaskRunner> proxy); + + // Add a task to the queue of startup tasks to be run. + virtual void AddTask(StartupTask& callback); + + // Start running the tasks. + virtual void StartRunningTasks(); + + private: + friend class base::RefCounted<StartupTaskRunner>; + virtual ~StartupTaskRunner(); + + std::list<StartupTask> task_list_; + void WrappedTask(); + + const bool asynchronous_startup_; + base::Callback<void(int)> startup_complete_callback_; + scoped_refptr<base::SingleThreadTaskRunner> proxy_; + + DISALLOW_COPY_AND_ASSIGN(StartupTaskRunner); +}; + +} // namespace content +#endif // CONTENT_BROWSER_STARTUP_TASK_RUNNER_H_ diff --git a/content/browser/startup_task_runner_unittest.cc b/content/browser/startup_task_runner_unittest.cc new file mode 100644 index 0000000000..2efa79f7ac --- /dev/null +++ b/content/browser/startup_task_runner_unittest.cc @@ -0,0 +1,281 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/startup_task_runner.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/callback.h" +#include "base/location.h" +#include "base/run_loop.h" +#include "base/task_runner.h" + +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace content { +namespace { + +using base::Closure; +using testing::_; +using testing::Assign; +using testing::Invoke; +using testing::WithArg; + +bool observer_called = false; +int observer_result; +base::Closure task; + +// I couldn't get gMock's SaveArg to compile, hence had to save the argument +// this way +bool SaveTaskArg(const Closure& arg) { + task = arg; + return true; +} + +void Observer(int result) { + observer_called = true; + observer_result = result; +} + +class StartupTaskRunnerTest : public testing::Test { + public: + + virtual void SetUp() { + last_task_ = 0; + observer_called = false; + } + + int Task1() { + last_task_ = 1; + return 0; + } + + int Task2() { + last_task_ = 2; + return 0; + } + + int FailingTask() { + // Task returning failure + last_task_ = 3; + return 1; + } + + int GetLastTask() { return last_task_; } + + private: + + int last_task_; +}; + +// We can't use the real message loop, even if we want to, since doing so on +// Android requires a complex Java infrastructure. The test would have to built +// as a content_shell test; but content_shell startup invokes the class we are +// trying to test. +// +// The mocks are not directly in TaskRunnerProxy because reference counted +// objects seem to confuse the mocking framework + +class MockTaskRunner { + public: + MOCK_METHOD3( + PostDelayedTask, + bool(const tracked_objects::Location&, const Closure&, base::TimeDelta)); + MOCK_METHOD3( + PostNonNestableDelayedTask, + bool(const tracked_objects::Location&, const Closure&, base::TimeDelta)); +}; + +class TaskRunnerProxy : public base::SingleThreadTaskRunner { + public: + TaskRunnerProxy(MockTaskRunner* mock) : mock_(mock) {} + virtual bool RunsTasksOnCurrentThread() const OVERRIDE { return true; } + virtual bool PostDelayedTask(const tracked_objects::Location& location, + const Closure& closure, + base::TimeDelta delta) OVERRIDE { + return mock_->PostDelayedTask(location, closure, delta); + } + virtual bool PostNonNestableDelayedTask( + const tracked_objects::Location& location, + const Closure& closure, + base::TimeDelta delta) OVERRIDE { + return mock_->PostNonNestableDelayedTask(location, closure, delta); + } + + private: + MockTaskRunner* mock_; + virtual ~TaskRunnerProxy() {} +}; + +TEST_F(StartupTaskRunnerTest, SynchronousExecution) { + MockTaskRunner mock_runner; + scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner); + + EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0); + EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, _, _)).Times(0); + + scoped_refptr<StartupTaskRunner> runner = + new StartupTaskRunner(false, base::Bind(&Observer), proxy); + + StartupTask task1 = + base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this)); + runner->AddTask(task1); + EXPECT_EQ(GetLastTask(), 0); + StartupTask task2 = + base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this)); + runner->AddTask(task2); + + // Nothing should run until we tell them to. + EXPECT_EQ(GetLastTask(), 0); + runner->StartRunningTasks(); + + // On an immediate StartupTaskRunner the tasks should now all have run. + EXPECT_EQ(GetLastTask(), 2); + + EXPECT_TRUE(observer_called); + EXPECT_EQ(observer_result, 0); +} + +TEST_F(StartupTaskRunnerTest, NullObserver) { + MockTaskRunner mock_runner; + scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner); + + EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0); + EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, _, _)).Times(0); + + scoped_refptr<StartupTaskRunner> runner = + new StartupTaskRunner(false, base::Callback<void(int)>(), proxy); + + StartupTask task1 = + base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this)); + runner->AddTask(task1); + EXPECT_EQ(GetLastTask(), 0); + StartupTask task2 = + base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this)); + runner->AddTask(task2); + + // Nothing should run until we tell them to. + EXPECT_EQ(GetLastTask(), 0); + runner->StartRunningTasks(); + + // On an immediate StartupTaskRunner the tasks should now all have run. + EXPECT_EQ(GetLastTask(), 2); + + EXPECT_FALSE(observer_called); +} + +TEST_F(StartupTaskRunnerTest, SynchronousExecutionFailedTask) { + MockTaskRunner mock_runner; + scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner); + + EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0); + EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, _, _)).Times(0); + + scoped_refptr<StartupTaskRunner> runner = + new StartupTaskRunner(false, base::Bind(&Observer), proxy); + + StartupTask task3 = + base::Bind(&StartupTaskRunnerTest::FailingTask, base::Unretained(this)); + runner->AddTask(task3); + EXPECT_EQ(GetLastTask(), 0); + StartupTask task2 = + base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this)); + runner->AddTask(task2); + + // Nothing should run until we tell them to. + EXPECT_EQ(GetLastTask(), 0); + runner->StartRunningTasks(); + + // Only the first task should have run, since it failed + EXPECT_EQ(GetLastTask(), 3); + + EXPECT_TRUE(observer_called); + EXPECT_EQ(observer_result, 1); +} + +TEST_F(StartupTaskRunnerTest, AsynchronousExecution) { + + MockTaskRunner mock_runner; + scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner); + + EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0); + EXPECT_CALL( + mock_runner, + PostNonNestableDelayedTask(_, _, base::TimeDelta::FromMilliseconds(0))) + .Times(testing::Between(2, 3)) + .WillRepeatedly(WithArg<1>(Invoke(SaveTaskArg))); + + scoped_refptr<StartupTaskRunner> runner = + new StartupTaskRunner(true, base::Bind(&Observer), proxy); + + StartupTask task1 = + base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this)); + runner->AddTask(task1); + StartupTask task2 = + base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this)); + runner->AddTask(task2); + + // Nothing should run until we tell them to. + EXPECT_EQ(GetLastTask(), 0); + runner->StartRunningTasks(); + + // No tasks should have run yet, since we the message loop hasn't run. + EXPECT_EQ(GetLastTask(), 0); + + // Fake the actual message loop. Each time a task is run a new task should + // be added to the queue, hence updating "task". The loop should actually run + // at most 3 times (once for each task plus possibly once for the observer), + // the "4" is a backstop. + for (int i = 0; i < 4 && !observer_called; i++) { + task.Run(); + EXPECT_EQ(i + 1, GetLastTask()); + } + EXPECT_TRUE(observer_called); + EXPECT_EQ(observer_result, 0); +} + +TEST_F(StartupTaskRunnerTest, AsynchronousExecutionFailedTask) { + + MockTaskRunner mock_runner; + scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner); + + EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0); + EXPECT_CALL( + mock_runner, + PostNonNestableDelayedTask(_, _, base::TimeDelta::FromMilliseconds(0))) + .Times(testing::Between(1, 2)) + .WillRepeatedly(WithArg<1>(Invoke(SaveTaskArg))); + + scoped_refptr<StartupTaskRunner> runner = + new StartupTaskRunner(true, base::Bind(&Observer), proxy); + + StartupTask task3 = + base::Bind(&StartupTaskRunnerTest::FailingTask, base::Unretained(this)); + runner->AddTask(task3); + StartupTask task2 = + base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this)); + runner->AddTask(task2); + + // Nothing should run until we tell them to. + EXPECT_EQ(GetLastTask(), 0); + runner->StartRunningTasks(); + + // No tasks should have run yet, since we the message loop hasn't run. + EXPECT_EQ(GetLastTask(), 0); + + // Fake the actual message loop. Each time a task is run a new task should + // be added to the queue, hence updating "task". The loop should actually run + // at most twice (once for the failed task plus possibly once for the + // observer), the "4" is a backstop. + for (int i = 0; i < 4 && !observer_called; i++) { + task.Run(); + } + EXPECT_EQ(GetLastTask(), 3); + + EXPECT_TRUE(observer_called); + EXPECT_EQ(observer_result, 1); +} +} // namespace +} // namespace content diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc index ec092d20c1..f7cda5c428 100644 --- a/content/browser/storage_partition_impl.cc +++ b/content/browser/storage_partition_impl.cc @@ -26,132 +26,244 @@ namespace content { namespace { -void DoNothingStatusCallback(quota::QuotaStatusCode status) { - // Do nothing. +int GenerateQuotaClientMask(uint32 remove_mask) { + int quota_client_mask = 0; + + if (remove_mask & StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS) + quota_client_mask |= quota::QuotaClient::kFileSystem; + if (remove_mask & StoragePartition::REMOVE_DATA_MASK_WEBSQL) + quota_client_mask |= quota::QuotaClient::kDatabase; + if (remove_mask & StoragePartition::REMOVE_DATA_MASK_APPCACHE) + quota_client_mask |= quota::QuotaClient::kAppcache; + if (remove_mask & StoragePartition::REMOVE_DATA_MASK_INDEXEDDB) + quota_client_mask |= quota::QuotaClient::kIndexedDatabase; + + return quota_client_mask; } -void ClearQuotaManagedOriginsOnIOThread( - const scoped_refptr<quota::QuotaManager>& quota_manager, - const std::set<GURL>& origins, - quota::StorageType quota_storage_type) { - // The QuotaManager manages all storage other than cookies, LocalStorage, - // and SessionStorage. This loop wipes out most HTML5 storage for the given - // origins. - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - std::set<GURL>::const_iterator origin; - for (std::set<GURL>::const_iterator origin = origins.begin(); - origin != origins.end(); ++origin) { - quota_manager->DeleteOriginData(*origin, quota_storage_type, - quota::QuotaClient::kAllClientsMask, - base::Bind(&DoNothingStatusCallback)); +void OnClearedCookies(const base::Closure& callback, int num_deleted) { + // The final callback needs to happen from UI thread. + if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&OnClearedCookies, callback, num_deleted)); + return; } + + callback.Run(); } -void ClearOriginOnIOThread( - uint32 storage_mask, - const GURL& storage_origin, - const scoped_refptr<net::URLRequestContextGetter>& request_context, - const scoped_refptr<quota::QuotaManager>& quota_manager) { +void ClearCookiesOnIOThread( + const scoped_refptr<net::URLRequestContextGetter>& rq_context, + const base::Time begin, + const base::Time end, + const base::Closure& callback) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + net::CookieStore* cookie_store = rq_context-> + GetURLRequestContext()->cookie_store(); + cookie_store->DeleteAllCreatedBetweenAsync(begin, end, + base::Bind(&OnClearedCookies, callback)); +} - if (storage_mask & StoragePartition::kCookies) { - // Handle the cookies. - net::CookieMonster* cookie_monster = - request_context->GetURLRequestContext()->cookie_store()-> - GetCookieMonster(); - if (cookie_monster) - cookie_monster->DeleteAllForHostAsync( - storage_origin, net::CookieMonster::DeleteCallback()); +void OnQuotaManagedOriginDeleted(const GURL& origin, + quota::StorageType type, + size_t* origins_to_delete_count, + const base::Closure& callback, + quota::QuotaStatusCode status) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DCHECK_GT(*origins_to_delete_count, 0u); + if (status != quota::kQuotaStatusOk) { + DLOG(ERROR) << "Couldn't remove data of type " << type << " for origin " + << origin << ". Status: " << status; } - // Handle all HTML5 storage other than DOMStorageContext. - std::set<GURL> origins; - origins.insert(storage_origin); - if (storage_mask & StoragePartition::kQuotaManagedTemporaryStorage) { - ClearQuotaManagedOriginsOnIOThread(quota_manager, - origins, - quota::kStorageTypeTemporary); - } - if (storage_mask & StoragePartition::kQuotaManagedPersistentStorage) { - ClearQuotaManagedOriginsOnIOThread(quota_manager, - origins, - quota::kStorageTypePersistent); - } - if (storage_mask & StoragePartition::kQuotaManagedSyncableStorage) { - ClearQuotaManagedOriginsOnIOThread(quota_manager, - origins, - quota::kStorageTypeSyncable); + (*origins_to_delete_count)--; + if (*origins_to_delete_count == 0) { + delete origins_to_delete_count; + callback.Run(); } } -void ClearAllDataOnIOThread( - uint32 storage_mask, - const scoped_refptr<net::URLRequestContextGetter>& request_context, - const scoped_refptr<quota::QuotaManager>& quota_manager) { +void ClearQuotaManagedOriginsOnIOThread(quota::QuotaManager* quota_manager, + uint32 remove_mask, + const base::Closure& callback, + const std::set<GURL>& origins, + quota::StorageType quota_storage_type) { + // The QuotaManager manages all storage other than cookies, LocalStorage, + // and SessionStorage. This loop wipes out most HTML5 storage for the given + // origins. DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - if (storage_mask & StoragePartition::kCookies) { - // Handle the cookies. - net::CookieMonster* cookie_monster = - request_context->GetURLRequestContext()->cookie_store()-> - GetCookieMonster(); - if (cookie_monster) - cookie_monster->DeleteAllAsync(net::CookieMonster::DeleteCallback()); + if (!origins.size()) { + // No origins to clear. + callback.Run(); + return; } - // Handle all HTML5 storage other than DOMStorageContext. - if (storage_mask & StoragePartition::kQuotaManagedTemporaryStorage) { - quota_manager->GetOriginsModifiedSince( - quota::kStorageTypeTemporary, base::Time(), - base::Bind(&ClearQuotaManagedOriginsOnIOThread, quota_manager)); - } - if (storage_mask & StoragePartition::kQuotaManagedPersistentStorage) { - quota_manager->GetOriginsModifiedSince( - quota::kStorageTypePersistent, base::Time(), - base::Bind(&ClearQuotaManagedOriginsOnIOThread, quota_manager)); - } - if (storage_mask & StoragePartition::kQuotaManagedSyncableStorage) { - quota_manager->GetOriginsModifiedSince( - quota::kStorageTypeSyncable, base::Time(), - base::Bind(&ClearQuotaManagedOriginsOnIOThread, quota_manager)); + std::set<GURL>::const_iterator origin; + size_t* origins_to_delete_count = new size_t(origins.size()); + for (std::set<GURL>::const_iterator origin = origins.begin(); + origin != origins.end(); ++origin) { + quota_manager->DeleteOriginData( + *origin, quota_storage_type, + GenerateQuotaClientMask(remove_mask), + base::Bind(&OnQuotaManagedOriginDeleted, + origin->GetOrigin(), quota_storage_type, + origins_to_delete_count, callback)); } } -void ClearedShaderCacheOnIOThread(base::Closure callback) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); +void ClearedShaderCache(const base::Closure& callback) { + if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&ClearedShaderCache, callback)); + return; + } + callback.Run(); } -void ClearShaderCacheOnIOThread(base::FilePath path, - base::Time begin, base::Time end, base::Closure callback) { +void ClearShaderCacheOnIOThread(const base::FilePath& path, + const base::Time begin, + const base::Time end, + const base::Closure& callback) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); ShaderCacheFactory::GetInstance()->ClearByPath( - path, begin, end, - base::Bind(&ClearedShaderCacheOnIOThread, callback)); + path, begin, end, base::Bind(&ClearedShaderCache, callback)); } void OnLocalStorageUsageInfo( const scoped_refptr<DOMStorageContextImpl>& dom_storage_context, + const base::Time delete_begin, + const base::Time delete_end, + const base::Closure& callback, const std::vector<dom_storage::LocalStorageUsageInfo>& infos) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); for (size_t i = 0; i < infos.size(); ++i) { - dom_storage_context->DeleteLocalStorage(infos[i].origin); + if (infos[i].last_modified >= delete_begin && + infos[i].last_modified <= delete_end) { + dom_storage_context->DeleteLocalStorage(infos[i].origin); + } } + callback.Run(); } void OnSessionStorageUsageInfo( const scoped_refptr<DOMStorageContextImpl>& dom_storage_context, + const base::Closure& callback, const std::vector<dom_storage::SessionStorageUsageInfo>& infos) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - for (size_t i = 0; i < infos.size(); ++i) { + for (size_t i = 0; i < infos.size(); ++i) dom_storage_context->DeleteSessionStorage(infos[i]); + + callback.Run(); +} + +void ClearLocalStorageOnUIThread( + const scoped_refptr<DOMStorageContextImpl>& dom_storage_context, + const GURL& remove_origin, + const base::Time begin, + const base::Time end, + const base::Closure& callback) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + if (!remove_origin.is_empty()) { + dom_storage_context->DeleteLocalStorage(remove_origin); + callback.Run(); + return; } + + dom_storage_context->GetLocalStorageUsage( + base::Bind(&OnLocalStorageUsageInfo, + dom_storage_context, begin, end, callback)); +} + +void ClearSessionStorageOnUIThread( + const scoped_refptr<DOMStorageContextImpl>& dom_storage_context, + const base::Closure& callback) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + dom_storage_context->GetSessionStorageUsage( + base::Bind(&OnSessionStorageUsageInfo, dom_storage_context, callback)); } } // namespace +// Helper for deleting quota managed data from a partition. +// +// Most of the operations in this class are done on IO thread. +struct StoragePartitionImpl::QuotaManagedDataDeletionHelper { + QuotaManagedDataDeletionHelper(const base::Closure& callback) + : callback(callback), task_count(0) { + } + + void IncrementTaskCountOnIO(); + void DecrementTaskCountOnIO(); + + void ClearDataOnIOThread( + const scoped_refptr<quota::QuotaManager>& quota_manager, + const base::Time begin, + uint32 remove_mask, + uint32 quota_storage_remove_mask, + const GURL& remove_origin); + + // Accessed on IO thread. + const base::Closure callback; + // Accessed on IO thread. + int task_count; +}; + +// Helper for deleting all sorts of data from a partition, keeps track of +// deletion status. +// +// StoragePartitionImpl creates an instance of this class to keep track of +// data deletion progress. Deletion requires deleting multiple bits of data +// (e.g. cookies, local storage, session storage etc.) and hopping between UI +// and IO thread. An instance of this class is created in the beginning of +// deletion process (StoragePartitionImpl::ClearDataImpl) and the instance is +// forwarded and updated on each (sub) deletion's callback. The instance is +// finally destroyed when deletion completes (and |callback| is invoked). +struct StoragePartitionImpl::DataDeletionHelper { + DataDeletionHelper(const base::Closure& callback) + : callback(callback), task_count(0) { + } + + void IncrementTaskCountOnUI(); + void DecrementTaskCountOnUI(); + + void ClearDataOnUIThread(uint32 remove_mask, + uint32 quota_storage_remove_mask, + const GURL& remove_origin, + const base::FilePath& path, + net::URLRequestContextGetter* rq_context, + DOMStorageContextImpl* dom_storage_context, + quota::QuotaManager* quota_manager, + const base::Time begin, + const base::Time end); + + // Accessed on UI thread. + const base::Closure callback; + // Accessed on UI thread. + int task_count; +}; + +void ClearQuotaManagedDataOnIOThread( + const scoped_refptr<quota::QuotaManager>& quota_manager, + const base::Time begin, + uint32 remove_mask, + uint32 quota_storage_remove_mask, + const GURL& remove_origin, + const base::Closure& callback) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + StoragePartitionImpl::QuotaManagedDataDeletionHelper* helper = + new StoragePartitionImpl::QuotaManagedDataDeletionHelper(callback); + helper->ClearDataOnIOThread(quota_manager, begin, + remove_mask, quota_storage_remove_mask, remove_origin); +} + StoragePartitionImpl::StoragePartitionImpl( const base::FilePath& partition_path, quota::QuotaManager* quota_manager, @@ -293,59 +405,221 @@ IndexedDBContextImpl* StoragePartitionImpl::GetIndexedDBContext() { return indexed_db_context_.get(); } -void StoragePartitionImpl::AsyncClearDataForOrigin( - uint32 storage_mask, - const GURL& storage_origin, - net::URLRequestContextGetter* request_context_getter) { +void StoragePartitionImpl::ClearDataImpl( + uint32 remove_mask, + uint32 quota_storage_remove_mask, + const GURL& remove_origin, + net::URLRequestContextGetter* rq_context, + const base::Time begin, + const base::Time end, + const base::Closure& callback) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DataDeletionHelper* helper = new DataDeletionHelper(callback); + // |helper| deletes itself when done in + // DataDeletionHelper::DecrementTaskCountOnUI(). + helper->ClearDataOnUIThread( + remove_mask, quota_storage_remove_mask, remove_origin, + GetPath(), rq_context, dom_storage_context_, quota_manager_, begin, end); +} - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&ClearOriginOnIOThread, - storage_mask, - storage_origin, - make_scoped_refptr(request_context_getter), - quota_manager_)); +void StoragePartitionImpl:: + QuotaManagedDataDeletionHelper::IncrementTaskCountOnIO() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + ++task_count; +} + +void StoragePartitionImpl:: + QuotaManagedDataDeletionHelper::DecrementTaskCountOnIO() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DCHECK_GT(task_count, 0); + --task_count; + if (task_count) + return; - if (storage_mask & kLocalDomStorage) - GetDOMStorageContext()->DeleteLocalStorage(storage_origin); + callback.Run(); + delete this; } -void StoragePartitionImpl::AsyncClearData(uint32 storage_mask) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); +void StoragePartitionImpl::QuotaManagedDataDeletionHelper::ClearDataOnIOThread( + const scoped_refptr<quota::QuotaManager>& quota_manager, + const base::Time begin, + uint32 remove_mask, + uint32 quota_storage_remove_mask, + const GURL& remove_origin) { + std::set<GURL> origins; + if (!remove_origin.is_empty()) + origins.insert(remove_origin); + + IncrementTaskCountOnIO(); + base::Closure decrement_callback = base::Bind( + &QuotaManagedDataDeletionHelper::DecrementTaskCountOnIO, + base::Unretained(this)); + + if (quota_storage_remove_mask & QUOTA_MANAGED_STORAGE_MASK_PERSISTENT) { + IncrementTaskCountOnIO(); + if (origins.empty()) { // Remove for all origins. + // Ask the QuotaManager for all origins with temporary quota modified + // within the user-specified timeframe, and deal with the resulting set in + // ClearQuotaManagedOriginsOnIOThread(). + quota_manager->GetOriginsModifiedSince( + quota::kStorageTypePersistent, begin, + base::Bind(&ClearQuotaManagedOriginsOnIOThread, + quota_manager, remove_mask, decrement_callback)); + } else { + ClearQuotaManagedOriginsOnIOThread( + quota_manager, remove_mask, decrement_callback, + origins, quota::kStorageTypePersistent); + } + } - // We ignore the media request context because it shares the same cookie store - // as the main request context. - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&ClearAllDataOnIOThread, - storage_mask, - url_request_context_, - quota_manager_)); - - if (storage_mask & kLocalDomStorage) { - dom_storage_context_->GetLocalStorageUsage( - base::Bind(&OnLocalStorageUsageInfo, dom_storage_context_)); + // Do the same for temporary quota. + if (quota_storage_remove_mask & QUOTA_MANAGED_STORAGE_MASK_TEMPORARY) { + IncrementTaskCountOnIO(); + if (origins.empty()) { // Remove for all origins. + quota_manager->GetOriginsModifiedSince( + quota::kStorageTypeTemporary, begin, + base::Bind(&ClearQuotaManagedOriginsOnIOThread, + quota_manager, remove_mask, decrement_callback)); + } else { + ClearQuotaManagedOriginsOnIOThread( + quota_manager, remove_mask, decrement_callback, + origins, quota::kStorageTypeTemporary); + } } - if (storage_mask & kSessionDomStorage) { - dom_storage_context_->GetSessionStorageUsage( - base::Bind(&OnSessionStorageUsageInfo, dom_storage_context_)); + // Do the same for syncable quota. + if (quota_storage_remove_mask & QUOTA_MANAGED_STORAGE_MASK_SYNCABLE) { + IncrementTaskCountOnIO(); + if (origins.empty()) { // Remove for all origins. + quota_manager->GetOriginsModifiedSince( + quota::kStorageTypeSyncable, begin, + base::Bind(&ClearQuotaManagedOriginsOnIOThread, + quota_manager, remove_mask, decrement_callback)); + } else { + ClearQuotaManagedOriginsOnIOThread( + quota_manager, remove_mask, decrement_callback, + origins, quota::kStorageTypeSyncable); + } } + + DecrementTaskCountOnIO(); } -void StoragePartitionImpl::AsyncClearDataBetween(uint32 storage_mask, - const base::Time& begin, const base::Time& end, - const base::Closure& callback) { +void StoragePartitionImpl::DataDeletionHelper::IncrementTaskCountOnUI() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - DCHECK(storage_mask == kShaderStorage); + ++task_count; +} - if (storage_mask & kShaderStorage) { +void StoragePartitionImpl::DataDeletionHelper::DecrementTaskCountOnUI() { + if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&DataDeletionHelper::DecrementTaskCountOnUI, + base::Unretained(this))); + return; + } + DCHECK_GT(task_count, 0); + --task_count; + if (!task_count) { + callback.Run(); + delete this; + } +} + +void StoragePartitionImpl::DataDeletionHelper::ClearDataOnUIThread( + uint32 remove_mask, + uint32 quota_storage_remove_mask, + const GURL& remove_origin, + const base::FilePath& path, + net::URLRequestContextGetter* rq_context, + DOMStorageContextImpl* dom_storage_context, + quota::QuotaManager* quota_manager, + const base::Time begin, + const base::Time end) { + DCHECK_NE(remove_mask, 0u); + DCHECK(!callback.is_null()); + + IncrementTaskCountOnUI(); + base::Closure decrement_callback = base::Bind( + &DataDeletionHelper::DecrementTaskCountOnUI, base::Unretained(this)); + + if (remove_mask & REMOVE_DATA_MASK_COOKIES) { + // Handle the cookies. + IncrementTaskCountOnUI(); + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(&ClearCookiesOnIOThread, + make_scoped_refptr(rq_context), begin, end, + decrement_callback)); + } + + if (remove_mask & REMOVE_DATA_MASK_INDEXEDDB || + remove_mask & REMOVE_DATA_MASK_WEBSQL || + remove_mask & REMOVE_DATA_MASK_APPCACHE || + remove_mask & REMOVE_DATA_MASK_FILE_SYSTEMS) { + IncrementTaskCountOnUI(); + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(&ClearQuotaManagedDataOnIOThread, + make_scoped_refptr(quota_manager), begin, + remove_mask, quota_storage_remove_mask, remove_origin, + decrement_callback)); + } + + if (remove_mask & REMOVE_DATA_MASK_LOCAL_STORAGE) { + IncrementTaskCountOnUI(); + ClearLocalStorageOnUIThread( + make_scoped_refptr(dom_storage_context), + remove_origin, begin, end, decrement_callback); + + // ClearDataImpl cannot clear session storage data when a particular origin + // is specified. Therefore we ignore clearing session storage in this case. + // TODO(lazyboy): Fix. + if (remove_origin.is_empty()) { + IncrementTaskCountOnUI(); + ClearSessionStorageOnUIThread( + make_scoped_refptr(dom_storage_context), decrement_callback); + } + } + + if (remove_mask & REMOVE_DATA_MASK_SHADER_CACHE) { + IncrementTaskCountOnUI(); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - base::Bind(&ClearShaderCacheOnIOThread, GetPath(), begin, end, - callback)); + base::Bind(&ClearShaderCacheOnIOThread, + path, begin, end, decrement_callback)); } + + DecrementTaskCountOnUI(); +} + + +void StoragePartitionImpl::ClearDataForOrigin( + uint32 remove_mask, + uint32 quota_storage_remove_mask, + const GURL& storage_origin, + net::URLRequestContextGetter* request_context_getter) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + ClearDataImpl(remove_mask, quota_storage_remove_mask, storage_origin, + request_context_getter, base::Time(), base::Time::Max(), + base::Bind(&base::DoNothing)); +} + +void StoragePartitionImpl::ClearDataForUnboundedRange( + uint32 remove_mask, + uint32 quota_storage_remove_mask) { + ClearDataImpl(remove_mask, quota_storage_remove_mask, GURL(), + GetURLRequestContext(), base::Time(), base::Time::Max(), + base::Bind(&base::DoNothing)); +} + +void StoragePartitionImpl::ClearDataForRange(uint32 remove_mask, + uint32 quota_storage_remove_mask, + const base::Time& begin, + const base::Time& end, + const base::Closure& callback) { + ClearDataImpl(remove_mask, quota_storage_remove_mask, GURL(), + GetURLRequestContext(), begin, end, callback); } WebRTCIdentityStore* StoragePartitionImpl::GetWebRTCIdentityStore() { diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h index 9dcdfeced5..0410f4d909 100644 --- a/content/browser/storage_partition_impl.h +++ b/content/browser/storage_partition_impl.h @@ -31,19 +31,26 @@ class StoragePartitionImpl : public StoragePartition { virtual webkit_database::DatabaseTracker* GetDatabaseTracker() OVERRIDE; virtual DOMStorageContextImpl* GetDOMStorageContext() OVERRIDE; virtual IndexedDBContextImpl* GetIndexedDBContext() OVERRIDE; - virtual void AsyncClearDataForOrigin( - uint32 storage_mask, + + virtual void ClearDataForOrigin( + uint32 remove_mask, + uint32 quota_storage_remove_mask, const GURL& storage_origin, net::URLRequestContextGetter* request_context_getter) OVERRIDE; - virtual void AsyncClearData(uint32 storage_mask) OVERRIDE; - virtual void AsyncClearDataBetween( - uint32 storage_mask, - const base::Time& begin, - const base::Time& end, - const base::Closure& callback) OVERRIDE; + virtual void ClearDataForUnboundedRange( + uint32 remove_mask, + uint32 quota_storage_remove_mask) OVERRIDE; + virtual void ClearDataForRange(uint32 remove_mask, + uint32 quota_storage_remove_mask, + const base::Time& begin, + const base::Time& end, + const base::Closure& callback) OVERRIDE; WebRTCIdentityStore* GetWebRTCIdentityStore(); + struct DataDeletionHelper; + struct QuotaManagedDataDeletionHelper; + private: friend class StoragePartitionImplMap; FRIEND_TEST_ALL_PREFIXES(StoragePartitionShaderClearTest, ClearShaderCache); @@ -58,6 +65,10 @@ class StoragePartitionImpl : public StoragePartition { bool in_memory, const base::FilePath& profile_path); + // Quota managed data uses a different bitmask for types than + // StoragePartition uses. This method generates that mask. + static int GenerateQuotaClientMask(uint32 remove_mask); + CONTENT_EXPORT StoragePartitionImpl( const base::FilePath& partition_path, quota::QuotaManager* quota_manager, @@ -68,6 +79,14 @@ class StoragePartitionImpl : public StoragePartition { IndexedDBContextImpl* indexed_db_context, scoped_ptr<WebRTCIdentityStore> webrtc_identity_store); + void ClearDataImpl(uint32 remove_mask, + uint32 quota_storage_remove_mask, + const GURL& remove_origin, + net::URLRequestContextGetter* rq_context, + const base::Time begin, + const base::Time end, + const base::Closure& callback); + // Used by StoragePartitionImplMap. // // TODO(ajwong): These should be taken in the constructor and in Create() but diff --git a/content/browser/storage_partition_impl_map.cc b/content/browser/storage_partition_impl_map.cc index 8b6556eec1..c5721aee66 100644 --- a/content/browser/storage_partition_impl_map.cc +++ b/content/browser/storage_partition_impl_map.cc @@ -496,7 +496,11 @@ void StoragePartitionImplMap::AsyncObliterate( ++it) { const StoragePartitionConfig& config = it->first; if (config.partition_domain == partition_domain) { - it->second->AsyncClearData(StoragePartition::kAllStorage); + it->second->ClearDataForUnboundedRange( + // All except shader cache. + StoragePartition::REMOVE_DATA_MASK_ALL & + (~StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE), + StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL); if (!config.in_memory) { paths_to_keep.push_back(it->second->GetPath()); } diff --git a/content/browser/storage_partition_impl_unittest.cc b/content/browser/storage_partition_impl_unittest.cc index 36af6387a6..22078374f5 100644 --- a/content/browser/storage_partition_impl_unittest.cc +++ b/content/browser/storage_partition_impl_unittest.cc @@ -98,8 +98,10 @@ class StoragePartitionShaderClearTest : public testing::Test { void ClearData(content::StoragePartitionImpl* sp, const base::Closure& cb) { base::Time time; - sp->AsyncClearDataBetween(content::StoragePartition::kShaderStorage, - time, time, cb); + sp->ClearDataForRange( + StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE, + StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, + time, time, cb); } TEST_F(StoragePartitionShaderClearTest, ClearShaderCache) { diff --git a/content/browser/streams/stream.cc b/content/browser/streams/stream.cc index 38f91b82e5..f1fa1043e7 100644 --- a/content/browser/streams/stream.cc +++ b/content/browser/streams/stream.cc @@ -72,7 +72,7 @@ void Stream::AddData(scoped_refptr<net::IOBuffer> buffer, size_t size) { } void Stream::Finalize() { - writer_->Close(DOWNLOAD_INTERRUPT_REASON_NONE); + writer_->Close(0); writer_.reset(NULL); // Continue asynchronously. diff --git a/content/browser/web_contents/render_view_host_manager.cc b/content/browser/web_contents/render_view_host_manager.cc index 0c8d26f1b2..9d29a09c6a 100644 --- a/content/browser/web_contents/render_view_host_manager.cc +++ b/content/browser/web_contents/render_view_host_manager.cc @@ -490,14 +490,10 @@ SiteInstance* RenderViewHostManager::GetSiteInstanceForEntry( SiteInstance* curr_instance) { // NOTE: This is only called when ShouldTransitionCrossSite is true. + const GURL& dest_url = entry.GetURL(); NavigationControllerImpl& controller = delegate_->GetControllerForRenderManager(); BrowserContext* browser_context = controller.GetBrowserContext(); - const GURL& dest_url = GetContentClient()->browser()-> - GetPossiblyPrivilegedURL(browser_context, - entry.GetURL(), - entry.is_renderer_initiated(), - curr_instance); // If the entry has an instance already we should use it. if (entry.site_instance()) diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index fe34bc0ef8..e9f0a1fbe5 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc @@ -9,6 +9,7 @@ #include "base/command_line.h" #include "base/debug/trace_event.h" #include "base/lazy_instance.h" +#include "base/logging.h" #include "base/metrics/histogram.h" #include "base/metrics/stats_counters.h" #include "base/strings/string16.h" @@ -81,6 +82,7 @@ #include "net/url_request/url_request_context_getter.h" #include "ui/base/layout.h" #include "ui/base/touch/touch_device.h" +#include "ui/base/touch/touch_enabled.h" #include "ui/base/ui_base_switches.h" #include "ui/gfx/display.h" #include "ui/gfx/screen.h" @@ -266,7 +268,8 @@ void MakeNavigateParams(const NavigationEntryImpl& entry, } // namespace WebContents* WebContents::Create(const WebContents::CreateParams& params) { - return WebContentsImpl::CreateWithOpener(params, NULL); + return WebContentsImpl::CreateWithOpener( + params, static_cast<WebContentsImpl*>(params.opener)); } WebContents* WebContents::CreateWithSessionStorage( @@ -375,7 +378,7 @@ WebContentsImpl::~WebContentsImpl() { // Clear out any JavaScript state. if (dialog_manager_) - dialog_manager_->ResetJavaScriptState(this); + dialog_manager_->WebContentsDestroyed(this); if (color_chooser_) color_chooser_->End(); @@ -477,11 +480,7 @@ WebPreferences WebContentsImpl::GetWebkitPrefs(RenderViewHost* rvh, prefs.experimental_webgl_enabled = GpuProcessHost::gpu_enabled() && !command_line.HasSwitch(switches::kDisable3DAPIs) && -#if defined(OS_ANDROID) - command_line.HasSwitch(switches::kEnableExperimentalWebGL); -#else !command_line.HasSwitch(switches::kDisableExperimentalWebGL); -#endif prefs.flash_3d_enabled = GpuProcessHost::gpu_enabled() && @@ -559,23 +558,9 @@ WebPreferences WebContentsImpl::GetWebkitPrefs(RenderViewHost* rvh, switches::kDisableGestureRequirementForMediaPlayback); #endif - bool touch_device_present = false; - touch_device_present = ui::IsTouchDevicePresent(); - const std::string touch_enabled_switch = - command_line.HasSwitch(switches::kTouchEvents) ? - command_line.GetSwitchValueASCII(switches::kTouchEvents) : - switches::kTouchEventsAuto; - - if (touch_enabled_switch.empty() || - touch_enabled_switch == switches::kTouchEventsEnabled) { - prefs.touch_enabled = true; - } else if (touch_enabled_switch == switches::kTouchEventsAuto) { - prefs.touch_enabled = touch_device_present; - } else if (touch_enabled_switch != switches::kTouchEventsDisabled) { - LOG(ERROR) << "Invalid --touch-events option: " << touch_enabled_switch; - } - - prefs.device_supports_touch = prefs.touch_enabled && touch_device_present; + prefs.touch_enabled = ui::AreTouchEventsEnabled(); + prefs.device_supports_touch = prefs.touch_enabled && + ui::IsTouchDevicePresent(); #if defined(OS_ANDROID) prefs.device_supports_mouse = false; #endif @@ -2701,6 +2686,8 @@ void WebContentsImpl::DidNavigateMainFramePostCommit( // Once the main frame is navigated, we're no longer considered to have // displayed insecure content. displayed_insecure_content_ = false; + SSLManager::NotifySSLInternalStateChanged( + GetController().GetBrowserContext()); } // Notify observers about navigation. @@ -2712,13 +2699,9 @@ void WebContentsImpl::DidNavigateAnyFramePostCommit( RenderViewHost* render_view_host, const LoadCommittedDetails& details, const ViewHostMsg_FrameNavigate_Params& params) { - // If we navigate off the page, reset JavaScript state. This does nothing - // to prevent a malicious script from spamming messages, since the script - // could just reload the page to stop blocking. - if (dialog_manager_ && !details.is_in_page) { - dialog_manager_->ResetJavaScriptState(this); - dialog_manager_ = NULL; - } + // If we navigate off the page, close all JavaScript dialogs. + if (dialog_manager_ && !details.is_in_page) + dialog_manager_->CancelActiveAndPendingDialogs(this); // Notify observers about navigation. FOR_EACH_OBSERVER(WebContentsObserver, observers_, diff --git a/content/browser/webui/shared_resources_data_source.cc b/content/browser/webui/shared_resources_data_source.cc index 23cdc3d23a..42d0d119cb 100644 --- a/content/browser/webui/shared_resources_data_source.cc +++ b/content/browser/webui/shared_resources_data_source.cc @@ -6,6 +6,7 @@ #include "base/logging.h" #include "base/memory/ref_counted_memory.h" +#include "base/strings/string_util.h" #include "base/threading/thread_restrictions.h" #include "content/public/common/content_client.h" #include "content/public/common/url_constants.h" @@ -14,10 +15,37 @@ namespace { +const char kAppImagesPath[] = "images/apps/"; +const char kAppImagesPath2x[] = "images/2x/apps/"; + +const char kReplacement[] = "../../resources/default_100_percent/common/"; +const char kReplacement2x[] = "../../resources/default_200_percent/common/"; + +// This entire method is a hack introduced to be able to handle apps images +// that exist in the ui/resources directory. From JS/CSS, we still load the +// image as if it were chrome://resources/images/apps/myappimage.png, if that +// path doesn't exist, we check to see if it that image exists in the relative +// path to ui/resources instead. +// TODO(rkc): Once we have a separate source for apps, remove this code. +bool AppsRelativePathMatch(const std::string& path, + const std::string& compareto) { + if (StartsWithASCII(path, kAppImagesPath, false)) { + if (compareto == + (kReplacement + path.substr(arraysize(kAppImagesPath) - 1))) + return true; + } else if (StartsWithASCII(path, kAppImagesPath2x, false)) { + if (compareto == + (kReplacement2x + path.substr(arraysize(kAppImagesPath) - 1))) + return true; + } + return false; +} + int PathToIDR(const std::string& path) { int idr = -1; for (size_t i = 0; i < kWebuiResourcesSize; ++i) { - if (kWebuiResources[i].name == path) { + if ((path == kWebuiResources[i].name) || + AppsRelativePathMatch(path, kWebuiResources[i].name)) { idr = kWebuiResources[i].value; break; } |