diff --git a/.gitignore b/.gitignore index c2ab5fb..6211b63a 100644 --- a/.gitignore +++ b/.gitignore
@@ -412,6 +412,11 @@ /third_party/nacl_sdk_binaries/ /third_party/netty-tcnative/src /third_party/netty4/src +/third_party/node/linux +/third_party/node/mac +/third_party/node/node_modules +/third_party/node/*.tar.gz +/third_party/node/win /third_party/nss /third_party/objenesis/lib/*.jar /third_party/omaha/src/omaha
diff --git a/DEPS b/DEPS index 5aafd26f..283e747 100644 --- a/DEPS +++ b/DEPS
@@ -44,7 +44,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '17c1b84066cacf7ea797b04c678748600ef6ec36', + 'v8_revision': '8ac979195637575c2ac7a0041ee0c9cd676a8b0a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -255,7 +255,7 @@ Var('chromium_git') + '/external/github.com/google/pywebsocket.git' + '@' + '2d7b73c3acbd0f41dcab487ae5c97c6feae06ce2', 'src/media/cdm/api': - Var('chromium_git') + '/chromium/cdm.git' + '@' + '6a62dcef02523e2d5be4defb68a7d9363c7389d2', + Var('chromium_git') + '/chromium/cdm.git' + '@' + '379a18058fee03b429bd5b4a330b78add56efec4', 'src/third_party/mesa/src': Var('chromium_git') + '/chromium/deps/mesa.git' + '@' + 'ef811c6bd4de74e13e7035ca882cc77f85793fef', @@ -1101,6 +1101,56 @@ '--version', ], }, + + # Pull down Node binaries for WebUI toolchain. + { + 'name': 'node_linux64', + 'pattern': '.', + 'action': [ 'download_from_google_storage', + '--no_resume', + '--platform=linux*', + '--extract', + '--no_auth', + '--bucket', 'chromium-nodejs/6.9.4', + '-s', 'src/third_party/node/linux/node-linux-x64.tar.gz.sha1', + ], + }, + { + 'name': 'node_mac', + 'pattern': '.', + 'action': [ 'download_from_google_storage', + '--no_resume', + '--platform=darwin', + '--extract', + '--no_auth', + '--bucket', 'chromium-nodejs/6.9.4', + '-s', 'src/third_party/node/mac/node-darwin-x64.tar.gz.sha1', + ], + }, + { + 'name': 'node_win', + 'pattern': '.', + 'action': [ 'download_from_google_storage', + '--no_resume', + '--platform=win32', + '--no_auth', + '--bucket', 'chromium-nodejs/6.9.4', + '-s', 'src/third_party/node/win/node.exe.sha1', + ], + }, + + # Pull down NPM dependencies for WebUI toolchain. + { + 'name': 'webui_node_modules', + 'pattern': '.', + 'action': [ 'download_from_google_storage', + '--no_resume', + '--extract', + '--no_auth', + '--bucket', 'chromium-nodejs', + '-s', 'src/third_party/node/node_modules.tar.gz.sha1', + ], + }, ] recursedeps = [
diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc index c2fb501..c3fef0f 100644 --- a/android_webview/browser/aw_browser_context.cc +++ b/android_webview/browser/aw_browser_context.cc
@@ -194,12 +194,12 @@ // is given a GUID, stored in this file in the app's data directory. const FilePath guid_file_path = GetPath().Append(FILE_PATH_LITERAL("metrics_guid")); - AwMetricsServiceClient::GetInstance()->Initialize( user_pref_service_.get(), content::BrowserContext::GetDefaultStoragePartition(this)-> GetURLRequestContext(), guid_file_path); + web_restriction_provider_.reset( new web_restrictions::WebRestrictionsClient()); pref_change_registrar_.Add(
diff --git a/android_webview/browser/aw_metrics_service_client.cc b/android_webview/browser/aw_metrics_service_client.cc index facd0fe..c2bdad0 100644 --- a/android_webview/browser/aw_metrics_service_client.cc +++ b/android_webview/browser/aw_metrics_service_client.cc
@@ -4,218 +4,9 @@ #include "android_webview/browser/aw_metrics_service_client.h" -#include "android_webview/common/aw_version_info_values.h" -#include "base/bind.h" -#include "base/files/file_util.h" -#include "base/guid.h" -#include "base/i18n/rtl.h" -#include "components/metrics/call_stack_profile_metrics_provider.h" -#include "components/metrics/enabled_state_provider.h" -#include "components/metrics/gpu/gpu_metrics_provider.h" -#include "components/metrics/metrics_pref_names.h" -#include "components/metrics/metrics_service.h" -#include "components/metrics/metrics_state_manager.h" -#include "components/metrics/net/net_metrics_log_uploader.h" -#include "components/metrics/profiler/profiler_metrics_provider.h" -#include "components/metrics/ui/screen_info_metrics_provider.h" -#include "components/metrics/url_constants.h" -#include "components/prefs/pref_service.h" -#include "content/public/browser/browser_thread.h" - namespace android_webview { -base::LazyInstance<AwMetricsServiceClient>::Leaky g_lazy_instance_; - -namespace { - -const int kUploadIntervalMinutes = 30; - -// Callbacks for metrics::MetricsStateManager::Create. Store/LoadClientInfo -// allow Windows Chrome to back up ClientInfo. They're no-ops for WebView. - -void StoreClientInfo(const metrics::ClientInfo& client_info) {} - -std::unique_ptr<metrics::ClientInfo> LoadClientInfo() { - std::unique_ptr<metrics::ClientInfo> client_info; - return client_info; -} - -// A GUID in text form is composed of 32 hex digits and 4 hyphens. -const size_t GUID_SIZE = 32 + 4; - -void GetOrCreateGUID(const base::FilePath guid_file_path, std::string* guid) { - DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); - - // Try to read an existing GUID. - if (base::ReadFileToStringWithMaxSize(guid_file_path, guid, GUID_SIZE)) { - if (base::IsValidGUID(*guid)) - return; - else - LOG(ERROR) << "Found invalid GUID"; - } - - // We must write a new GUID. - *guid = base::GenerateGUID(); - if (!base::WriteFile(guid_file_path, guid->c_str(), guid->size())) - LOG(ERROR) << "Failed to write new GUID"; - return; -} - -} // namespace - -// static -AwMetricsServiceClient* AwMetricsServiceClient::GetInstance() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - return g_lazy_instance_.Pointer(); -} - -void AwMetricsServiceClient::Initialize( - PrefService* pref_service, - net::URLRequestContextGetter* request_context, - const base::FilePath guid_file_path) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - DCHECK(!is_initialized_); - - pref_service_ = pref_service; - request_context_ = request_context; - - std::string* guid = new std::string; - // Initialization happens on the UI thread, but getting the GUID should happen - // on the file I/O thread. So we start to initialize, then post to get the - // GUID, and then pick up where we left off, back on the UI thread, in - // InitializeWithGUID. - content::BrowserThread::PostTaskAndReply( - content::BrowserThread::FILE, - FROM_HERE, - base::Bind(&GetOrCreateGUID, guid_file_path, guid), - base::Bind(&AwMetricsServiceClient::InitializeWithGUID, - base::Unretained(this), base::Owned(guid))); -} - -void AwMetricsServiceClient::InitializeWithGUID(std::string* guid) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - DCHECK(!is_initialized_); - - pref_service_->SetString(metrics::prefs::kMetricsClientID, *guid); - - metrics_state_manager_ = metrics::MetricsStateManager::Create( - pref_service_, this, base::Bind(&StoreClientInfo), - base::Bind(&LoadClientInfo)); - - metrics_service_.reset(new ::metrics::MetricsService( - metrics_state_manager_.get(), this, pref_service_)); - - metrics_service_->RegisterMetricsProvider( - std::unique_ptr<metrics::MetricsProvider>( - new metrics::NetworkMetricsProvider( - content::BrowserThread::GetBlockingPool()))); - - metrics_service_->RegisterMetricsProvider( - std::unique_ptr<metrics::MetricsProvider>( - new metrics::GPUMetricsProvider)); - - metrics_service_->RegisterMetricsProvider( - std::unique_ptr<metrics::MetricsProvider>( - new metrics::ScreenInfoMetricsProvider)); - - metrics_service_->RegisterMetricsProvider( - std::unique_ptr<metrics::MetricsProvider>( - new metrics::ProfilerMetricsProvider())); - - metrics_service_->RegisterMetricsProvider( - std::unique_ptr<metrics::MetricsProvider>( - new metrics::CallStackProfileMetricsProvider)); - - metrics_service_->InitializeMetricsRecordingState(); - - is_initialized_ = true; - - if (IsReportingEnabled()) - metrics_service_->Start(); -} - -void AwMetricsServiceClient::SetMetricsEnabled(bool enabled) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - - // If the client is already initialized, apply the setting immediately. - // Otherwise, it will be applied on initialization. - if (is_initialized_ && is_enabled_ != enabled) { - if (enabled) - metrics_service_->Start(); - else - metrics_service_->Stop(); - } - is_enabled_ = enabled; -} - -bool AwMetricsServiceClient::IsConsentGiven() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - return is_enabled_; -} - -metrics::MetricsService* AwMetricsServiceClient::GetMetricsService() { - return metrics_service_.get(); -} - -// In Chrome, UMA and Breakpad are enabled/disabled together by the same -// checkbox and they share the same client ID (a.k.a. GUID). SetMetricsClientId -// is intended to provide the ID to Breakpad. In WebView, UMA and Breakpad are -// independent, so this is a no-op. - -void AwMetricsServiceClient::SetMetricsClientId(const std::string& client_id) {} - -int32_t AwMetricsServiceClient::GetProduct() { - return ::metrics::ChromeUserMetricsExtension::ANDROID_WEBVIEW; -} - -std::string AwMetricsServiceClient::GetApplicationLocale() { - return base::i18n::GetConfiguredLocale(); -} - -bool AwMetricsServiceClient::GetBrand(std::string* brand_code) { - // WebView doesn't use brand codes. - return false; -} - -metrics::SystemProfileProto::Channel AwMetricsServiceClient::GetChannel() { - // "Channel" means stable, beta, etc. WebView doesn't have channel info yet. - // TODO(paulmiller) Update this once we have channel info. - return metrics::SystemProfileProto::CHANNEL_UNKNOWN; -} - -std::string AwMetricsServiceClient::GetVersionString() { - return PRODUCT_VERSION; -} - -void AwMetricsServiceClient::InitializeSystemProfileMetrics( - const base::Closure& done_callback) { - done_callback.Run(); -} - -void AwMetricsServiceClient::CollectFinalMetricsForLog( - const base::Closure& done_callback) { - done_callback.Run(); -} - -std::unique_ptr<metrics::MetricsLogUploader> -AwMetricsServiceClient::CreateUploader( - const std::string& server_url, - const std::string& mime_type, - const base::Callback<void(int)>& on_upload_complete) { - return std::unique_ptr<::metrics::MetricsLogUploader>( - new metrics::NetMetricsLogUploader( - request_context_, server_url, mime_type, on_upload_complete)); -} - -base::TimeDelta AwMetricsServiceClient::GetStandardUploadInterval() { - return base::TimeDelta::FromMinutes(kUploadIntervalMinutes); -} - -AwMetricsServiceClient::AwMetricsServiceClient() - : is_initialized_(false), - is_enabled_(false), - pref_service_(nullptr), - request_context_(nullptr) {} +AwMetricsServiceClient::AwMetricsServiceClient() {} AwMetricsServiceClient::~AwMetricsServiceClient() {}
diff --git a/android_webview/browser/aw_metrics_service_client.h b/android_webview/browser/aw_metrics_service_client.h index 3bfc5123..82ac198 100644 --- a/android_webview/browser/aw_metrics_service_client.h +++ b/android_webview/browser/aw_metrics_service_client.h
@@ -5,12 +5,6 @@ #ifndef ANDROID_WEBVIEW_BROWSER_AW_METRICS_SERVICE_CLIENT_IMPL_H_ #define ANDROID_WEBVIEW_BROWSER_AW_METRICS_SERVICE_CLIENT_IMPL_H_ -#include <memory> -#include <string> - -#include "android_webview/browser/aw_metrics_service_client.h" -#include "base/lazy_instance.h" -#include "base/macros.h" #include "components/metrics/enabled_state_provider.h" #include "components/metrics/metrics_service_client.h" @@ -20,69 +14,25 @@ class FilePath; } -namespace metrics { -class MetricsStateManager; -} - namespace net { class URLRequestContextGetter; } namespace android_webview { -// This singleton manages metrics for an app using any number of WebViews. The -// homonymous Java class is responsible for turning metrics on and off. This -// singleton must always be used on the same thread. (Currently the UI thread -// is enforced, but it could be any thread.) This is to prevent enable/disable -// race conditions, and because MetricsService is single-threaded. -// Initialization is asynchronous; even after Initialize has returned, some -// methods may not be ready to use (see below). class AwMetricsServiceClient : public metrics::MetricsServiceClient, public metrics::EnabledStateProvider { - friend struct base::DefaultLazyInstanceTraits<AwMetricsServiceClient>; - public: - // These may be called at any time. static AwMetricsServiceClient* GetInstance(); - void Initialize(PrefService* pref_service, - net::URLRequestContextGetter* request_context, - const base::FilePath guid_file_path); - void SetMetricsEnabled(bool enabled); + virtual void Initialize(PrefService* pref_service, + net::URLRequestContextGetter* request_context, + const base::FilePath guid_file_path) = 0; - // metrics::EnabledStateProvider: - bool IsConsentGiven() override; - - // These implement metrics::MetricsServiceClient. They must not be called - // until initialization has asynchronously finished. - metrics::MetricsService* GetMetricsService() override; - void SetMetricsClientId(const std::string& client_id) override; - int32_t GetProduct() override; - std::string GetApplicationLocale() override; - bool GetBrand(std::string* brand_code) override; - metrics::SystemProfileProto::Channel GetChannel() override; - std::string GetVersionString() override; - void InitializeSystemProfileMetrics( - const base::Closure& done_callback) override; - void CollectFinalMetricsForLog(const base::Closure& done_callback) override; - std::unique_ptr<metrics::MetricsLogUploader> CreateUploader( - const std::string& server_url, - const std::string& mime_type, - const base::Callback<void(int)>& on_upload_complete) override; - base::TimeDelta GetStandardUploadInterval() override; - - private: + protected: AwMetricsServiceClient(); ~AwMetricsServiceClient() override; - void InitializeWithGUID(std::string* guid); - - bool is_initialized_; - bool is_enabled_; - PrefService* pref_service_; - net::URLRequestContextGetter* request_context_; - std::unique_ptr<metrics::MetricsStateManager> metrics_state_manager_; - std::unique_ptr<metrics::MetricsService> metrics_service_; - + private: DISALLOW_COPY_AND_ASSIGN(AwMetricsServiceClient); };
diff --git a/android_webview/glue/glue.gni b/android_webview/glue/glue.gni index e3f044c..c85dcd6 100644 --- a/android_webview/glue/glue.gni +++ b/android_webview/glue/glue.gni
@@ -6,6 +6,7 @@ # ResourceRewrite.java need to be generated according 'glue' deps. glue_library_deps = [ "//android_webview:android_webview_java", + "//android_webview:android_webview_platform_services_java", "//base:base_java", "//content/public/android:content_java", "//net/android:net_java",
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java index f98410d6..b7fb06b 100644 --- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java +++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
@@ -24,6 +24,7 @@ import android.webkit.GeolocationPermissions; import android.webkit.ServiceWorkerController; import android.webkit.TokenBindingService; +import android.webkit.ValueCallback; import android.webkit.WebStorage; import android.webkit.WebView; import android.webkit.WebViewDatabase; @@ -40,11 +41,13 @@ import org.chromium.android_webview.AwContentsStatics; import org.chromium.android_webview.AwCookieManager; import org.chromium.android_webview.AwDevToolsServer; +import org.chromium.android_webview.AwMetricsServiceClient; import org.chromium.android_webview.AwNetworkChangeNotifierRegistrationPolicy; import org.chromium.android_webview.AwQuotaManagerBridge; import org.chromium.android_webview.AwResource; import org.chromium.android_webview.AwSettings; import org.chromium.android_webview.HttpAuthDatabase; +import org.chromium.android_webview.PlatformServiceBridge; import org.chromium.android_webview.ResourcesContextWrapperFactory; import org.chromium.base.BuildConfig; import org.chromium.base.CommandLine; @@ -396,7 +399,7 @@ // Make sure that ResourceProvider is initialized before starting the browser process. final String webViewPackageName = WebViewFactory.getLoadedPackageInfo().packageName; - Context context = ContextUtils.getApplicationContext(); + final Context context = ContextUtils.getApplicationContext(); setUpResources(webViewPackageName, context); initPlatSupportLibrary(); initNetworkChangeNotifier(context); @@ -405,6 +408,14 @@ AwBrowserProcess.start(); AwBrowserProcess.handleMinidumps(webViewPackageName); + PlatformServiceBridge.getInstance(context) + .queryMetricsSetting(new ValueCallback<Boolean>() { + public void onReceiveValue(Boolean enabled) { + ThreadUtils.assertOnUiThread(); + AwMetricsServiceClient.setConsentSetting(context, enabled); + } + }); + if (isBuildDebuggable()) { setWebContentsDebuggingEnabled(true); }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwBrowserContext.java b/android_webview/java/src/org/chromium/android_webview/AwBrowserContext.java index 32ee78b..52869fb 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwBrowserContext.java +++ b/android_webview/java/src/org/chromium/android_webview/AwBrowserContext.java
@@ -24,13 +24,11 @@ private AwGeolocationPermissions mGeolocationPermissions; private AwFormDatabase mFormDatabase; private AppWebMessagePortService mMessagePortService; - private AwMetricsServiceClient mMetricsServiceClient; private AwServiceWorkerController mServiceWorkerController; private Context mApplicationContext; public AwBrowserContext(SharedPreferences sharedPreferences, Context applicationContext) { mSharedPreferences = sharedPreferences; - mMetricsServiceClient = new AwMetricsServiceClient(applicationContext); mApplicationContext = applicationContext; } @@ -55,10 +53,6 @@ return mMessagePortService; } - public AwMetricsServiceClient getMetricsServiceClient() { - return mMetricsServiceClient; - } - public AwServiceWorkerController getServiceWorkerController() { if (mServiceWorkerController == null) { mServiceWorkerController = new AwServiceWorkerController(mApplicationContext, this);
diff --git a/android_webview/java/src/org/chromium/android_webview/AwMetricsServiceClient.java b/android_webview/java/src/org/chromium/android_webview/AwMetricsServiceClient.java index 09173a3..209c8a6 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwMetricsServiceClient.java +++ b/android_webview/java/src/org/chromium/android_webview/AwMetricsServiceClient.java
@@ -7,15 +7,25 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.webkit.ValueCallback; import org.chromium.base.Log; +import org.chromium.base.ThreadUtils; +import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; /** - * Java twin of the homonymous C++ class. The Java side is only responsible for - * switching metrics on and off. Since the setting is a platform feature, it - * must be obtained through PlatformServiceBridge. + * Determines whether metrics should be enabled. + * + * This requires the following steps: + * 1) Check the platform's metrics consent setting. + * 2) Check if the app has opted out. + * 3) Wait for the native AwMetricsServiceClient to call nativeInitialized. + * 4) If enabled, inform the native AwMetricsServiceClient via nativeSetMetricsEnabled. + * + * Step 1 is done asynchronously and the result is passed to setConsentSetting, which does step 2. + * This happens in parallel with native AwMetricsServiceClient initialization; either + * nativeInitialized or setConsentSetting might fire first. Whichever fires second should call + * nativeSetMetricsEnabled. */ @JNINamespace("android_webview") public class AwMetricsServiceClient { @@ -25,10 +35,13 @@ // reporting. See https://developer.android.com/reference/android/webkit/WebView.html private static final String OPT_OUT_META_DATA_STR = "android.webkit.WebView.MetricsOptOut"; - private static boolean isAppOptedOut(Context applicationContext) { + private static boolean sIsClientReady; // Is the native AwMetricsServiceClient initialized? + private static boolean sShouldEnable; // Have steps 1 and 2 passed? + + private static boolean isAppOptedOut(Context appContext) { try { - ApplicationInfo info = applicationContext.getPackageManager().getApplicationInfo( - applicationContext.getPackageName(), PackageManager.GET_META_DATA); + ApplicationInfo info = appContext.getPackageManager().getApplicationInfo( + appContext.getPackageName(), PackageManager.GET_META_DATA); if (info.metaData == null) { // null means no such tag was found. return false; @@ -43,18 +56,27 @@ } } - public AwMetricsServiceClient(Context applicationContext) { - if (isAppOptedOut(applicationContext)) { + public static void setConsentSetting(Context appContext, boolean userConsent) { + ThreadUtils.assertOnUiThread(); + + if (!userConsent || isAppOptedOut(appContext)) { + // Metrics defaults to off, so no need to call nativeSetMetricsEnabled(false). return; } - // Check if the user has consented. - PlatformServiceBridge.getInstance(applicationContext) - .setMetricsSettingListener(new ValueCallback<Boolean>() { - public void onReceiveValue(Boolean enabled) { - nativeSetMetricsEnabled(enabled); - } - }); + sShouldEnable = true; + if (sIsClientReady) { + nativeSetMetricsEnabled(true); + } + } + + @CalledByNative + public static void nativeInitialized() { + ThreadUtils.assertOnUiThread(); + sIsClientReady = true; + if (sShouldEnable) { + nativeSetMetricsEnabled(true); + } } public static native void nativeSetMetricsEnabled(boolean enabled);
diff --git a/android_webview/java/src/org/chromium/android_webview/PlatformServiceBridge.java b/android_webview/java/src/org/chromium/android_webview/PlatformServiceBridge.java index 8818ce0f..b41d091 100644 --- a/android_webview/java/src/org/chromium/android_webview/PlatformServiceBridge.java +++ b/android_webview/java/src/org/chromium/android_webview/PlatformServiceBridge.java
@@ -8,6 +8,7 @@ import android.webkit.ValueCallback; import org.chromium.base.Log; +import org.chromium.base.ThreadUtils; import java.lang.reflect.InvocationTargetException; @@ -24,7 +25,9 @@ protected PlatformServiceBridge() {} - public static PlatformServiceBridge getInstance(Context applicationContext) { + public static PlatformServiceBridge getInstance(Context appContext) { + ThreadUtils.assertOnUiThread(); // Avoid race conditions on sInstance. + if (sInstance != null) { return sInstance; } @@ -33,7 +36,7 @@ try { Class<?> cls = Class.forName(PLATFORM_SERVICE_BRIDGE); sInstance = (PlatformServiceBridge) cls.getDeclaredConstructor(Context.class) - .newInstance(applicationContext); + .newInstance(appContext); return sInstance; } catch (ClassNotFoundException e) { // This is not an error; it just means this device doesn't have specialized services. @@ -49,13 +52,21 @@ return sInstance; } - // Try to enable WebView to use Google Play Services (a.k.a. GMS) APIs. Return true on success. - // Do not use GMS APIs before this has returned true, or if it returns false. This can be called - // from multiple threads, so long as no thread uses GMS APIs before at least one call has - // returned true. (The easy way is for each thread to wait for its own call to return true.) + // TODO(paulmiller): remove; replaced by canUseGms public boolean tryEnableGms() { return false; } - public void setMetricsSettingListener(ValueCallback<Boolean> callback) {} + // Can WebView use Google Play Services (a.k.a. GMS)? + public boolean canUseGms() { + return false; + } + + // Overriding implementations may call "callback" asynchronously. For simplicity (and not + // because of any technical limitation) we require that "queryMetricsSetting" and "callback" + // both get called on WebView's UI thread. + public void queryMetricsSetting(ValueCallback<Boolean> callback) { + ThreadUtils.assertOnUiThread(); + callback.onReceiveValue(false); + } }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwStrictModeTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwStrictModeTest.java index d12cd37..898d9eb 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AwStrictModeTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwStrictModeTest.java
@@ -7,7 +7,6 @@ import android.os.StrictMode; import android.support.test.filters.LargeTest; -import org.chromium.android_webview.AwBrowserProcess; import org.chromium.base.test.util.Feature; /** @@ -99,11 +98,11 @@ private void startEverythingSync() throws Exception { getActivity(); + createAwBrowserContext(); + startBrowserProcess(); getInstrumentation().runOnMainSync(new Runnable() { @Override public void run() { - createAwBrowserContext(); - AwBrowserProcess.start(); mAwTestContainerView = createAwTestContainerView(mContentsClient); } });
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java index d37e9b4..a0ce792 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java
@@ -98,12 +98,18 @@ if (mBrowserContext != null) { throw new AndroidRuntimeException("There should only be one browser context."); } - Context appContext = getInstrumentation().getTargetContext().getApplicationContext(); - mBrowserContext = new AwBrowserContext(new InMemorySharedPreferences(), appContext); + final InMemorySharedPreferences prefs = new InMemorySharedPreferences(); + final Context appContext = getInstrumentation().getTargetContext().getApplicationContext(); + getInstrumentation().runOnMainSync(new Runnable() { + @Override + public void run() { + mBrowserContext = new AwBrowserContext(prefs, appContext); + } + }); } protected void startBrowserProcess() throws Exception { - // The activity must be launched in order for proper webview statics to be setup. + // The Activity must be launched in order for proper webview statics to be setup. getActivity(); getInstrumentation().runOnMainSync(new Runnable() { @Override
diff --git a/android_webview/native/BUILD.gn b/android_webview/native/BUILD.gn index 6eaba42..2b2d04e 100644 --- a/android_webview/native/BUILD.gn +++ b/android_webview/native/BUILD.gn
@@ -68,8 +68,8 @@ "aw_locale_manager_impl.h", "aw_media_url_interceptor.cc", "aw_media_url_interceptor.h", - "aw_metrics_switch.cc", - "aw_metrics_switch.h", + "aw_metrics_service_client_impl.cc", + "aw_metrics_service_client_impl.h", "aw_pdf_exporter.cc", "aw_pdf_exporter.h", "aw_picture.cc",
diff --git a/android_webview/native/android_webview_jni_registrar.cc b/android_webview/native/android_webview_jni_registrar.cc index 7697aa14..9523993 100644 --- a/android_webview/native/android_webview_jni_registrar.cc +++ b/android_webview/native/android_webview_jni_registrar.cc
@@ -14,7 +14,7 @@ #include "android_webview/native/aw_form_database.h" #include "android_webview/native/aw_gl_functor.h" #include "android_webview/native/aw_http_auth_handler.h" -#include "android_webview/native/aw_metrics_switch.h" +#include "android_webview/native/aw_metrics_service_client_impl.h" #include "android_webview/native/aw_pdf_exporter.h" #include "android_webview/native/aw_picture.h" #include "android_webview/native/aw_quota_manager_bridge_impl.h"
diff --git a/android_webview/native/aw_metrics_service_client_impl.cc b/android_webview/native/aw_metrics_service_client_impl.cc new file mode 100644 index 0000000..3668f26 --- /dev/null +++ b/android_webview/native/aw_metrics_service_client_impl.cc
@@ -0,0 +1,235 @@ +// Copyright 2017 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 "android_webview/native/aw_metrics_service_client_impl.h" + +#include "android_webview/common/aw_version_info_values.h" +#include "android_webview/jni/AwMetricsServiceClient_jni.h" +#include "base/bind.h" +#include "base/files/file_util.h" +#include "base/guid.h" +#include "base/i18n/rtl.h" +#include "components/metrics/call_stack_profile_metrics_provider.h" +#include "components/metrics/enabled_state_provider.h" +#include "components/metrics/gpu/gpu_metrics_provider.h" +#include "components/metrics/metrics_pref_names.h" +#include "components/metrics/metrics_service.h" +#include "components/metrics/metrics_state_manager.h" +#include "components/metrics/net/net_metrics_log_uploader.h" +#include "components/metrics/profiler/profiler_metrics_provider.h" +#include "components/metrics/ui/screen_info_metrics_provider.h" +#include "components/metrics/url_constants.h" +#include "components/prefs/pref_service.h" +#include "content/public/browser/browser_thread.h" + +namespace android_webview { + +base::LazyInstance<AwMetricsServiceClientImpl>::Leaky g_lazy_instance_; + +namespace { + +const int kUploadIntervalMinutes = 30; + +// Callbacks for metrics::MetricsStateManager::Create. Store/LoadClientInfo +// allow Windows Chrome to back up ClientInfo. They're no-ops for WebView. + +void StoreClientInfo(const metrics::ClientInfo& client_info) {} + +std::unique_ptr<metrics::ClientInfo> LoadClientInfo() { + std::unique_ptr<metrics::ClientInfo> client_info; + return client_info; +} + +// A GUID in text form is composed of 32 hex digits and 4 hyphens. +const size_t GUID_SIZE = 32 + 4; + +void GetOrCreateGUID(const base::FilePath guid_file_path, std::string* guid) { + DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); + + // Try to read an existing GUID. + if (base::ReadFileToStringWithMaxSize(guid_file_path, guid, GUID_SIZE)) { + if (base::IsValidGUID(*guid)) + return; + else + LOG(ERROR) << "Overwriting invalid GUID"; + } + + // We must write a new GUID. + *guid = base::GenerateGUID(); + if (!base::WriteFile(guid_file_path, guid->c_str(), guid->size())) { + // If writing fails, proceed anyway with the new GUID. It won't be persisted + // to the next run, but we can still collect metrics with this 1-time GUID. + LOG(ERROR) << "Failed to write new GUID"; + } + return; +} + +} // namespace + +// static +AwMetricsServiceClient* AwMetricsServiceClient::GetInstance() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + return g_lazy_instance_.Pointer(); +} + +void AwMetricsServiceClientImpl::Initialize( + PrefService* pref_service, + net::URLRequestContextGetter* request_context, + const base::FilePath guid_file_path) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + DCHECK(pref_service_ == nullptr); // Initialize should only happen once. + DCHECK(request_context_ == nullptr); + pref_service_ = pref_service; + request_context_ = request_context; + + std::string* guid = new std::string; + // Initialization happens on the UI thread, but getting the GUID should happen + // on the file I/O thread. So we start to initialize, then post to get the + // GUID, and then pick up where we left off, back on the UI thread, in + // InitializeWithGUID. + content::BrowserThread::PostTaskAndReply( + content::BrowserThread::FILE, + FROM_HERE, + base::Bind(&GetOrCreateGUID, guid_file_path, guid), + base::Bind(&AwMetricsServiceClientImpl::InitializeWithGUID, + base::Unretained(this), base::Owned(guid))); +} + +void AwMetricsServiceClientImpl::InitializeWithGUID(std::string* guid) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + pref_service_->SetString(metrics::prefs::kMetricsClientID, *guid); + + metrics_state_manager_ = metrics::MetricsStateManager::Create( + pref_service_, this, base::Bind(&StoreClientInfo), + base::Bind(&LoadClientInfo)); + + metrics_service_.reset(new ::metrics::MetricsService( + metrics_state_manager_.get(), this, pref_service_)); + + metrics_service_->RegisterMetricsProvider( + std::unique_ptr<metrics::MetricsProvider>( + new metrics::NetworkMetricsProvider( + content::BrowserThread::GetBlockingPool()))); + + metrics_service_->RegisterMetricsProvider( + std::unique_ptr<metrics::MetricsProvider>( + new metrics::GPUMetricsProvider)); + + metrics_service_->RegisterMetricsProvider( + std::unique_ptr<metrics::MetricsProvider>( + new metrics::ScreenInfoMetricsProvider)); + + metrics_service_->RegisterMetricsProvider( + std::unique_ptr<metrics::MetricsProvider>( + new metrics::ProfilerMetricsProvider())); + + metrics_service_->RegisterMetricsProvider( + std::unique_ptr<metrics::MetricsProvider>( + new metrics::CallStackProfileMetricsProvider)); + + metrics_service_->InitializeMetricsRecordingState(); + + JNIEnv* env = base::android::AttachCurrentThread(); + Java_AwMetricsServiceClient_nativeInitialized(env); +} + +bool AwMetricsServiceClientImpl::IsConsentGiven() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + return is_enabled_; +} + +void AwMetricsServiceClientImpl::SetMetricsEnabled(bool enabled) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + if (is_enabled_ != enabled) { + if (enabled) { + // TODO(paulmiller): Actually enable metrics when the server-side is ready + //metrics_service_->Start(); + } else { + metrics_service_->Stop(); + } + is_enabled_ = enabled; + } +} + +metrics::MetricsService* AwMetricsServiceClientImpl::GetMetricsService() { + return metrics_service_.get(); +} + +// In Chrome, UMA and Breakpad are enabled/disabled together by the same +// checkbox and they share the same client ID (a.k.a. GUID). SetMetricsClientId +// is intended to provide the ID to Breakpad. In WebView, UMA and Breakpad are +// independent, so this is a no-op. +void AwMetricsServiceClientImpl::SetMetricsClientId( + const std::string& client_id) {} + +int32_t AwMetricsServiceClientImpl::GetProduct() { + return ::metrics::ChromeUserMetricsExtension::ANDROID_WEBVIEW; +} + +std::string AwMetricsServiceClientImpl::GetApplicationLocale() { + return base::i18n::GetConfiguredLocale(); +} + +bool AwMetricsServiceClientImpl::GetBrand(std::string* brand_code) { + // WebView doesn't use brand codes. + return false; +} + +metrics::SystemProfileProto::Channel AwMetricsServiceClientImpl::GetChannel() { + // "Channel" means stable, beta, etc. WebView doesn't have channel info yet. + // TODO(paulmiller) Update this once we have channel info. + return metrics::SystemProfileProto::CHANNEL_UNKNOWN; +} + +std::string AwMetricsServiceClientImpl::GetVersionString() { + return PRODUCT_VERSION; +} + +void AwMetricsServiceClientImpl::InitializeSystemProfileMetrics( + const base::Closure& done_callback) { + done_callback.Run(); +} + +void AwMetricsServiceClientImpl::CollectFinalMetricsForLog( + const base::Closure& done_callback) { + done_callback.Run(); +} + +std::unique_ptr<metrics::MetricsLogUploader> +AwMetricsServiceClientImpl::CreateUploader( + const std::string& server_url, + const std::string& mime_type, + const base::Callback<void(int)>& on_upload_complete) { + return std::unique_ptr<::metrics::MetricsLogUploader>( + new metrics::NetMetricsLogUploader( + request_context_, server_url, mime_type, on_upload_complete)); +} + +base::TimeDelta AwMetricsServiceClientImpl::GetStandardUploadInterval() { + return base::TimeDelta::FromMinutes(kUploadIntervalMinutes); +} + +AwMetricsServiceClientImpl::AwMetricsServiceClientImpl() + : is_enabled_(false), + pref_service_(nullptr), + request_context_(nullptr) {} + +AwMetricsServiceClientImpl::~AwMetricsServiceClientImpl() {} + +// static +void SetMetricsEnabled( + JNIEnv* env, + const base::android::JavaParamRef<jclass>& jcaller, + jboolean enabled) { + g_lazy_instance_.Pointer()->SetMetricsEnabled(enabled); +} + +bool RegisterAwMetricsServiceClient(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +} // namespace android_webview
diff --git a/android_webview/native/aw_metrics_service_client_impl.h b/android_webview/native/aw_metrics_service_client_impl.h new file mode 100644 index 0000000..75242ad --- /dev/null +++ b/android_webview/native/aw_metrics_service_client_impl.h
@@ -0,0 +1,80 @@ +// Copyright 2017 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 ANDROID_WEBVIEW_NATIVE_AW_METRICS_SERVICE_CLIENT_IMPL_ +#define ANDROID_WEBVIEW_NATIVE_AW_METRICS_SERVICE_CLIENT_IMPL_ + +#include "android_webview/browser/aw_metrics_service_client.h" + +#include <jni.h> +#include <string> + +#include "base/lazy_instance.h" +#include "base/macros.h" + +namespace metrics { +class MetricsStateManager; +} + +namespace android_webview { + +// This singleton manages metrics for an app using any number of WebViews. It +// must always be used on the same thread. (Currently the UI thread is enforced, +// but it could be any thread.) This is to prevent enable/disable race +// conditions, and because MetricsService is single-threaded. Initialization is +// asynchronous; even after Initialize has returned, some methods may not be +// ready to use (see below). +class AwMetricsServiceClientImpl : public AwMetricsServiceClient { + friend struct base::DefaultLazyInstanceTraits<AwMetricsServiceClientImpl>; + + public: + void Initialize(PrefService* pref_service, + net::URLRequestContextGetter* request_context, + const base::FilePath guid_file_path) override; + + // metrics::EnabledStateProvider implementation + bool IsConsentGiven() override; + + // The below functions must not be called until initialization has + // asynchronously finished. + + void SetMetricsEnabled(bool enabled); + + // metrics::MetricsServiceClient implementation + metrics::MetricsService* GetMetricsService() override; + void SetMetricsClientId(const std::string& client_id) override; + int32_t GetProduct() override; + std::string GetApplicationLocale() override; + bool GetBrand(std::string* brand_code) override; + metrics::SystemProfileProto::Channel GetChannel() override; + std::string GetVersionString() override; + void InitializeSystemProfileMetrics( + const base::Closure& done_callback) override; + void CollectFinalMetricsForLog(const base::Closure& done_callback) override; + std::unique_ptr<metrics::MetricsLogUploader> CreateUploader( + const std::string& server_url, + const std::string& mime_type, + const base::Callback<void(int)>& on_upload_complete) override; + base::TimeDelta GetStandardUploadInterval() override; + + private: + AwMetricsServiceClientImpl(); + ~AwMetricsServiceClientImpl() override; + + void InitializeWithGUID(std::string* guid); + + bool is_enabled_; + PrefService* pref_service_; + net::URLRequestContextGetter* request_context_; + std::unique_ptr<metrics::MetricsStateManager> metrics_state_manager_; + std::unique_ptr<metrics::MetricsService> metrics_service_; + + DISALLOW_COPY_AND_ASSIGN(AwMetricsServiceClientImpl); +}; + +bool RegisterAwMetricsServiceClient(JNIEnv* env); + +} // namespace android_webview + +#endif // ANDROID_WEBVIEW_NATIVE_AW_METRICS_SWITCH_
diff --git a/android_webview/native/aw_metrics_switch.cc b/android_webview/native/aw_metrics_switch.cc deleted file mode 100644 index 44ab70a3b..0000000 --- a/android_webview/native/aw_metrics_switch.cc +++ /dev/null
@@ -1,23 +0,0 @@ -// Copyright 2015 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 "android_webview/native/aw_metrics_switch.h" - -#include "android_webview/browser/aw_metrics_service_client.h" -#include "android_webview/jni/AwMetricsServiceClient_jni.h" - -namespace android_webview { - -static void SetMetricsEnabled( - JNIEnv* env, - const base::android::JavaParamRef<jclass>& jcaller, - jboolean enabled) { - AwMetricsServiceClient::GetInstance()->SetMetricsEnabled(enabled); -} - -bool RegisterAwMetricsServiceClient(JNIEnv* env) { - return RegisterNativesImpl(env); -} - -} // namespace android_webview
diff --git a/android_webview/native/aw_metrics_switch.h b/android_webview/native/aw_metrics_switch.h deleted file mode 100644 index 3f07a60..0000000 --- a/android_webview/native/aw_metrics_switch.h +++ /dev/null
@@ -1,16 +0,0 @@ -// Copyright 2015 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 ANDROID_WEBVIEW_NATIVE_AW_METRICS_SWITCH_ -#define ANDROID_WEBVIEW_NATIVE_AW_METRICS_SWITCH_ - -#include <jni.h> - -namespace android_webview { - -bool RegisterAwMetricsServiceClient(JNIEnv* env); - -} // namespace android_webview - -#endif // ANDROID_WEBVIEW_NATIVE_AW_METRICS_SWITCH_
diff --git a/base/BUILD.gn b/base/BUILD.gn index 002a70bf..bdecf4a 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -2042,6 +2042,7 @@ "task_scheduler/test_utils.h", "template_util_unittest.cc", "test/histogram_tester_unittest.cc", + "test/mock_callback_unittest.cc", "test/scoped_mock_time_message_loop_task_runner_unittest.cc", "test/scoped_task_scheduler_unittest.cc", "test/test_pending_task_unittest.cc",
diff --git a/base/json/json_value_converter.h b/base/json/json_value_converter.h index 187c4c4..68ebfa2 100644 --- a/base/json/json_value_converter.h +++ b/base/json/json_value_converter.h
@@ -14,7 +14,7 @@ #include "base/base_export.h" #include "base/logging.h" #include "base/macros.h" -#include "base/memory/scoped_vector.h" +#include "base/memory/ptr_util.h" #include "base/strings/string16.h" #include "base/strings/string_piece.h" #include "base/values.h" @@ -65,9 +65,9 @@ // } // }; // -// For repeated field, we just assume ScopedVector for its container -// and you can put RegisterRepeatedInt or some other types. Use -// RegisterRepeatedMessage for nested repeated fields. +// For repeated field, we just assume std::vector<std::unique_ptr<ElementType>> +// for its container and you can put RegisterRepeatedInt or some other types. +// Use RegisterRepeatedMessage for nested repeated fields. // // Sometimes JSON format uses string representations for other types such // like enum, timestamp, or URL. You can use RegisterCustomField method @@ -247,12 +247,13 @@ }; template <typename Element> -class RepeatedValueConverter : public ValueConverter<ScopedVector<Element> > { +class RepeatedValueConverter + : public ValueConverter<std::vector<std::unique_ptr<Element>>> { public: RepeatedValueConverter() {} bool Convert(const base::Value& value, - ScopedVector<Element>* field) const override { + std::vector<std::unique_ptr<Element>>* field) const override { const base::ListValue* list = NULL; if (!value.GetAsList(&list)) { // The field is not a list. @@ -267,7 +268,7 @@ std::unique_ptr<Element> e(new Element); if (basic_converter_.Convert(*element, e.get())) { - field->push_back(e.release()); + field->push_back(std::move(e)); } else { DVLOG(1) << "failure at " << i << "-th element"; return false; @@ -283,12 +284,12 @@ template <typename NestedType> class RepeatedMessageConverter - : public ValueConverter<ScopedVector<NestedType> > { + : public ValueConverter<std::vector<std::unique_ptr<NestedType>>> { public: RepeatedMessageConverter() {} bool Convert(const base::Value& value, - ScopedVector<NestedType>* field) const override { + std::vector<std::unique_ptr<NestedType>>* field) const override { const base::ListValue* list = NULL; if (!value.GetAsList(&list)) return false; @@ -301,7 +302,7 @@ std::unique_ptr<NestedType> nested(new NestedType); if (converter_.Convert(*element, nested.get())) { - field->push_back(nested.release()); + field->push_back(std::move(nested)); } else { DVLOG(1) << "failure at " << i << "-th element"; return false; @@ -317,7 +318,7 @@ template <typename NestedType> class RepeatedCustomValueConverter - : public ValueConverter<ScopedVector<NestedType> > { + : public ValueConverter<std::vector<std::unique_ptr<NestedType>>> { public: typedef bool(*ConvertFunc)(const base::Value* value, NestedType* field); @@ -325,7 +326,7 @@ : convert_func_(convert_func) {} bool Convert(const base::Value& value, - ScopedVector<NestedType>* field) const override { + std::vector<std::unique_ptr<NestedType>>* field) const override { const base::ListValue* list = NULL; if (!value.GetAsList(&list)) return false; @@ -338,7 +339,7 @@ std::unique_ptr<NestedType> nested(new NestedType); if ((*convert_func_)(element, nested.get())) { - field->push_back(nested.release()); + field->push_back(std::move(nested)); } else { DVLOG(1) << "failure at " << i << "-th element"; return false; @@ -364,41 +365,42 @@ void RegisterIntField(const std::string& field_name, int StructType::* field) { - fields_.push_back(new internal::FieldConverter<StructType, int>( + fields_.push_back(MakeUnique<internal::FieldConverter<StructType, int>>( field_name, field, new internal::BasicValueConverter<int>)); } void RegisterStringField(const std::string& field_name, std::string StructType::* field) { - fields_.push_back(new internal::FieldConverter<StructType, std::string>( - field_name, field, new internal::BasicValueConverter<std::string>)); + fields_.push_back( + MakeUnique<internal::FieldConverter<StructType, std::string>>( + field_name, field, new internal::BasicValueConverter<std::string>)); } void RegisterStringField(const std::string& field_name, string16 StructType::* field) { - fields_.push_back(new internal::FieldConverter<StructType, string16>( - field_name, field, new internal::BasicValueConverter<string16>)); + fields_.push_back( + MakeUnique<internal::FieldConverter<StructType, string16>>( + field_name, field, new internal::BasicValueConverter<string16>)); } void RegisterBoolField(const std::string& field_name, bool StructType::* field) { - fields_.push_back(new internal::FieldConverter<StructType, bool>( + fields_.push_back(MakeUnique<internal::FieldConverter<StructType, bool>>( field_name, field, new internal::BasicValueConverter<bool>)); } void RegisterDoubleField(const std::string& field_name, double StructType::* field) { - fields_.push_back(new internal::FieldConverter<StructType, double>( + fields_.push_back(MakeUnique<internal::FieldConverter<StructType, double>>( field_name, field, new internal::BasicValueConverter<double>)); } template <class NestedType> void RegisterNestedField( const std::string& field_name, NestedType StructType::* field) { - fields_.push_back(new internal::FieldConverter<StructType, NestedType>( - field_name, - field, - new internal::NestedValueConverter<NestedType>)); + fields_.push_back( + MakeUnique<internal::FieldConverter<StructType, NestedType>>( + field_name, field, new internal::NestedValueConverter<NestedType>)); } template <typename FieldType> @@ -406,10 +408,10 @@ const std::string& field_name, FieldType StructType::* field, bool (*convert_func)(const StringPiece&, FieldType*)) { - fields_.push_back(new internal::FieldConverter<StructType, FieldType>( - field_name, - field, - new internal::CustomFieldConverter<FieldType>(convert_func))); + fields_.push_back( + MakeUnique<internal::FieldConverter<StructType, FieldType>>( + field_name, field, + new internal::CustomFieldConverter<FieldType>(convert_func))); } template <typename FieldType> @@ -417,71 +419,76 @@ const std::string& field_name, FieldType StructType::* field, bool (*convert_func)(const base::Value*, FieldType*)) { - fields_.push_back(new internal::FieldConverter<StructType, FieldType>( - field_name, - field, - new internal::ValueFieldConverter<FieldType>(convert_func))); + fields_.push_back( + MakeUnique<internal::FieldConverter<StructType, FieldType>>( + field_name, field, + new internal::ValueFieldConverter<FieldType>(convert_func))); } - void RegisterRepeatedInt(const std::string& field_name, - ScopedVector<int> StructType::* field) { + void RegisterRepeatedInt( + const std::string& field_name, + std::vector<std::unique_ptr<int>> StructType::*field) { fields_.push_back( - new internal::FieldConverter<StructType, ScopedVector<int> >( + MakeUnique<internal::FieldConverter<StructType, + std::vector<std::unique_ptr<int>>>>( field_name, field, new internal::RepeatedValueConverter<int>)); } - void RegisterRepeatedString(const std::string& field_name, - ScopedVector<std::string> StructType::* field) { + void RegisterRepeatedString( + const std::string& field_name, + std::vector<std::unique_ptr<std::string>> StructType::*field) { fields_.push_back( - new internal::FieldConverter<StructType, ScopedVector<std::string> >( - field_name, - field, + MakeUnique<internal::FieldConverter< + StructType, std::vector<std::unique_ptr<std::string>>>>( + field_name, field, new internal::RepeatedValueConverter<std::string>)); } - void RegisterRepeatedString(const std::string& field_name, - ScopedVector<string16> StructType::* field) { - fields_.push_back( - new internal::FieldConverter<StructType, ScopedVector<string16> >( - field_name, - field, - new internal::RepeatedValueConverter<string16>)); + void RegisterRepeatedString( + const std::string& field_name, + std::vector<std::unique_ptr<string16>> StructType::*field) { + fields_.push_back(MakeUnique<internal::FieldConverter< + StructType, std::vector<std::unique_ptr<string16>>>>( + field_name, field, new internal::RepeatedValueConverter<string16>)); } - void RegisterRepeatedDouble(const std::string& field_name, - ScopedVector<double> StructType::* field) { - fields_.push_back( - new internal::FieldConverter<StructType, ScopedVector<double> >( - field_name, field, new internal::RepeatedValueConverter<double>)); + void RegisterRepeatedDouble( + const std::string& field_name, + std::vector<std::unique_ptr<double>> StructType::*field) { + fields_.push_back(MakeUnique<internal::FieldConverter< + StructType, std::vector<std::unique_ptr<double>>>>( + field_name, field, new internal::RepeatedValueConverter<double>)); } - void RegisterRepeatedBool(const std::string& field_name, - ScopedVector<bool> StructType::* field) { - fields_.push_back( - new internal::FieldConverter<StructType, ScopedVector<bool> >( - field_name, field, new internal::RepeatedValueConverter<bool>)); + void RegisterRepeatedBool( + const std::string& field_name, + std::vector<std::unique_ptr<bool>> StructType::*field) { + fields_.push_back(MakeUnique<internal::FieldConverter< + StructType, std::vector<std::unique_ptr<bool>>>>( + field_name, field, new internal::RepeatedValueConverter<bool>)); } template <class NestedType> void RegisterRepeatedCustomValue( const std::string& field_name, - ScopedVector<NestedType> StructType::* field, + std::vector<std::unique_ptr<NestedType>> StructType::*field, bool (*convert_func)(const base::Value*, NestedType*)) { fields_.push_back( - new internal::FieldConverter<StructType, ScopedVector<NestedType> >( - field_name, - field, + MakeUnique<internal::FieldConverter< + StructType, std::vector<std::unique_ptr<NestedType>>>>( + field_name, field, new internal::RepeatedCustomValueConverter<NestedType>( convert_func))); } template <class NestedType> - void RegisterRepeatedMessage(const std::string& field_name, - ScopedVector<NestedType> StructType::* field) { + void RegisterRepeatedMessage( + const std::string& field_name, + std::vector<std::unique_ptr<NestedType>> StructType::*field) { fields_.push_back( - new internal::FieldConverter<StructType, ScopedVector<NestedType> >( - field_name, - field, + MakeUnique<internal::FieldConverter< + StructType, std::vector<std::unique_ptr<NestedType>>>>( + field_name, field, new internal::RepeatedMessageConverter<NestedType>)); } @@ -492,7 +499,7 @@ for (size_t i = 0; i < fields_.size(); ++i) { const internal::FieldConverterBase<StructType>* field_converter = - fields_[i]; + fields_[i].get(); const base::Value* field = NULL; if (dictionary_value->Get(field_converter->field_path(), &field)) { if (!field_converter->ConvertField(*field, output)) { @@ -505,7 +512,8 @@ } private: - ScopedVector<internal::FieldConverterBase<StructType> > fields_; + std::vector<std::unique_ptr<internal::FieldConverterBase<StructType>>> + fields_; DISALLOW_COPY_AND_ASSIGN(JSONValueConverter); };
diff --git a/base/json/json_value_converter_unittest.cc b/base/json/json_value_converter_unittest.cc index 56ade24..6a603d3a 100644 --- a/base/json/json_value_converter_unittest.cc +++ b/base/json/json_value_converter_unittest.cc
@@ -9,7 +9,6 @@ #include <vector> #include "base/json/json_reader.h" -#include "base/memory/scoped_vector.h" #include "base/strings/string_piece.h" #include "base/values.h" #include "testing/gtest/include/gtest/gtest.h" @@ -27,8 +26,8 @@ bool baz; bool bstruct; SimpleEnum simple_enum; - ScopedVector<int> ints; - ScopedVector<std::string> string_values; + std::vector<std::unique_ptr<int>> ints; + std::vector<std::unique_ptr<std::string>> string_values; SimpleMessage() : foo(0), baz(false), bstruct(false), simple_enum(FOO) {} static bool ParseSimpleEnum(const StringPiece& value, SimpleEnum* field) { @@ -80,7 +79,7 @@ struct NestedMessage { double foo; SimpleMessage child; - ScopedVector<SimpleMessage> children; + std::vector<std::unique_ptr<SimpleMessage>> children; NestedMessage() : foo(0) {} @@ -163,7 +162,7 @@ EXPECT_EQ("value_2", *message.child.string_values[1]); EXPECT_EQ(2, static_cast<int>(message.children.size())); - const SimpleMessage* first_child = message.children[0]; + const SimpleMessage* first_child = message.children[0].get(); ASSERT_TRUE(first_child); EXPECT_EQ(2, first_child->foo); EXPECT_EQ("foobar", first_child->bar); @@ -172,7 +171,7 @@ ASSERT_EQ(1U, first_child->string_values.size()); EXPECT_EQ("value_1", *first_child->string_values[0]); - const SimpleMessage* second_child = message.children[1]; + const SimpleMessage* second_child = message.children[1].get(); ASSERT_TRUE(second_child); EXPECT_EQ(3, second_child->foo); EXPECT_EQ("barbaz", second_child->bar);
diff --git a/base/test/BUILD.gn b/base/test/BUILD.gn index 265ef44a..256cae2 100644 --- a/base/test/BUILD.gn +++ b/base/test/BUILD.gn
@@ -48,6 +48,7 @@ "launcher/test_result.h", "launcher/test_results_tracker.h", "launcher/unit_test_launcher.h", + "mock_callback.h", "mock_chrome_application_mac.h", "mock_chrome_application_mac.mm", "mock_devices_changed_observer.cc",
diff --git a/base/test/mock_callback.h b/base/test/mock_callback.h new file mode 100644 index 0000000..7ac4d346 --- /dev/null +++ b/base/test/mock_callback.h
@@ -0,0 +1,366 @@ +// This file was GENERATED by command: +// pump.py mock_callback.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2017 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. + +// Analogous to GMock's built-in MockFunction, but for base::Callback instead of +// std::function. It takes the full callback type as a parameter, so that it can +// support both OnceCallback and RepeatingCallback. +// +// Use: +// using FooCallback = base::Callback<int(std::string)>; +// +// TEST(FooTest, RunsCallbackWithBarArgument) { +// base::MockCallback<FooCallback> callback; +// EXPECT_CALL(callback, Run("bar")).WillOnce(Return(1)); +// Foo(callback.Get()); +// } +// +// Can be used with StrictMock and NiceMock. Caller must ensure that it outlives +// any base::Callback obtained from it. + +#ifndef BASE_TEST_MOCK_CALLBACK_H_ +#define BASE_TEST_MOCK_CALLBACK_H_ + +#include "base/bind.h" +#include "base/callback.h" +#include "base/macros.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace base { + +// clang-format off + +template <typename F> +class MockCallback; + +template <typename R> +class MockCallback<Callback<R()>> { + public: + MockCallback() = default; + MOCK_METHOD0_T(Run, R()); + + Callback<R()> Get() { + return Bind(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +template <typename R> +class MockCallback<OnceCallback<R()>> { + public: + MockCallback() = default; + MOCK_METHOD0_T(Run, R()); + + OnceCallback<R()> Get() { + return BindOnce(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +template <typename R, typename A1> +class MockCallback<Callback<R(A1)>> { + public: + MockCallback() = default; + MOCK_METHOD1_T(Run, R(A1)); + + Callback<R(A1)> Get() { + return Bind(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +template <typename R, typename A1> +class MockCallback<OnceCallback<R(A1)>> { + public: + MockCallback() = default; + MOCK_METHOD1_T(Run, R(A1)); + + OnceCallback<R(A1)> Get() { + return BindOnce(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +template <typename R, typename A1, typename A2> +class MockCallback<Callback<R(A1, A2)>> { + public: + MockCallback() = default; + MOCK_METHOD2_T(Run, R(A1, A2)); + + Callback<R(A1, A2)> Get() { + return Bind(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +template <typename R, typename A1, typename A2> +class MockCallback<OnceCallback<R(A1, A2)>> { + public: + MockCallback() = default; + MOCK_METHOD2_T(Run, R(A1, A2)); + + OnceCallback<R(A1, A2)> Get() { + return BindOnce(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +template <typename R, typename A1, typename A2, typename A3> +class MockCallback<Callback<R(A1, A2, A3)>> { + public: + MockCallback() = default; + MOCK_METHOD3_T(Run, R(A1, A2, A3)); + + Callback<R(A1, A2, A3)> Get() { + return Bind(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +template <typename R, typename A1, typename A2, typename A3> +class MockCallback<OnceCallback<R(A1, A2, A3)>> { + public: + MockCallback() = default; + MOCK_METHOD3_T(Run, R(A1, A2, A3)); + + OnceCallback<R(A1, A2, A3)> Get() { + return BindOnce(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +template <typename R, typename A1, typename A2, typename A3, typename A4> +class MockCallback<Callback<R(A1, A2, A3, A4)>> { + public: + MockCallback() = default; + MOCK_METHOD4_T(Run, R(A1, A2, A3, A4)); + + Callback<R(A1, A2, A3, A4)> Get() { + return Bind(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +template <typename R, typename A1, typename A2, typename A3, typename A4> +class MockCallback<OnceCallback<R(A1, A2, A3, A4)>> { + public: + MockCallback() = default; + MOCK_METHOD4_T(Run, R(A1, A2, A3, A4)); + + OnceCallback<R(A1, A2, A3, A4)> Get() { + return BindOnce(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +template <typename R, typename A1, typename A2, typename A3, typename A4, + typename A5> +class MockCallback<Callback<R(A1, A2, A3, A4, A5)>> { + public: + MockCallback() = default; + MOCK_METHOD5_T(Run, R(A1, A2, A3, A4, A5)); + + Callback<R(A1, A2, A3, A4, A5)> Get() { + return Bind(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +template <typename R, typename A1, typename A2, typename A3, typename A4, + typename A5> +class MockCallback<OnceCallback<R(A1, A2, A3, A4, A5)>> { + public: + MockCallback() = default; + MOCK_METHOD5_T(Run, R(A1, A2, A3, A4, A5)); + + OnceCallback<R(A1, A2, A3, A4, A5)> Get() { + return BindOnce(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +template <typename R, typename A1, typename A2, typename A3, typename A4, + typename A5, typename A6> +class MockCallback<Callback<R(A1, A2, A3, A4, A5, A6)>> { + public: + MockCallback() = default; + MOCK_METHOD6_T(Run, R(A1, A2, A3, A4, A5, A6)); + + Callback<R(A1, A2, A3, A4, A5, A6)> Get() { + return Bind(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +template <typename R, typename A1, typename A2, typename A3, typename A4, + typename A5, typename A6> +class MockCallback<OnceCallback<R(A1, A2, A3, A4, A5, A6)>> { + public: + MockCallback() = default; + MOCK_METHOD6_T(Run, R(A1, A2, A3, A4, A5, A6)); + + OnceCallback<R(A1, A2, A3, A4, A5, A6)> Get() { + return BindOnce(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +template <typename R, typename A1, typename A2, typename A3, typename A4, + typename A5, typename A6, typename A7> +class MockCallback<Callback<R(A1, A2, A3, A4, A5, A6, A7)>> { + public: + MockCallback() = default; + MOCK_METHOD7_T(Run, R(A1, A2, A3, A4, A5, A6, A7)); + + Callback<R(A1, A2, A3, A4, A5, A6, A7)> Get() { + return Bind(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +template <typename R, typename A1, typename A2, typename A3, typename A4, + typename A5, typename A6, typename A7> +class MockCallback<OnceCallback<R(A1, A2, A3, A4, A5, A6, A7)>> { + public: + MockCallback() = default; + MOCK_METHOD7_T(Run, R(A1, A2, A3, A4, A5, A6, A7)); + + OnceCallback<R(A1, A2, A3, A4, A5, A6, A7)> Get() { + return BindOnce(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +template <typename R, typename A1, typename A2, typename A3, typename A4, + typename A5, typename A6, typename A7, typename A8> +class MockCallback<Callback<R(A1, A2, A3, A4, A5, A6, A7, A8)>> { + public: + MockCallback() = default; + MOCK_METHOD8_T(Run, R(A1, A2, A3, A4, A5, A6, A7, A8)); + + Callback<R(A1, A2, A3, A4, A5, A6, A7, A8)> Get() { + return Bind(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +template <typename R, typename A1, typename A2, typename A3, typename A4, + typename A5, typename A6, typename A7, typename A8> +class MockCallback<OnceCallback<R(A1, A2, A3, A4, A5, A6, A7, A8)>> { + public: + MockCallback() = default; + MOCK_METHOD8_T(Run, R(A1, A2, A3, A4, A5, A6, A7, A8)); + + OnceCallback<R(A1, A2, A3, A4, A5, A6, A7, A8)> Get() { + return BindOnce(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +template <typename R, typename A1, typename A2, typename A3, typename A4, + typename A5, typename A6, typename A7, typename A8, typename A9> +class MockCallback<Callback<R(A1, A2, A3, A4, A5, A6, A7, A8, A9)>> { + public: + MockCallback() = default; + MOCK_METHOD9_T(Run, R(A1, A2, A3, A4, A5, A6, A7, A8, A9)); + + Callback<R(A1, A2, A3, A4, A5, A6, A7, A8, A9)> Get() { + return Bind(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +template <typename R, typename A1, typename A2, typename A3, typename A4, + typename A5, typename A6, typename A7, typename A8, typename A9> +class MockCallback<OnceCallback<R(A1, A2, A3, A4, A5, A6, A7, A8, A9)>> { + public: + MockCallback() = default; + MOCK_METHOD9_T(Run, R(A1, A2, A3, A4, A5, A6, A7, A8, A9)); + + OnceCallback<R(A1, A2, A3, A4, A5, A6, A7, A8, A9)> Get() { + return BindOnce(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +template <typename R, typename A1, typename A2, typename A3, typename A4, + typename A5, typename A6, typename A7, typename A8, typename A9, + typename A10> +class MockCallback<Callback<R(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)>> { + public: + MockCallback() = default; + MOCK_METHOD10_T(Run, R(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)); + + Callback<R(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)> Get() { + return Bind(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +template <typename R, typename A1, typename A2, typename A3, typename A4, + typename A5, typename A6, typename A7, typename A8, typename A9, + typename A10> +class MockCallback<OnceCallback<R(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)>> { + public: + MockCallback() = default; + MOCK_METHOD10_T(Run, R(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)); + + OnceCallback<R(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)> Get() { + return BindOnce(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +// clang-format on + +} // namespace base + +#endif // BASE_TEST_MOCK_CALLBACK_H_
diff --git a/base/test/mock_callback.h.pump b/base/test/mock_callback.h.pump new file mode 100644 index 0000000..3372789 --- /dev/null +++ b/base/test/mock_callback.h.pump
@@ -0,0 +1,85 @@ +$$ This is a pump file for generating file templates. Pump is a python +$$ script that is part of the Google Test suite of utilities. Description +$$ can be found here: +$$ +$$ https://github.com/google/googletest/blob/master/googletest/docs/PumpManual.md +$$ +$$ MAX_ARITY controls the number of arguments that MockCallback supports. +$$ It is choosen to match the number GMock supports. +$var MAX_ARITY = 10 +$$ +// Copyright 2017 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. + +// Analogous to GMock's built-in MockFunction, but for base::Callback instead of +// std::function. It takes the full callback type as a parameter, so that it can +// support both OnceCallback and RepeatingCallback. +// +// Use: +// using FooCallback = base::Callback<int(std::string)>; +// +// TEST(FooTest, RunsCallbackWithBarArgument) { +// base::MockCallback<FooCallback> callback; +// EXPECT_CALL(callback, Run("bar")).WillOnce(Return(1)); +// Foo(callback.Get()); +// } +// +// Can be used with StrictMock and NiceMock. Caller must ensure that it outlives +// any base::Callback obtained from it. + +#ifndef BASE_TEST_MOCK_CALLBACK_H_ +#define BASE_TEST_MOCK_CALLBACK_H_ + +#include "base/bind.h" +#include "base/callback.h" +#include "base/macros.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace base { + +// clang-format off + +template <typename F> +class MockCallback; + +$range i 0..MAX_ARITY +$for i [[ +$range j 1..i +$var run_type = [[R($for j, [[A$j]])]] + +template <typename R$for j [[, typename A$j]]> +class MockCallback<Callback<$run_type>> { + public: + MockCallback() = default; + MOCK_METHOD$(i)_T(Run, $run_type); + + Callback<$run_type> Get() { + return Bind(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +template <typename R$for j [[, typename A$j]]> +class MockCallback<OnceCallback<$run_type>> { + public: + MockCallback() = default; + MOCK_METHOD$(i)_T(Run, $run_type); + + OnceCallback<$run_type> Get() { + return BindOnce(&MockCallback::Run, Unretained(this)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockCallback); +}; + +]] + +// clang-format on + +} // namespace base + +#endif // BASE_TEST_MOCK_CALLBACK_H_
diff --git a/base/test/mock_callback_unittest.cc b/base/test/mock_callback_unittest.cc new file mode 100644 index 0000000..c5f109f --- /dev/null +++ b/base/test/mock_callback_unittest.cc
@@ -0,0 +1,59 @@ +// Copyright 2017 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/test/mock_callback.h" + +#include "base/callback.h" +#include "testing/gmock/include/gmock/gmock.h" + +using testing::InSequence; +using testing::Return; + +namespace base { +namespace { + +TEST(MockCallbackTest, ZeroArgs) { + MockCallback<Closure> mock_closure; + EXPECT_CALL(mock_closure, Run()); + mock_closure.Get().Run(); + + MockCallback<Callback<int()>> mock_int_callback; + { + InSequence sequence; + EXPECT_CALL(mock_int_callback, Run()).WillOnce(Return(42)); + EXPECT_CALL(mock_int_callback, Run()).WillOnce(Return(88)); + } + EXPECT_EQ(42, mock_int_callback.Get().Run()); + EXPECT_EQ(88, mock_int_callback.Get().Run()); +} + +TEST(MockCallbackTest, WithArgs) { + MockCallback<Callback<int(int, int)>> mock_two_int_callback; + EXPECT_CALL(mock_two_int_callback, Run(1, 2)).WillOnce(Return(42)); + EXPECT_CALL(mock_two_int_callback, Run(0, 0)).WillRepeatedly(Return(-1)); + Callback<int(int, int)> two_int_callback = mock_two_int_callback.Get(); + EXPECT_EQ(-1, two_int_callback.Run(0, 0)); + EXPECT_EQ(42, two_int_callback.Run(1, 2)); + EXPECT_EQ(-1, two_int_callback.Run(0, 0)); +} + +TEST(MockCallbackTest, ZeroArgsOnce) { + MockCallback<OnceClosure> mock_closure; + EXPECT_CALL(mock_closure, Run()); + mock_closure.Get().Run(); + + MockCallback<OnceCallback<int()>> mock_int_callback; + EXPECT_CALL(mock_int_callback, Run()).WillOnce(Return(88)); + EXPECT_EQ(88, mock_int_callback.Get().Run()); +} + +TEST(MockCallbackTest, WithArgsOnce) { + MockCallback<OnceCallback<int(int, int)>> mock_two_int_callback; + EXPECT_CALL(mock_two_int_callback, Run(1, 2)).WillOnce(Return(42)); + OnceCallback<int(int, int)> two_int_callback = mock_two_int_callback.Get(); + EXPECT_EQ(42, std::move(two_int_callback).Run(1, 2)); +} + +} // namespace +} // namespace base
diff --git a/build/android/gyp/util/proguard_util.py b/build/android/gyp/util/proguard_util.py index 547a7646..1977833 100644 --- a/build/android/gyp/util/proguard_util.py +++ b/build/android/gyp/util/proguard_util.py
@@ -151,6 +151,19 @@ inputs += [self._tested_apk_info_path] return inputs + def _WriteFlagsFile(self, out): + # Quite useful for auditing proguard flags. + for config in self._configs: + out.write('#' * 80 + '\n') + out.write(config + '\n') + out.write('#' * 80 + '\n') + with open(config) as config_file: + out.write(config_file.read().rstrip()) + out.write('\n\n') + out.write('#' * 80 + '\n') + out.write('Command-line\n') + out.write('#' * 80 + '\n') + out.write(' '.join(self._cmd) + '\n') def CheckOutput(self): self.build() @@ -160,6 +173,10 @@ open(self._outjar + '.seeds', 'w').close() open(self._outjar + '.usage', 'w').close() open(self._outjar + '.mapping', 'w').close() + + with open(self._outjar + '.flags', 'w') as out: + self._WriteFlagsFile(out) + # Warning: and Error: are sent to stderr, but messages and Note: are sent # to stdout. stdout_filter = None
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni index 3c0541f..a662457 100644 --- a/build/config/android/internal_rules.gni +++ b/build/config/android/internal_rules.gni
@@ -767,8 +767,9 @@ depfile = "${target_gen_dir}/${target_name}.d" outputs = [ _output_jar_path, - "$_output_jar_path.seeds", + "$_output_jar_path.flags", "$_output_jar_path.mapping", + "$_output_jar_path.seeds", "$_output_jar_path.usage", ] args = [
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc index 1b8799b..35ecffb 100644 --- a/cc/output/gl_renderer.cc +++ b/cc/output/gl_renderer.cc
@@ -2141,7 +2141,11 @@ int resource_multiplier_location = -1; int resource_offset_location = -1; const Program* program = GetProgram(ProgramKey::YUVVideo( - tex_coord_precision, sampler, use_alpha_plane, use_nv12, use_color_lut)); + tex_coord_precision, sampler, + use_alpha_plane ? YUV_HAS_ALPHA_TEXTURE : YUV_NO_ALPHA_TEXTURE, + use_nv12 ? UV_TEXTURE_MODE_UV : UV_TEXTURE_MODE_U_V, + use_color_lut ? COLOR_CONVERSION_MODE_2D_LUT_AS_3D_FROM_YUV + : COLOR_CONVERSION_MODE_NONE)); DCHECK(program && (program->initialized() || IsContextLost())); SetUseProgram(program->program()); matrix_location = program->matrix_location();
diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc index 20a5e36..dc5a6aaa 100644 --- a/cc/output/gl_renderer_unittest.cc +++ b/cc/output/gl_renderer_unittest.cc
@@ -186,11 +186,17 @@ ProgramKey::Tile(precision, sampler, NO_AA, DO_SWIZZLE, true))); // Iterate over alpha plane, nv12, and color_lut parameters. + UVTextureMode uv_modes[2] = {UV_TEXTURE_MODE_UV, UV_TEXTURE_MODE_U_V}; + YUVAlphaTextureMode a_modes[2] = {YUV_NO_ALPHA_TEXTURE, + YUV_HAS_ALPHA_TEXTURE}; + ColorConversionMode c_modes[2] = { + COLOR_CONVERSION_MODE_NONE, + COLOR_CONVERSION_MODE_2D_LUT_AS_3D_FROM_YUV}; for (int j = 0; j < 2; j++) { for (int k = 0; k < 2; k++) { for (int l = 0; l < 2; l++) { - const Program* program = renderer()->GetProgram( - ProgramKey::YUVVideo(precision, sampler, j, k, l)); + const Program* program = renderer()->GetProgram(ProgramKey::YUVVideo( + precision, sampler, a_modes[j], uv_modes[k], c_modes[l])); EXPECT_PROGRAM_VALID(program); } }
diff --git a/cc/output/program_binding.cc b/cc/output/program_binding.cc index 70ed5709..d80ef68 100644 --- a/cc/output/program_binding.cc +++ b/cc/output/program_binding.cc
@@ -27,8 +27,9 @@ mask_mode_ == other.mask_mode_ && mask_for_background_ == other.mask_for_background_ && has_color_matrix_ == other.has_color_matrix_ && - use_alpha_texture_ == other.use_alpha_texture_ && - use_nv12_ == other.use_nv12_ && use_color_lut_ == other.use_color_lut_; + yuv_alpha_texture_mode_ == other.yuv_alpha_texture_mode_ && + uv_texture_mode_ == other.uv_texture_mode_ && + color_conversion_mode_ == other.color_conversion_mode_; } // static @@ -108,16 +109,20 @@ // static ProgramKey ProgramKey::YUVVideo(TexCoordPrecision precision, SamplerType sampler, - bool use_alpha_texture, - bool use_nv12, - bool use_color_lut) { + YUVAlphaTextureMode yuv_alpha_texture_mode, + UVTextureMode uv_texture_mode, + ColorConversionMode color_conversion_mode) { ProgramKey result; result.type_ = PROGRAM_TYPE_YUV_VIDEO; result.precision_ = precision; result.sampler_ = sampler; - result.use_alpha_texture_ = use_alpha_texture; - result.use_nv12_ = use_nv12; - result.use_color_lut_ = use_color_lut; + result.yuv_alpha_texture_mode_ = yuv_alpha_texture_mode; + DCHECK(yuv_alpha_texture_mode == YUV_NO_ALPHA_TEXTURE || + yuv_alpha_texture_mode == YUV_HAS_ALPHA_TEXTURE); + result.uv_texture_mode_ = uv_texture_mode; + DCHECK(uv_texture_mode == UV_TEXTURE_MODE_UV || + uv_texture_mode == UV_TEXTURE_MODE_U_V); + result.color_conversion_mode_ = color_conversion_mode; return result; }
diff --git a/cc/output/program_binding.h b/cc/output/program_binding.h index a95587f..e8cfe681 100644 --- a/cc/output/program_binding.h +++ b/cc/output/program_binding.h
@@ -92,9 +92,9 @@ static ProgramKey VideoStream(TexCoordPrecision precision); static ProgramKey YUVVideo(TexCoordPrecision precision, SamplerType sampler, - bool use_alpha_texture, - bool use_nv12, - bool use_color_lut); + YUVAlphaTextureMode yuv_alpha_texture_mode, + UVTextureMode uv_texture_mode, + ColorConversionMode color_conversion_mode); bool operator==(const ProgramKey& other) const; @@ -118,9 +118,10 @@ bool mask_for_background_ = false; bool has_color_matrix_ = false; - bool use_alpha_texture_ = false; - bool use_nv12_ = false; - bool use_color_lut_ = false; + YUVAlphaTextureMode yuv_alpha_texture_mode_ = YUV_NO_ALPHA_TEXTURE; + UVTextureMode uv_texture_mode_ = UV_TEXTURE_MODE_NA; + + ColorConversionMode color_conversion_mode_ = COLOR_CONVERSION_MODE_NONE; }; struct ProgramKeyHash { @@ -137,9 +138,9 @@ (static_cast<size_t>(key.mask_mode_) << 21) ^ (static_cast<size_t>(key.mask_for_background_) << 22) ^ (static_cast<size_t>(key.has_color_matrix_) << 23) ^ - (static_cast<size_t>(key.use_alpha_texture_) << 24) ^ - (static_cast<size_t>(key.use_nv12_) << 25) ^ - (static_cast<size_t>(key.use_color_lut_) << 26); + (static_cast<size_t>(key.yuv_alpha_texture_mode_) << 24) ^ + (static_cast<size_t>(key.uv_texture_mode_) << 25) ^ + (static_cast<size_t>(key.color_conversion_mode_) << 26); } }; @@ -384,9 +385,10 @@ vertex_shader_.is_ya_uv_ = true; fragment_shader_.input_color_type_ = INPUT_COLOR_SOURCE_YUV_TEXTURES; - fragment_shader_.use_alpha_texture_ = key.use_alpha_texture_; - fragment_shader_.use_nv12_ = key.use_nv12_; - fragment_shader_.use_color_lut_ = key.use_color_lut_; + fragment_shader_.has_uniform_alpha_ = true; + fragment_shader_.yuv_alpha_texture_mode_ = key.yuv_alpha_texture_mode_; + fragment_shader_.uv_texture_mode_ = key.uv_texture_mode_; + fragment_shader_.color_conversion_mode_ = key.color_conversion_mode_; } void InitializeInternal(ContextProvider* context_provider) {
diff --git a/cc/output/shader.cc b/cc/output/shader.cc index c86344c..ccc5cce 100644 --- a/cc/output/shader.cc +++ b/cc/output/shader.cc
@@ -387,7 +387,7 @@ std::string FragmentShader::GetShaderString() const { // TODO(ccameron): Merge YUV shaders into the main shader generator. std::string source; - if (input_color_type_ == INPUT_COLOR_SOURCE_YUV_TEXTURES) + if (color_conversion_mode_ == COLOR_CONVERSION_MODE_2D_LUT_AS_3D_FROM_YUV) source = GetShaderStringYUVVideo(); else source = GetShaderSource(); @@ -405,7 +405,7 @@ unsigned program, int* base_uniform_index) { // TODO(ccameron): Merge YUV shaders into the main shader generator. - if (input_color_type_ == INPUT_COLOR_SOURCE_YUV_TEXTURES) { + if (color_conversion_mode_ == COLOR_CONVERSION_MODE_2D_LUT_AS_3D_FROM_YUV) { InitYUVVideo(context, program, base_uniform_index); return; } @@ -437,7 +437,19 @@ uniforms.push_back("fragmentTexTransform"); break; case INPUT_COLOR_SOURCE_YUV_TEXTURES: - NOTREACHED(); + uniforms.push_back("y_texture"); + if (uv_texture_mode_ == UV_TEXTURE_MODE_UV) + uniforms.push_back("uv_texture"); + if (uv_texture_mode_ == UV_TEXTURE_MODE_U_V) { + uniforms.push_back("u_texture"); + uniforms.push_back("v_texture"); + } + if (yuv_alpha_texture_mode_ == YUV_HAS_ALPHA_TEXTURE) + uniforms.push_back("a_texture"); + uniforms.push_back("ya_clamp_rect"); + uniforms.push_back("uv_clamp_rect"); + uniforms.push_back("yuv_matrix"); + uniforms.push_back("yuv_adj"); break; case INPUT_COLOR_SOURCE_UNIFORM: uniforms.push_back("color"); @@ -475,7 +487,19 @@ fragment_tex_transform_location_ = locations[index++]; break; case INPUT_COLOR_SOURCE_YUV_TEXTURES: - NOTREACHED(); + y_texture_location_ = locations[index++]; + if (uv_texture_mode_ == UV_TEXTURE_MODE_UV) + uv_texture_location_ = locations[index++]; + if (uv_texture_mode_ == UV_TEXTURE_MODE_U_V) { + u_texture_location_ = locations[index++]; + v_texture_location_ = locations[index++]; + } + if (yuv_alpha_texture_mode_ == YUV_HAS_ALPHA_TEXTURE) + a_texture_location_ = locations[index++]; + ya_clamp_rect_location_ = locations[index++]; + uv_clamp_rect_location_ = locations[index++]; + yuv_matrix_location_ = locations[index++]; + yuv_adj_location_ = locations[index++]; break; case INPUT_COLOR_SOURCE_UNIFORM: color_location_ = locations[index++]; @@ -808,7 +832,32 @@ } break; case INPUT_COLOR_SOURCE_YUV_TEXTURES: - NOTREACHED(); + HDR("uniform SamplerType y_texture;"); + SRC("vec2 ya_clamped ="); + SRC(" max(ya_clamp_rect.xy, min(ya_clamp_rect.zw, v_yaTexCoord));"); + SRC("vec2 uv_clamped ="); + SRC(" max(uv_clamp_rect.xy, min(uv_clamp_rect.zw, v_uvTexCoord));"); + SRC("vec3 yuv;"); + SRC("yuv.x = TextureLookup(y_texture, ya_clamped).x;"); + if (uv_texture_mode_ == UV_TEXTURE_MODE_UV) { + HDR("uniform SamplerType uv_texture;"); + SRC("yuv.yz = TextureLookup(uv_texture, uv_clamped).xy;"); + } + if (uv_texture_mode_ == UV_TEXTURE_MODE_U_V) { + HDR("uniform SamplerType u_texture;"); + HDR("uniform SamplerType v_texture;"); + SRC("yuv.y = TextureLookup(u_texture, uv_clamped).x;"); + SRC("yuv.z = TextureLookup(v_texture, uv_clamped).x;"); + } + if (yuv_alpha_texture_mode_ == YUV_HAS_ALPHA_TEXTURE) + HDR("uniform SamplerType a_texture;"); + HDR("uniform vec4 ya_clamp_rect;"); + HDR("uniform vec4 uv_clamp_rect;"); + HDR("uniform mat3 yuv_matrix;"); + HDR("uniform vec3 yuv_adj;"); + HDR("varying TexCoordPrecision vec2 v_yaTexCoord;"); + HDR("varying TexCoordPrecision vec2 v_uvTexCoord;"); + SRC("vec4 texColor = vec4(yuv_matrix * (yuv + yuv_adj), 1.0);"); break; case INPUT_COLOR_SOURCE_UNIFORM: DCHECK(!ignore_sampler_type_); @@ -891,6 +940,8 @@ line += " * aa"; if (mask_mode_ != NO_MASK) line += " * maskColor.a"; + if (yuv_alpha_texture_mode_ == YUV_HAS_ALPHA_TEXTURE) + line += " * TextureLookup(a_texture, ya_clamped).x"; line += ";\n"; source += line; } @@ -945,20 +996,22 @@ locations, base_uniform_index); y_texture_location_ = locations[0]; - if (!use_nv12_) { + if (uv_texture_mode_ == UV_TEXTURE_MODE_U_V) { u_texture_location_ = locations[1]; v_texture_location_ = locations[2]; - } else { + } + if (uv_texture_mode_ == UV_TEXTURE_MODE_UV) { uv_texture_location_ = locations[3]; } - if (use_alpha_texture_) { + if (yuv_alpha_texture_mode_ == YUV_HAS_ALPHA_TEXTURE) { a_texture_location_ = locations[4]; } - if (use_color_lut_) { + if (color_conversion_mode_ == COLOR_CONVERSION_MODE_2D_LUT_AS_3D_FROM_YUV) { lut_texture_location_ = locations[5]; resource_multiplier_location_ = locations[6]; resource_offset_location_ = locations[7]; - } else { + } + if (color_conversion_mode_ == COLOR_CONVERSION_MODE_NONE) { yuv_matrix_location_ = locations[8]; yuv_adj_location_ = locations[9]; } @@ -980,14 +1033,15 @@ }); std::string functions = ""; - if (use_nv12_) { + if (uv_texture_mode_ == UV_TEXTURE_MODE_UV) { head += " uniform SamplerType uv_texture;\n"; functions += SHADER0([]() { vec2 GetUV(vec2 uv_clamped) { return TextureLookup(uv_texture, uv_clamped).xy; } }); - } else { + } + if (uv_texture_mode_ == UV_TEXTURE_MODE_U_V) { head += " uniform SamplerType u_texture;\n"; head += " uniform SamplerType v_texture;\n"; functions += SHADER0([]() { @@ -998,7 +1052,7 @@ }); } - if (use_alpha_texture_) { + if (yuv_alpha_texture_mode_ == YUV_HAS_ALPHA_TEXTURE) { head += " uniform SamplerType a_texture;\n"; functions += SHADER0([]() { float GetAlpha(vec2 ya_clamped) { @@ -1011,7 +1065,7 @@ }); } - if (use_color_lut_) { + if (color_conversion_mode_ == COLOR_CONVERSION_MODE_2D_LUT_AS_3D_FROM_YUV) { head += " uniform sampler2D lut_texture;\n"; head += " uniform float resource_multiplier;\n"; head += " uniform float resource_offset;\n"; @@ -1034,7 +1088,8 @@ return LUT(lut_texture, yuv, 17.0).xyz; } }); - } else { + } + if (color_conversion_mode_ == COLOR_CONVERSION_MODE_NONE) { head += " uniform mat3 yuv_matrix;\n"; head += " uniform vec3 yuv_adj;\n"; functions += SHADER0([]() {
diff --git a/cc/output/shader.h b/cc/output/shader.h index 6550f901..e69d4f4d 100644 --- a/cc/output/shader.h +++ b/cc/output/shader.h
@@ -114,6 +114,29 @@ INPUT_COLOR_SOURCE_UNIFORM, }; +enum UVTextureMode { + // Shader does not use YUV textures. + UV_TEXTURE_MODE_NA, + // UV plane is a single texture. + UV_TEXTURE_MODE_UV, + // U and V planes have separate textures. + UV_TEXTURE_MODE_U_V, +}; + +enum YUVAlphaTextureMode { + YUV_ALPHA_TEXTURE_MODE_NA, + YUV_NO_ALPHA_TEXTURE, + YUV_HAS_ALPHA_TEXTURE, +}; + +enum ColorConversionMode { + // No color conversion is performed. + COLOR_CONVERSION_MODE_NONE, + // Conversion is done directly from YUV to output RGB space, via a 3D texture + // represented as a 2D texture. + COLOR_CONVERSION_MODE_2D_LUT_AS_3D_FROM_YUV, +}; + // TODO(ccameron): Merge this with BlendMode. enum FragColorMode { FRAG_COLOR_MODE_DEFAULT, @@ -256,9 +279,10 @@ bool mask_for_background_ = false; // YUV-only parameters. - bool use_alpha_texture_ = false; - bool use_nv12_ = false; - bool use_color_lut_ = false; + YUVAlphaTextureMode yuv_alpha_texture_mode_ = YUV_ALPHA_TEXTURE_MODE_NA; + UVTextureMode uv_texture_mode_ = UV_TEXTURE_MODE_UV; + + ColorConversionMode color_conversion_mode_ = COLOR_CONVERSION_MODE_NONE; // YUV uniform locations. int y_texture_location_ = -1;
diff --git a/chrome/android/java/res/layout/search_engine_recent_title.xml b/chrome/android/java/res/layout/search_engine_recent_title.xml index 9bd4c4d..9b5c64b 100644 --- a/chrome/android/java/res/layout/search_engine_recent_title.xml +++ b/chrome/android/java/res/layout/search_engine_recent_title.xml
@@ -7,7 +7,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/search_engine_recently_visited" - android:textColor="@color/light_active_color" + android:textColor="@color/google_blue_700" style="@style/RobotoMediumStyle" android:gravity="center_vertical" android:paddingBottom="16dp"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEngineAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEngineAdapter.java index 4370b0c..32572c75 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEngineAdapter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEngineAdapter.java
@@ -268,7 +268,7 @@ link.setVisibility(View.GONE); } else { ForegroundColorSpan linkSpan = new ForegroundColorSpan( - ApiCompatibilityUtils.getColor(resources, R.color.pref_accent_color)); + ApiCompatibilityUtils.getColor(resources, R.color.google_blue_700)); if (LocationUtils.getInstance().isSystemLocationSettingEnabled()) { String message = mContext.getString( locationEnabled(position, true)
diff --git a/chrome/app/settings_chromium_strings.grdp b/chrome/app/settings_chromium_strings.grdp index 43b388d1..69dd33d6 100644 --- a/chrome/app/settings_chromium_strings.grdp +++ b/chrome/app/settings_chromium_strings.grdp
@@ -39,7 +39,7 @@ <!-- Default Browser Page --> <if expr="not chromeos"> <message name="IDS_SETTINGS_DEFAULT_BROWSER_DEFAULT" desc="The text displayed when Chrome is the default browser"> - Chromium is your default browser. Cheers. + Chromium is your default browser. Cheers! </message> <message name="IDS_SETTINGS_DEFAULT_BROWSER_MAKE_DEFAULT" desc="Default browser checkbox label"> Make Chromium the default browser
diff --git a/chrome/app/settings_google_chrome_strings.grdp b/chrome/app/settings_google_chrome_strings.grdp index bae71b7..5cf2399 100644 --- a/chrome/app/settings_google_chrome_strings.grdp +++ b/chrome/app/settings_google_chrome_strings.grdp
@@ -39,7 +39,7 @@ <!-- Default Browser Page --> <if expr="not chromeos"> <message name="IDS_SETTINGS_DEFAULT_BROWSER_DEFAULT" desc="The text displayed when Chrome is not the default browser"> - Google Chrome is your default browser. Cheers. + Google Chrome is your default browser. Cheers! </message> <message name="IDS_SETTINGS_DEFAULT_BROWSER_MAKE_DEFAULT" desc="Default browser checkbox label"> Make Google Chrome the default browser
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index d2fde5a..2ed9ea5 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -248,7 +248,7 @@ Show home button </message> <message name="IDS_SETTINGS_SHOW_BOOKMARKS_BAR" desc="Label for the checkbox which enables or disables showing the bookmarks bar in the toolbar."> - Always show the bookmarks bar + Show bookmarks bar </message> <message name="IDS_SETTINGS_HOME_PAGE_NTP" desc="Description of the New Tab Page when set as the home page."> Use the New Tab Page @@ -954,7 +954,7 @@ Google Cloud Print </message> <message name="IDS_SETTINGS_PRINTING_CLOUD_PRINTERS_DESCRIPTION" desc="In Printing Settings, the title description of the google cloud printers setting section."> - Setup cloud printing devices + Set up cloud printing devices </message> <!-- Downloads Page --> @@ -1582,13 +1582,13 @@ Keep Wi-Fi on during sleep </message> <message name="IDS_SETTINGS_MANAGE_CERTIFICATES" desc="Text for manage certificates button in Privacy options"> - Manage Certificates + Manage certificates </message> <message name="IDS_SETTINGS_MANAGE_CERTIFICATES_DESCRIPTION" desc="Secondary, continued explanation of how to manage SSL certificates and settings in Privacy options"> Manage HTTPS/SSL certificates and settings </message> <message name="IDS_SETTINGS_CONTENT_SETTINGS" desc="Text of the button that takes a user to settings page thats allows users to modify site settings. Also the title of that settings page."> - Content Settings + Content settings </message> <message name="IDS_SETTINGS_SITE_SETTINGS" desc="Text of the button that takes a user to the enhanced settings page thats allows users to modify site settings. Also the title of that settings page."> Site Settings @@ -1939,10 +1939,10 @@ Search cookies </message> <message name="IDS_SETTINGS_SITE_SETTINGS_THIRD_PARTY_COOKIE" desc="Label for the Block 3rd-party cookie checkbox on the Cookies category."> - Block third-party cookies. + Block third-party cookies </message> <message name="IDS_SETTINGS_SITE_SETTINGS_THIRD_PARTY_COOKIE_SUBLABEL" desc="A sub-label below the Block 3rd-party cookie checkbox."> - Prevent third-party websites from saving and reading cookie data. + Prevent third-party websites from saving and reading cookie data </message> <message name="IDS_SETTINGS_SITE_SETTINGS_DELETE_DATA_POST_SESSION" desc="Label for the checkbox that allows the user to automatically delete their data at the end of the browser session."> Keep local data only until you quit your browser @@ -2222,7 +2222,7 @@ </if> <message name="IDS_SETTINGS_SYNC_OVERVIEW" desc="The message that appears in the options dialog when sync has not been set up by the user."> - Sign in to get your bookmarks, history, passwords and other settings on all your devices. You'll also automatically be signed in to your Google services. + Sign in to get your bookmarks, history, passwords, and other settings on all your devices. You'll also automatically be signed in to your Google services. </message> <message name="IDS_SETTINGS_SYNC_DISCONNECT" desc="The text to display on the button to indicate stop syncing functionality."> Sign Out
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 4f43954..9659be9 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -772,8 +772,6 @@ "login/screens/error_screen.cc", "login/screens/error_screen.h", "login/screens/error_screen_actor_delegate.h", - "login/screens/eula_model.cc", - "login/screens/eula_model.h", "login/screens/eula_screen.cc", "login/screens/eula_screen.h", "login/screens/eula_view.h",
diff --git a/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_controller.cc b/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_controller.cc index 2f56fa51..dd980bdc 100644 --- a/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_controller.cc +++ b/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_controller.cc
@@ -125,6 +125,10 @@ if (target_screen_calibration_view->GetDisplayPointLocation(&display_point)) { touch_point_quad_[state_index] = std::make_pair(display_point, touch->location()); + } else { + // TODO(malaykeshav): Display some kind of error for the user. + NOTREACHED() << "Touch calibration failed. Could not retrieve location for" + " display point. Retry calibration."; } // If this is the final state, then store all calibration data and stop
diff --git a/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_controller_unittest.cc b/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_controller_unittest.cc index 4ac1ea6..080e208 100644 --- a/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_controller_unittest.cc +++ b/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_controller_unittest.cc
@@ -56,7 +56,7 @@ ctrl->touch_calibrator_views_[target_display.id()].get(); // End the background fade in animation. - target_calibrator_view->SkipCurrentAnimationForTest(); + target_calibrator_view->SkipCurrentAnimation(); // TouchCalibratorView on the display being calibrated should be at the // state where the first display point is visible.
diff --git a/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_view.cc b/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_view.cc index 123aefa..5924a25c 100644 --- a/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_view.cc +++ b/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_view.cc
@@ -9,10 +9,12 @@ #include "ash/shell.h" #include "ui/aura/window.h" #include "ui/base/resource/resource_bundle.h" +#include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/gfx/animation/linear_animation.h" #include "ui/gfx/animation/throb_animation.h" #include "ui/gfx/canvas.h" #include "ui/strings/grit/ui_strings.h" +#include "ui/views/background.h" #include "ui/views/controls/label.h" #include "ui/views/widget/widget.h" @@ -24,23 +26,28 @@ constexpr int kAnimationFrameRate = 100; constexpr int kFadeDurationInMs = 150; +constexpr int kPointMoveDurationInMs = 600; +constexpr int kPointMoveDurationLongInMs = 700; const SkColor kExitLabelColor = SkColorSetARGBInline(255, 96, 96, 96); const SkColor kExitLabelShadowColor = SkColorSetARGBInline(255, 11, 11, 11); constexpr int kExitLabelWidth = 300; constexpr int kExitLabelHeight = 20; +const SkColor kTapHereLabelColor = SK_ColorWHITE; + constexpr int kHintBoxWidth = 298; constexpr int kHintBoxHeight = 180; constexpr int kHintBoxLabelTextSize = 5; constexpr int kHintBoxSublabelTextSize = 3; -constexpr int kThrobberCircleViewWidth = 128; +constexpr int kThrobberCircleViewWidth = 64; constexpr float kThrobberCircleRadiusFactor = 3.f / 8.f; constexpr int kTouchPointViewOffset = 100; constexpr int kTapLabelHeight = 48; +constexpr int kTapLabelWidth = 80; const SkColor kHintLabelTextColor = SK_ColorBLACK; const SkColor kHintSublabelTextColor = SkColorSetARGBInline(255, 161, 161, 161); @@ -50,7 +57,7 @@ constexpr int kCircleAnimationDurationMs = 900; -constexpr int kHintRectBorderRadius = 8; +constexpr int kHintRectBorderRadius = 4; constexpr float kBackgroundFinalOpacity = 0.75f; @@ -78,6 +85,17 @@ return gfx::Size(width, height); } +void AnimateLayerToPosition(views::View* view, + int duration, + gfx::Point end_position) { + ui::ScopedLayerAnimationSettings slide_settings(view->layer()->GetAnimator()); + slide_settings.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + slide_settings.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(duration)); + view->SetBoundsRect(gfx::Rect(end_position, view->size())); +} + } // namespace // Creates a throbbing animated view with two concentric circles. The radius of @@ -291,6 +309,7 @@ : display_(target_display), is_primary_view_(is_primary_view), exit_label_(nullptr), + tap_label_(nullptr), throbber_circle_(nullptr), hint_box_view_(nullptr), touch_point_view_(nullptr) { @@ -349,18 +368,41 @@ // Initialize the touch point view that contains the animated circle that the // user needs to tap. const int kTouchPointViewHeight = kThrobberCircleViewWidth + kTapLabelHeight; + const int kThrobberCircleViewHorizontalOffset = + (kTapLabelWidth - kThrobberCircleViewWidth) / 2; throbber_circle_ = new CircularThrobberView(kThrobberCircleViewWidth, kInnerCircleColor, kOuterCircleColor, kCircleAnimationDurationMs); - throbber_circle_->SetPosition(gfx::Point(0, 0)); + throbber_circle_->SetPosition( + gfx::Point(kThrobberCircleViewHorizontalOffset, 0)); + + // Initialize the tap label. + tap_label_ = new views::Label( + rb.GetLocalizedString(IDS_DISPLAY_TOUCH_CALIBRATION_TAP_HERE_LABEL), + rb.GetFontListWithDelta(6, gfx::Font::FontStyle::NORMAL, + gfx::Font::Weight::NORMAL)); + tap_label_->SetBounds(0, kThrobberCircleViewWidth, kTapLabelWidth, + kTapLabelHeight); + tap_label_->SetEnabledColor(kTapHereLabelColor); + tap_label_->SetDisabledColor(kTapHereLabelColor); + tap_label_->SetHorizontalAlignment(gfx::ALIGN_CENTER); + tap_label_->SetAutoColorReadabilityEnabled(false); + tap_label_->SetSubpixelRenderingEnabled(false); + tap_label_->SetVisible(false); touch_point_view_ = new views::View; touch_point_view_->SetBounds(kTouchPointViewOffset, kTouchPointViewOffset, - kThrobberCircleViewWidth, kTouchPointViewHeight); + kTapLabelWidth, kTouchPointViewHeight); touch_point_view_->SetVisible(false); + touch_point_view_->SetPaintToLayer(true); + touch_point_view_->layer()->SetFillsBoundsOpaquely(false); + touch_point_view_->layer()->GetAnimator()->AddObserver(this); + touch_point_view_->set_background( + views::Background::CreateSolidBackground(SK_ColorTRANSPARENT)); touch_point_view_->AddChildView(throbber_circle_); + touch_point_view_->AddChildView(tap_label_); AddChildView(touch_point_view_); @@ -411,7 +453,10 @@ } void TouchCalibratorView::AnimationProgressed(const gfx::Animation* animation) { - SchedulePaint(); + if (!is_primary_view_) { + SchedulePaint(); + return; + } } void TouchCalibratorView::AnimationCanceled(const gfx::Animation* animation) { @@ -433,9 +478,38 @@ } } +void TouchCalibratorView::OnLayerAnimationStarted( + ui::LayerAnimationSequence* sequence) {} + +void TouchCalibratorView::OnLayerAnimationEnded( + ui::LayerAnimationSequence* sequence) { + switch (state_) { + case ANIMATING_1_TO_2: + state_ = DISPLAY_POINT_2; + tap_label_->SetVisible(true); + break; + case ANIMATING_2_TO_3: + state_ = DISPLAY_POINT_3; + break; + case ANIMATING_3_TO_4: + state_ = DISPLAY_POINT_4; + break; + default: + break; + } +} + +void TouchCalibratorView::OnLayerAnimationAborted( + ui::LayerAnimationSequence* sequence) { + OnLayerAnimationEnded(sequence); +} + +void TouchCalibratorView::OnLayerAnimationScheduled( + ui::LayerAnimationSequence* sequence) {} + void TouchCalibratorView::AdvanceToNextState() { // Stop any previous animations and skip them to the end. - animator_->End(); + SkipCurrentAnimation(); switch (state_) { case UNKNOWN: @@ -445,26 +519,75 @@ end_opacity_value_ = kBackgroundFinalOpacity; paint_.setStyle(SkPaint::kFill_Style); - animator_->SetDuration(kFadeDurationInMs); - break; + animator_->Start(); + return; + case DISPLAY_POINT_1: + state_ = ANIMATING_1_TO_2; + + // The touch point has to be animated from the top left corner of the + // screen to the top right corner. + AnimateLayerToPosition( + touch_point_view_, kPointMoveDurationInMs, + gfx::Point(display_.bounds().width() - kTouchPointViewOffset - + touch_point_view_->width(), + touch_point_view_->y())); + hint_box_view_->SetVisible(false); + return; + case DISPLAY_POINT_2: + state_ = ANIMATING_2_TO_3; + + // The touch point has to be animated from the top right corner of the + // screen to the bottom left corner. + AnimateLayerToPosition( + touch_point_view_, kPointMoveDurationLongInMs, + gfx::Point(kTouchPointViewOffset, display_.bounds().height() - + kTouchPointViewOffset - + touch_point_view_->height())); + return; + case DISPLAY_POINT_3: + state_ = ANIMATING_3_TO_4; + + // The touch point has to be animated from the bottom left corner of the + // screen to the bottom right corner. + AnimateLayerToPosition( + touch_point_view_, kPointMoveDurationInMs, + gfx::Point(display_.bounds().width() - kTouchPointViewOffset - + touch_point_view_->width(), + touch_point_view_->y())); + return; default: - break; + return; } - animator_->Start(); } bool TouchCalibratorView::GetDisplayPointLocation(gfx::Point* location) { + DCHECK(location); if (!is_primary_view_) return false; - return false; + + if (state_ != DISPLAY_POINT_1 && state_ != DISPLAY_POINT_2 && + state_ != DISPLAY_POINT_3 && state_ != DISPLAY_POINT_4) { + return false; + } + + if (!touch_point_view_ || !throbber_circle_) + return false; + // TODO(malaykeshav): Can use views::ConvertPointToScreen() + location->SetPoint(touch_point_view_->x() + touch_point_view_->width() / 2.f, + touch_point_view_->y() + touch_point_view_->width() / 2.f); + return true; } void TouchCalibratorView::SkipToFinalState() {} -void TouchCalibratorView::SkipCurrentAnimationForTest() { +void TouchCalibratorView::SkipCurrentAnimation() { if (animator_->is_animating()) animator_->End(); + if (touch_point_view_ && + touch_point_view_->layer()->GetAnimator()->is_animating()) { + touch_point_view_->layer()->GetAnimator()->StopAnimating(); + } } } // namespace chromeos
diff --git a/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_view.h b/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_view.h index de46566..69719506 100644 --- a/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_view.h +++ b/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_view.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_CHROMEOS_DISPLAY_TOUCH_CALIBRATOR_TOUCH_CALIBRATOR_VIEW_H_ #include "base/macros.h" +#include "ui/compositor/layer_animation_observer.h" #include "ui/display/display.h" #include "ui/gfx/animation/animation_delegate.h" #include "ui/views/view.h" @@ -20,6 +21,10 @@ class LinearAnimation; } +namespace ui { +class LayerAnimationSequence; +} + namespace chromeos { class CircularThrobberView; @@ -30,7 +35,9 @@ // touch calibration view. // |TouchCalibratorView| acts as a state machine and has an API to toggle its // state or get the current state. -class TouchCalibratorView : public views::View, public gfx::AnimationDelegate { +class TouchCalibratorView : public views::View, + public gfx::AnimationDelegate, + public ui::LayerAnimationObserver { public: // Different states of |TouchCalibratorView| in order. enum State { @@ -68,6 +75,12 @@ void AnimationProgressed(const gfx::Animation* animation) override; void AnimationCanceled(const gfx::Animation* animation) override; + // ui::LayerAnimationObserver + void OnLayerAnimationStarted(ui::LayerAnimationSequence* sequence) override; + void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override; + void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override; + void OnLayerAnimationScheduled(ui::LayerAnimationSequence* sequence) override; + // Moves the touch calibrator view to its next state. void AdvanceToNextState(); @@ -81,7 +94,7 @@ bool GetDisplayPointLocation(gfx::Point* location); // Skips/cancels any ongoing animation to its end. - void SkipCurrentAnimationForTest(); + void SkipCurrentAnimation(); // Returns the current state of the view. State state() { return state_; } @@ -104,6 +117,8 @@ // Text label indicating how to exit the touch calibration. views::Label* exit_label_; + // Text label indicating the significance of the touch point on screen. + views::Label* tap_label_; // Start and end opacity values used during the fade animation. This is set // before the animation begins.
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc index 21f8af2..ebab6deb 100644 --- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc +++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
@@ -161,7 +161,7 @@ TargetVolume volume; // Entries to be added. - ScopedVector<TestEntryInfo> entries; + std::vector<std::unique_ptr<TestEntryInfo>> entries; // Registers the member information to the given converter. static void RegisterJSONConverter(
diff --git a/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc b/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc index b66802f..a037ab1 100644 --- a/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc +++ b/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
@@ -180,9 +180,9 @@ foo_app->set_application_id("foo_app_id"); foo_app->set_name("Foo"); foo_app->set_object_type("foo_object_type"); - ScopedVector<std::string> foo_mime_types; - foo_mime_types.push_back(new std::string("text/plain")); - foo_mime_types.push_back(new std::string("text/html")); + std::vector<std::unique_ptr<std::string>> foo_mime_types; + foo_mime_types.push_back(base::MakeUnique<std::string>("text/plain")); + foo_mime_types.push_back(base::MakeUnique<std::string>("text/html")); foo_app->set_primary_mimetypes(std::move(foo_mime_types)); // Bar.app can only handle "text/plain". @@ -192,14 +192,14 @@ bar_app->set_application_id("bar_app_id"); bar_app->set_name("Bar"); bar_app->set_object_type("bar_object_type"); - ScopedVector<std::string> bar_mime_types; - bar_mime_types.push_back(new std::string("text/plain")); + std::vector<std::unique_ptr<std::string>> bar_mime_types; + bar_mime_types.push_back(base::MakeUnique<std::string>("text/plain")); bar_app->set_primary_mimetypes(std::move(bar_mime_types)); // Prepare DriveAppRegistry from Foo.app and Bar.app. - ScopedVector<google_apis::AppResource> app_resources; - app_resources.push_back(foo_app.release()); - app_resources.push_back(bar_app.release()); + std::vector<std::unique_ptr<google_apis::AppResource>> app_resources; + app_resources.push_back(std::move(foo_app)); + app_resources.push_back(std::move(bar_app)); google_apis::AppList app_list; app_list.set_items(std::move(app_resources)); drive::DriveAppRegistry drive_app_registry(NULL); @@ -734,12 +734,12 @@ baz_app->set_application_id(kBazId); baz_app->set_name("Baz"); baz_app->set_object_type("baz_object_type"); - ScopedVector<std::string> baz_mime_types; - baz_mime_types.push_back(new std::string("text/plain")); + std::vector<std::unique_ptr<std::string>> baz_mime_types; + baz_mime_types.push_back(base::MakeUnique<std::string>("text/plain")); baz_app->set_primary_mimetypes(std::move(baz_mime_types)); // Set up DriveAppRegistry. - ScopedVector<google_apis::AppResource> app_resources; - app_resources.push_back(baz_app.release()); + std::vector<std::unique_ptr<google_apis::AppResource>> app_resources; + app_resources.push_back(std::move(baz_app)); google_apis::AppList app_list; app_list.set_items(std::move(app_resources)); drive::DriveAppRegistry drive_app_registry(NULL); @@ -783,13 +783,14 @@ foo_app->set_application_id(kFooId); foo_app->set_name("Foo"); foo_app->set_object_type("foo_object_type"); - ScopedVector<std::string> foo_extensions; - foo_extensions.push_back(new std::string("gdoc")); // Not ".gdoc" + std::vector<std::unique_ptr<std::string>> foo_extensions; + foo_extensions.push_back( + base::MakeUnique<std::string>("gdoc")); // Not ".gdoc" foo_app->set_primary_file_extensions(std::move(foo_extensions)); // Prepare DriveAppRegistry from Foo.app. - ScopedVector<google_apis::AppResource> app_resources; - app_resources.push_back(foo_app.release()); + std::vector<std::unique_ptr<google_apis::AppResource>> app_resources; + app_resources.push_back(std::move(foo_app)); google_apis::AppList app_list; app_list.set_items(std::move(app_resources)); drive::DriveAppRegistry drive_app_registry(NULL);
diff --git a/chrome/browser/chromeos/login/screens/eula_model.cc b/chrome/browser/chromeos/login/screens/eula_model.cc deleted file mode 100644 index 21b2884..0000000 --- a/chrome/browser/chromeos/login/screens/eula_model.cc +++ /dev/null
@@ -1,20 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/chromeos/login/screens/eula_model.h" - -#include "chrome/browser/chromeos/login/wizard_controller.h" - -namespace chromeos { - -const char EulaModel::kUserActionAcceptButtonClicked[] = "accept-button"; -const char EulaModel::kUserActionBackButtonClicked[] = "back-button"; -const char EulaModel::kContextKeyUsageStatsEnabled[] = "usageStatsEnabled"; - -EulaModel::EulaModel(BaseScreenDelegate* base_screen_delegate) - : BaseScreen(base_screen_delegate, OobeScreen::SCREEN_OOBE_EULA) {} - -EulaModel::~EulaModel() {} - -} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/eula_model.h b/chrome/browser/chromeos/login/screens/eula_model.h deleted file mode 100644 index fb1a45a..0000000 --- a/chrome/browser/chromeos/login/screens/eula_model.h +++ /dev/null
@@ -1,44 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_EULA_MODEL_H_ -#define CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_EULA_MODEL_H_ - -#include "chrome/browser/chromeos/login/screens/base_screen.h" -#include "url/gurl.h" - -namespace chromeos { - -class BaseScreenDelegate; -class EulaView; - -// Allows us to get info from eula screen that we need. -class EulaModel : public BaseScreen { - public: - static const char kUserActionAcceptButtonClicked[]; - static const char kUserActionBackButtonClicked[]; - static const char kContextKeyUsageStatsEnabled[]; - - explicit EulaModel(BaseScreenDelegate* base_screen_delegate); - ~EulaModel() override; - - // Returns URL of the OEM EULA page that should be displayed using current - // locale and manifest. Returns empty URL otherwise. - virtual GURL GetOemEulaUrl() const = 0; - - // Initiate TPM password fetch. Will call actor's OnPasswordFetched() when - // done. - virtual void InitiatePasswordFetch() = 0; - - // Returns true if usage statistics reporting is enabled. - virtual bool IsUsageStatsEnabled() const = 0; - - // This method is called, when view is being destroyed. Note, if model - // is destroyed earlier then it has to call SetModel(NULL). - virtual void OnViewDestroyed(EulaView* view) = 0; -}; - -} // namespace chromeos - -#endif // CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_EULA_MODEL_H_
diff --git a/chrome/browser/chromeos/login/screens/eula_screen.cc b/chrome/browser/chromeos/login/screens/eula_screen.cc index 3b2719fd..e17cc1e 100644 --- a/chrome/browser/chromeos/login/screens/eula_screen.cc +++ b/chrome/browser/chromeos/login/screens/eula_screen.cc
@@ -11,24 +11,32 @@ #include "chrome/browser/chromeos/customization/customization_document.h" #include "chrome/browser/chromeos/login/screens/base_screen_delegate.h" #include "chrome/browser/chromeos/login/screens/eula_view.h" +#include "chrome/browser/chromeos/login/wizard_controller.h" #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h" #include "chromeos/dbus/cryptohome_client.h" #include "chromeos/dbus/dbus_method_call_status.h" #include "chromeos/dbus/dbus_thread_manager.h" namespace chromeos { +namespace { + +constexpr const char kUserActionAcceptButtonClicked[] = "accept-button"; +constexpr const char kUserActionBackButtonClicked[] = "back-button"; +constexpr const char kContextKeyUsageStatsEnabled[] = "usageStatsEnabled"; + +} // namespace EulaScreen::EulaScreen(BaseScreenDelegate* base_screen_delegate, Delegate* delegate, EulaView* view) - : EulaModel(base_screen_delegate), + : BaseScreen(base_screen_delegate, OobeScreen::SCREEN_OOBE_EULA), delegate_(delegate), view_(view), password_fetcher_(this) { DCHECK(view_); DCHECK(delegate_); if (view_) - view_->Bind(*this); + view_->Bind(this); } EulaScreen::~EulaScreen() { @@ -36,22 +44,6 @@ view_->Unbind(); } -void EulaScreen::Show() { - // Command to own the TPM. - DBusThreadManager::Get()->GetCryptohomeClient()->TpmCanAttemptOwnership( - EmptyVoidDBusMethodCallback()); - if (policy::DeviceCloudPolicyManagerChromeOS::GetZeroTouchEnrollmentMode() == - policy::ZeroTouchEnrollmentMode::HANDS_OFF) - OnUserAction(EulaModel::kUserActionAcceptButtonClicked); - else if (view_) - view_->Show(); -} - -void EulaScreen::Hide() { - if (view_) - view_->Hide(); -} - GURL EulaScreen::GetOemEulaUrl() const { const StartupCustomizationDocument* customization = StartupCustomizationDocument::GetInstance(); @@ -79,12 +71,6 @@ } } -void EulaScreen::OnPasswordFetched(const std::string& tpm_password) { - tpm_password_ = tpm_password; - if (view_) - view_->OnPasswordFetched(tpm_password_); -} - bool EulaScreen::IsUsageStatsEnabled() const { return delegate_ && delegate_->GetUsageStatisticsReporting(); } @@ -94,6 +80,22 @@ view_ = NULL; } +void EulaScreen::Show() { + // Command to own the TPM. + DBusThreadManager::Get()->GetCryptohomeClient()->TpmCanAttemptOwnership( + EmptyVoidDBusMethodCallback()); + if (policy::DeviceCloudPolicyManagerChromeOS::GetZeroTouchEnrollmentMode() == + policy::ZeroTouchEnrollmentMode::HANDS_OFF) + OnUserAction(kUserActionAcceptButtonClicked); + else if (view_) + view_->Show(); +} + +void EulaScreen::Hide() { + if (view_) + view_->Hide(); +} + void EulaScreen::OnUserAction(const std::string& action_id) { if (action_id == kUserActionAcceptButtonClicked) Finish(BaseScreenDelegate::EULA_ACCEPTED); @@ -111,4 +113,10 @@ } } +void EulaScreen::OnPasswordFetched(const std::string& tpm_password) { + tpm_password_ = tpm_password; + if (view_) + view_->OnPasswordFetched(tpm_password_); +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/eula_screen.h b/chrome/browser/chromeos/login/screens/eula_screen.h index 83a0d4a..4c03ebc 100644 --- a/chrome/browser/chromeos/login/screens/eula_screen.h +++ b/chrome/browser/chromeos/login/screens/eula_screen.h
@@ -10,16 +10,18 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "chrome/browser/chromeos/login/screens/base_screen.h" -#include "chrome/browser/chromeos/login/screens/eula_model.h" #include "chromeos/tpm/tpm_password_fetcher.h" #include "components/login/screens/screen_context.h" #include "url/gurl.h" namespace chromeos { +class BaseScreenDelegate; +class EulaView; + // Representation independent class that controls OOBE screen showing EULA // to users. -class EulaScreen : public EulaModel, public TpmPasswordFetcherDelegate { +class EulaScreen : public BaseScreen, public TpmPasswordFetcherDelegate { public: class Delegate { public: @@ -35,20 +37,31 @@ EulaView* view); ~EulaScreen() override; - // EulaModel implementation: + // Returns URL of the OEM EULA page that should be displayed using current + // locale and manifest. Returns empty URL otherwise. + GURL GetOemEulaUrl() const; + + // Initiate TPM password fetch. Will call actor's OnPasswordFetched() when + // done. + void InitiatePasswordFetch(); + + // Returns true if usage statistics reporting is enabled. + bool IsUsageStatsEnabled() const; + + // This method is called, when view is being destroyed. Note, if model + // is destroyed earlier then it has to call SetModel(NULL). + void OnViewDestroyed(EulaView* view); + + private: + // BaseScreen implementation: void Show() override; void Hide() override; - GURL GetOemEulaUrl() const override; - void InitiatePasswordFetch() override; - bool IsUsageStatsEnabled() const override; - void OnViewDestroyed(EulaView* view) override; void OnUserAction(const std::string& action_id) override; void OnContextKeyUpdated(const ::login::ScreenContext::KeyType& key) override; // TpmPasswordFetcherDelegate implementation: void OnPasswordFetched(const std::string& tpm_password) override; - private: // URL of the OEM EULA page (on disk). GURL oem_eula_page_;
diff --git a/chrome/browser/chromeos/login/screens/eula_view.h b/chrome/browser/chromeos/login/screens/eula_view.h index 1d12715..08c0da0f 100644 --- a/chrome/browser/chromeos/login/screens/eula_view.h +++ b/chrome/browser/chromeos/login/screens/eula_view.h
@@ -9,7 +9,7 @@ namespace chromeos { -class EulaModel; +class EulaScreen; // Interface between eula screen and its representation, either WebUI // or Views one. Note, do not forget to call OnViewDestroyed in the @@ -20,7 +20,7 @@ virtual void Show() = 0; virtual void Hide() = 0; - virtual void Bind(EulaModel& model) = 0; + virtual void Bind(EulaScreen* screen) = 0; virtual void Unbind() = 0; virtual void OnPasswordFetched(const std::string& tpm_password) = 0; };
diff --git a/chrome/browser/chromeos/login/screens/mock_eula_screen.cc b/chrome/browser/chromeos/login/screens/mock_eula_screen.cc index 41f7508e..d5aebbc3 100644 --- a/chrome/browser/chromeos/login/screens/mock_eula_screen.cc +++ b/chrome/browser/chromeos/login/screens/mock_eula_screen.cc
@@ -23,17 +23,17 @@ } MockEulaView::~MockEulaView() { - if (model_) - model_->OnViewDestroyed(this); + if (screen_) + screen_->OnViewDestroyed(this); } -void MockEulaView::Bind(EulaModel& model) { - model_ = &model; - MockBind(model); +void MockEulaView::Bind(EulaScreen* screen) { + screen_ = screen; + MockBind(screen); } void MockEulaView::Unbind() { - model_ = nullptr; + screen_ = nullptr; MockUnbind(); }
diff --git a/chrome/browser/chromeos/login/screens/mock_eula_screen.h b/chrome/browser/chromeos/login/screens/mock_eula_screen.h index 27c4ba4..5d71201 100644 --- a/chrome/browser/chromeos/login/screens/mock_eula_screen.h +++ b/chrome/browser/chromeos/login/screens/mock_eula_screen.h
@@ -25,18 +25,18 @@ MockEulaView(); ~MockEulaView() override; - void Bind(EulaModel& model) override; + void Bind(EulaScreen* screen) override; void Unbind() override; MOCK_METHOD0(Show, void()); MOCK_METHOD0(Hide, void()); - MOCK_METHOD1(MockBind, void(EulaModel& model)); + MOCK_METHOD1(MockBind, void(EulaScreen* screen)); MOCK_METHOD0(MockUnbind, void()); MOCK_METHOD1(OnPasswordFetched, void(const std::string& tpm_password)); private: - EulaModel* model_; + EulaScreen* screen_ = nullptr; }; } // namespace chromeos
diff --git a/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.cc b/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.cc index a6562915..077b3b9 100644 --- a/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.cc +++ b/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.cc
@@ -8,9 +8,11 @@ #include <vector> #include "base/bind.h" +#include "base/command_line.h" #include "base/logging.h" #include "base/memory/weak_ptr.h" #include "base/strings/string_util.h" +#include "chromeos/chromeos_switches.h" #include "content/public/browser/browser_thread.h" #include "google_apis/gaia/gaia_auth_fetcher.h" #include "google_apis/gaia/gaia_constants.h" @@ -164,6 +166,16 @@ } void PolicyOAuth2TokenFetcherImpl::StartFetchingRefreshToken() { + // Don't fetch tokens for test. + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + chromeos::switches::kDisableGaiaServices)) { + failed_ = true; + ForwardPolicyToken( + std::string(), + GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED)); + return; + } + if (auth_code_.empty()) { refresh_token_fetcher_.reset(new GaiaAuthFetcher( this, GaiaConstants::kChromeSource, auth_context_getter_.get()));
diff --git a/chrome/browser/domain_reliability/browsertest.cc b/chrome/browser/domain_reliability/browsertest.cc index 1954b78c..c70aacd 100644 --- a/chrome/browser/domain_reliability/browsertest.cc +++ b/chrome/browser/domain_reliability/browsertest.cc
@@ -82,7 +82,7 @@ auto config = base::MakeUnique<DomainReliabilityConfig>(); config->origin = GURL("https://localhost/"); config->include_subdomains = false; - config->collectors.push_back(new GURL( + config->collectors.push_back(base::MakeUnique<GURL>( net::URLRequestFailedJob::GetMockHttpsUrl(net::ERR_IO_PENDING))); config->success_sample_rate = 1.0; config->failure_sample_rate = 1.0;
diff --git a/chrome/browser/resources/settings/controls/settings_input.html b/chrome/browser/resources/settings/controls/settings_input.html index aec34aa..77254c5 100644 --- a/chrome/browser/resources/settings/controls/settings_input.html +++ b/chrome/browser/resources/settings/controls/settings_input.html
@@ -1,3 +1,4 @@ +<link rel="import" href="chrome://resources/html/assert.html"> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html"> <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_pref_behavior.html"> @@ -18,7 +19,7 @@ error-message="[[errorMessage]]" label="[[label]]" no-label-float="[[noLabelFloat]]" pattern="[[pattern]]" readonly$="[[readonly]]" required="[[required]]" type="[[type]]" - on-blur="onBlur_" disabled="[[isDisabled_(disabled, pref)]]" + on-change="onChange_" disabled="[[isDisabled_(disabled, pref)]]" stop-keyboard-event-propagation$="[[stopKeyboardEventPropagation]]" tabindex$="[[getTabindex_(canTab)]]"> </paper-input>
diff --git a/chrome/browser/resources/settings/controls/settings_input.js b/chrome/browser/resources/settings/controls/settings_input.js index 012a8bca..2652db17 100644 --- a/chrome/browser/resources/settings/controls/settings_input.js +++ b/chrome/browser/resources/settings/controls/settings_input.js
@@ -90,10 +90,11 @@ }, /** - * Blur method for paper-input. Only update the pref value on a blur event. + * Change event handler for paper-input. Updates the pref value. + * settings-input uses the change event because it is fired by the Enter key. * @private */ - onBlur_: function() { + onChange_: function() { if (!this.pref) return;
diff --git a/chrome/browser/resources/settings/site_settings/site_list.js b/chrome/browser/resources/settings/site_settings/site_list.js index 8501b13..deb8f38c 100644 --- a/chrome/browser/resources/settings/site_settings/site_list.js +++ b/chrome/browser/resources/settings/site_settings/site_list.js
@@ -223,11 +223,13 @@ if (this.allSites) { this.getAllSitesList_().then(function(lists) { this.processExceptions_(lists); + this.closeActionMenu_(); }.bind(this)); } else { this.browserProxy_.getExceptionList(this.category).then( function(exceptionList) { this.processExceptions_([exceptionList]); + this.closeActionMenu_(); }.bind(this)); } }, @@ -465,7 +467,9 @@ /** @private */ closeActionMenu_: function() { this.actionMenuSite_ = null; - /** @type {!CrActionMenuElement} */ ( - this.$$('dialog[is=cr-action-menu]')).close(); + var actionMenu = /** @type {!CrActionMenuElement} */ ( + this.$$('dialog[is=cr-action-menu]')); + if (actionMenu.open) + actionMenu.close(); }, });
diff --git a/chrome/browser/sync_file_system/drive_backend/conflict_resolver_unittest.cc b/chrome/browser/sync_file_system/drive_backend/conflict_resolver_unittest.cc index 99d194d..e9582e3 100644 --- a/chrome/browser/sync_file_system/drive_backend/conflict_resolver_unittest.cc +++ b/chrome/browser/sync_file_system/drive_backend/conflict_resolver_unittest.cc
@@ -237,10 +237,10 @@ return status; } - ScopedVector<google_apis::FileResource> + std::vector<std::unique_ptr<google_apis::FileResource>> GetResourceEntriesForParentAndTitle(const std::string& parent_folder_id, const std::string& title) { - ScopedVector<google_apis::FileResource> entries; + std::vector<std::unique_ptr<google_apis::FileResource>> entries; EXPECT_EQ(google_apis::HTTP_SUCCESS, fake_drive_helper_->SearchByTitle( parent_folder_id, title, &entries)); @@ -252,7 +252,7 @@ const std::string& title, const std::string& primary_file_id, test_util::FileResourceKind kind) { - ScopedVector<google_apis::FileResource> entries; + std::vector<std::unique_ptr<google_apis::FileResource>> entries; EXPECT_EQ(google_apis::HTTP_SUCCESS, fake_drive_helper_->SearchByTitle( parent_folder_id, title, &entries)); @@ -307,7 +307,7 @@ EXPECT_EQ(SYNC_STATUS_OK, ListChanges()); RunRemoteToLocalSyncerUntilIdle(); - ScopedVector<google_apis::FileResource> entries = + std::vector<std::unique_ptr<google_apis::FileResource>> entries = GetResourceEntriesForParentAndTitle(app_root, kTitle); ASSERT_EQ(4u, entries.size()); @@ -333,7 +333,7 @@ EXPECT_EQ(SYNC_STATUS_OK, ListChanges()); RunRemoteToLocalSyncerUntilIdle(); - ScopedVector<google_apis::FileResource> entries = + std::vector<std::unique_ptr<google_apis::FileResource>> entries = GetResourceEntriesForParentAndTitle(app_root, kTitle); ASSERT_EQ(4u, entries.size()); @@ -359,7 +359,7 @@ EXPECT_EQ(SYNC_STATUS_OK, ListChanges()); RunRemoteToLocalSyncerUntilIdle(); - ScopedVector<google_apis::FileResource> entries = + std::vector<std::unique_ptr<google_apis::FileResource>> entries = GetResourceEntriesForParentAndTitle(app_root, kTitle); ASSERT_EQ(4u, entries.size()); @@ -391,7 +391,7 @@ EXPECT_EQ(SYNC_STATUS_OK, ListChanges()); RunRemoteToLocalSyncerUntilIdle(); - ScopedVector<google_apis::FileResource> entries = + std::vector<std::unique_ptr<google_apis::FileResource>> entries = GetResourceEntriesForParentAndTitle(app_root, kTitle); ASSERT_EQ(2u, entries.size()); @@ -439,7 +439,7 @@ EXPECT_EQ(SYNC_STATUS_OK, ListChanges()); RunRemoteToLocalSyncerUntilIdle(); - ScopedVector<google_apis::FileResource> entries = + std::vector<std::unique_ptr<google_apis::FileResource>> entries = GetResourceEntriesForParentAndTitle(app_root, kTitle); ASSERT_EQ(2u, entries.size());
diff --git a/chrome/browser/sync_file_system/drive_backend/drive_backend_sync_unittest.cc b/chrome/browser/sync_file_system/drive_backend/drive_backend_sync_unittest.cc index 2ed5052..300fdc8 100644 --- a/chrome/browser/sync_file_system/drive_backend/drive_backend_sync_unittest.cc +++ b/chrome/browser/sync_file_system/drive_backend/drive_backend_sync_unittest.cc
@@ -12,6 +12,7 @@ #include "base/macros.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" +#include "base/stl_util.h" #include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/sync_file_system/drive_backend/callback_helper.h" #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h" @@ -412,18 +413,14 @@ } EXPECT_EQ(google_apis::HTTP_SUCCESS, error); - ScopedVector<google_apis::FileResource> remote_entries; + std::vector<std::unique_ptr<google_apis::FileResource>> remote_entries; EXPECT_EQ(google_apis::HTTP_SUCCESS, fake_drive_service_helper_->ListFilesInFolder( sync_root_folder_id, &remote_entries)); std::map<std::string, const google_apis::FileResource*> app_root_by_title; - for (ScopedVector<google_apis::FileResource>::iterator itr = - remote_entries.begin(); - itr != remote_entries.end(); - ++itr) { - const google_apis::FileResource& remote_entry = **itr; - EXPECT_FALSE(base::ContainsKey(app_root_by_title, remote_entry.title())); - app_root_by_title[remote_entry.title()] = *itr; + for (const auto& remote_entry : remote_entries) { + EXPECT_FALSE(base::ContainsKey(app_root_by_title, remote_entry->title())); + app_root_by_title[remote_entry->title()] = remote_entry.get(); } for (std::map<std::string, CannedSyncableFileSystem*>::const_iterator itr = @@ -446,14 +443,14 @@ CannedSyncableFileSystem* file_system) { SCOPED_TRACE(testing::Message() << "Verifying folder: " << path.value()); - ScopedVector<google_apis::FileResource> remote_entries; + std::vector<std::unique_ptr<google_apis::FileResource>> remote_entries; EXPECT_EQ(google_apis::HTTP_SUCCESS, fake_drive_service_helper_->ListFilesInFolder( folder_id, &remote_entries)); std::map<std::string, const google_apis::FileResource*> remote_entry_by_title; for (size_t i = 0; i < remote_entries.size(); ++i) { - google_apis::FileResource* remote_entry = remote_entries[i]; + google_apis::FileResource* remote_entry = remote_entries[i].get(); EXPECT_FALSE( base::ContainsKey(remote_entry_by_title, remote_entry->title())) << "title: " << remote_entry->title();
diff --git a/chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.cc b/chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.cc index 26d0a79..6975d04 100644 --- a/chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.cc +++ b/chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.cc
@@ -217,12 +217,11 @@ if (error != google_apis::HTTP_SUCCESS) return error; - const ScopedVector<FileResource>& items = resource_list->items(); - for (ScopedVector<FileResource>::const_iterator itr = items.begin(); - itr != items.end(); ++itr) { - const FileResource& item = **itr; - if (item.parents().empty()) { - *sync_root_folder_id = item.file_id(); + const std::vector<std::unique_ptr<FileResource>>& items = + resource_list->items(); + for (const auto& item : items) { + if (item->parents().empty()) { + *sync_root_folder_id = item->file_id(); return google_apis::HTTP_SUCCESS; } } @@ -231,7 +230,7 @@ DriveApiErrorCode FakeDriveServiceHelper::ListFilesInFolder( const std::string& folder_id, - ScopedVector<FileResource>* entries) { + std::vector<std::unique_ptr<FileResource>>* entries) { DriveApiErrorCode error = google_apis::DRIVE_OTHER_ERROR; std::unique_ptr<FileList> list; fake_drive_service_->GetFileListInDirectory( @@ -247,7 +246,7 @@ DriveApiErrorCode FakeDriveServiceHelper::SearchByTitle( const std::string& folder_id, const std::string& title, - ScopedVector<FileResource>* entries) { + std::vector<std::unique_ptr<FileResource>>* entries) { DriveApiErrorCode error = google_apis::DRIVE_OTHER_ERROR; std::unique_ptr<FileList> list; fake_drive_service_->SearchByTitle( @@ -316,15 +315,12 @@ DriveApiErrorCode FakeDriveServiceHelper::CompleteListing( std::unique_ptr<FileList> list, - ScopedVector<FileResource>* entries) { + std::vector<std::unique_ptr<FileResource>>* entries) { while (true) { entries->reserve(entries->size() + list->items().size()); - std::vector<FileResource*> tmp; - list->mutable_items()->release(&tmp); - for (std::vector<FileResource*>::const_iterator itr = - tmp.begin(); itr != tmp.end(); ++itr) { - entries->push_back(*itr); - } + std::move(list->mutable_items()->begin(), list->mutable_items()->end(), + std::back_inserter(*entries)); + list->mutable_items()->clear(); GURL next_feed = list->next_link(); if (next_feed.is_empty())
diff --git a/chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.h b/chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.h index 599417ec..36817aa 100644 --- a/chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.h +++ b/chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.h
@@ -60,11 +60,11 @@ std::string* sync_root_folder_id); google_apis::DriveApiErrorCode ListFilesInFolder( const std::string& folder_id, - ScopedVector<google_apis::FileResource>* entries); + std::vector<std::unique_ptr<google_apis::FileResource>>* entries); google_apis::DriveApiErrorCode SearchByTitle( const std::string& folder_id, const std::string& title, - ScopedVector<google_apis::FileResource>* entries); + std::vector<std::unique_ptr<google_apis::FileResource>>* entries); google_apis::DriveApiErrorCode GetFileResource( const std::string& file_id, @@ -83,7 +83,7 @@ private: google_apis::DriveApiErrorCode CompleteListing( std::unique_ptr<google_apis::FileList> list, - ScopedVector<google_apis::FileResource>* entries); + std::vector<std::unique_ptr<google_apis::FileResource>>* entries); void Initialize();
diff --git a/chrome/browser/sync_file_system/drive_backend/folder_creator.cc b/chrome/browser/sync_file_system/drive_backend/folder_creator.cc index 8a7ec88..4d732bc 100644 --- a/chrome/browser/sync_file_system/drive_backend/folder_creator.cc +++ b/chrome/browser/sync_file_system/drive_backend/folder_creator.cc
@@ -56,14 +56,16 @@ drive_service_->SearchByTitle( title_, parent_folder_id_, - base::Bind(&FolderCreator::DidListFolders, - weak_ptr_factory_.GetWeakPtr(), callback, - base::Passed(ScopedVector<google_apis::FileResource>()))); + base::Bind( + &FolderCreator::DidListFolders, weak_ptr_factory_.GetWeakPtr(), + callback, + base::Passed( + std::vector<std::unique_ptr<google_apis::FileResource>>()))); } void FolderCreator::DidListFolders( const FileIDCallback& callback, - ScopedVector<google_apis::FileResource> candidates, + std::vector<std::unique_ptr<google_apis::FileResource>> candidates, google_apis::DriveApiErrorCode error, std::unique_ptr<google_apis::FileList> file_list) { SyncStatusCode status = DriveApiErrorCodeToSyncStatusCode(error); @@ -79,10 +81,9 @@ } candidates.reserve(candidates.size() + file_list->items().size()); - candidates.insert(candidates.end(), - file_list->items().begin(), - file_list->items().end()); - file_list->mutable_items()->weak_clear(); + std::move(file_list->mutable_items()->begin(), + file_list->mutable_items()->end(), std::back_inserter(candidates)); + file_list->mutable_items()->clear(); if (!file_list->next_link().is_empty()) { drive_service_->GetRemainingFileList(
diff --git a/chrome/browser/sync_file_system/drive_backend/folder_creator.h b/chrome/browser/sync_file_system/drive_backend/folder_creator.h index dca4186..53457df 100644 --- a/chrome/browser/sync_file_system/drive_backend/folder_creator.h +++ b/chrome/browser/sync_file_system/drive_backend/folder_creator.h
@@ -9,7 +9,6 @@ #include <string> #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/sync_file_system/sync_callbacks.h" #include "google_apis/drive/drive_api_error_codes.h" @@ -45,10 +44,11 @@ void DidCreateFolder(const FileIDCallback& callback, google_apis::DriveApiErrorCode error, std::unique_ptr<google_apis::FileResource> entry); - void DidListFolders(const FileIDCallback& callback, - ScopedVector<google_apis::FileResource> candidates, - google_apis::DriveApiErrorCode error, - std::unique_ptr<google_apis::FileList> file_list); + void DidListFolders( + const FileIDCallback& callback, + std::vector<std::unique_ptr<google_apis::FileResource>> candidates, + google_apis::DriveApiErrorCode error, + std::unique_ptr<google_apis::FileList> file_list); drive::DriveServiceInterface* drive_service_; MetadataDatabase* metadata_database_;
diff --git a/chrome/browser/sync_file_system/drive_backend/list_changes_task.cc b/chrome/browser/sync_file_system/drive_backend/list_changes_task.cc index 7d8d793..9991ff3c 100644 --- a/chrome/browser/sync_file_system/drive_backend/list_changes_task.cc +++ b/chrome/browser/sync_file_system/drive_backend/list_changes_task.cc
@@ -75,12 +75,12 @@ return; } - std::vector<google_apis::ChangeResource*> changes; - change_list->mutable_items()->release(&changes); - - change_list_.reserve(change_list_.size() + changes.size()); - for (size_t i = 0; i < changes.size(); ++i) - change_list_.push_back(changes[i]); + change_list_.reserve(change_list_.size() + + change_list->mutable_items()->size()); + std::move(change_list->mutable_items()->begin(), + change_list->mutable_items()->end(), + std::back_inserter(change_list_)); + change_list->mutable_items()->clear(); if (!change_list->next_link().is_empty()) { drive_service()->GetRemainingChangeList(
diff --git a/chrome/browser/sync_file_system/drive_backend/list_changes_task.h b/chrome/browser/sync_file_system/drive_backend/list_changes_task.h index 9b47673e..220dcdd 100644 --- a/chrome/browser/sync_file_system/drive_backend/list_changes_task.h +++ b/chrome/browser/sync_file_system/drive_backend/list_changes_task.h
@@ -10,7 +10,6 @@ #include <memory> #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/sync_file_system/drive_backend/sync_task.h" #include "google_apis/drive/drive_api_error_codes.h" @@ -50,7 +49,7 @@ drive::DriveServiceInterface* drive_service(); SyncEngineContext* sync_context_; - ScopedVector<google_apis::ChangeResource> change_list_; + std::vector<std::unique_ptr<google_apis::ChangeResource>> change_list_; std::vector<std::string> file_ids_;
diff --git a/chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer_unittest.cc b/chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer_unittest.cc index d08ac823..bb9ce1d 100644 --- a/chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer_unittest.cc +++ b/chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer_unittest.cc
@@ -210,10 +210,10 @@ return status; } - ScopedVector<google_apis::FileResource> + std::vector<std::unique_ptr<google_apis::FileResource>> GetResourceEntriesForParentAndTitle(const std::string& parent_folder_id, const std::string& title) { - ScopedVector<google_apis::FileResource> entries; + std::vector<std::unique_ptr<google_apis::FileResource>> entries; EXPECT_EQ(google_apis::HTTP_SUCCESS, fake_drive_helper_->SearchByTitle( parent_folder_id, title, &entries)); @@ -222,7 +222,7 @@ std::string GetFileIDForParentAndTitle(const std::string& parent_folder_id, const std::string& title) { - ScopedVector<google_apis::FileResource> entries = + std::vector<std::unique_ptr<google_apis::FileResource>> entries = GetResourceEntriesForParentAndTitle(parent_folder_id, title); if (entries.size() != 1) return std::string(); @@ -233,7 +233,7 @@ const std::string& parent_folder_id, const std::string& title, test_util::FileResourceKind kind) { - ScopedVector<google_apis::FileResource> entries; + std::vector<std::unique_ptr<google_apis::FileResource>> entries; EXPECT_EQ(google_apis::HTTP_SUCCESS, fake_drive_helper_->SearchByTitle( parent_folder_id, title, &entries)); @@ -243,7 +243,7 @@ void VerifyFileDeletion(const std::string& parent_folder_id, const std::string& title) { - ScopedVector<google_apis::FileResource> entries; + std::vector<std::unique_ptr<google_apis::FileResource>> entries; EXPECT_EQ(google_apis::HTTP_SUCCESS, fake_drive_helper_->SearchByTitle( parent_folder_id, title, &entries)); @@ -377,7 +377,7 @@ URL(kOrigin, "foo"))); // There should exist both file and folder on remote. - ScopedVector<google_apis::FileResource> entries = + std::vector<std::unique_ptr<google_apis::FileResource>> entries = GetResourceEntriesForParentAndTitle(app_root, "foo"); ASSERT_EQ(2u, entries.size()); EXPECT_EQ(test_util::RESOURCE_KIND_FOLDER, @@ -402,7 +402,7 @@ URL(kOrigin, "foo"))); // There should exist both file and folder on remote. - ScopedVector<google_apis::FileResource> entries = + std::vector<std::unique_ptr<google_apis::FileResource>> entries = GetResourceEntriesForParentAndTitle(app_root, "foo"); ASSERT_EQ(2u, entries.size()); EXPECT_EQ(test_util::RESOURCE_KIND_FILE, @@ -427,7 +427,7 @@ URL(kOrigin, "foo"))); // There should exist both files on remote. - ScopedVector<google_apis::FileResource> entries = + std::vector<std::unique_ptr<google_apis::FileResource>> entries = GetResourceEntriesForParentAndTitle(app_root, "foo"); ASSERT_EQ(2u, entries.size()); EXPECT_EQ(test_util::RESOURCE_KIND_FILE, @@ -459,7 +459,7 @@ SYNC_FILE_TYPE_FILE), URL(kOrigin, "foo"))); - ScopedVector<google_apis::FileResource> entries = + std::vector<std::unique_ptr<google_apis::FileResource>> entries = GetResourceEntriesForParentAndTitle(app_root, "foo"); ASSERT_EQ(1u, entries.size()); EXPECT_EQ(test_util::RESOURCE_KIND_FILE, @@ -489,7 +489,7 @@ SYNC_FILE_TYPE_FILE), URL(kOrigin, "foo"))); - ScopedVector<google_apis::FileResource> entries = + std::vector<std::unique_ptr<google_apis::FileResource>> entries = GetResourceEntriesForParentAndTitle(app_root, "foo"); ASSERT_EQ(1u, entries.size()); EXPECT_EQ(test_util::RESOURCE_KIND_FILE, @@ -512,7 +512,7 @@ SYNC_FILE_TYPE_DIRECTORY), URL(kOrigin, "foo"))); - ScopedVector<google_apis::FileResource> entries = + std::vector<std::unique_ptr<google_apis::FileResource>> entries = GetResourceEntriesForParentAndTitle(app_root, "foo"); ASSERT_EQ(2u, entries.size()); EXPECT_EQ(test_util::RESOURCE_KIND_FOLDER,
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database.cc index 0b1e11e..84436d6 100644 --- a/chrome/browser/sync_file_system/drive_backend/metadata_database.cc +++ b/chrome/browser/sync_file_system/drive_backend/metadata_database.cc
@@ -622,7 +622,8 @@ SyncStatusCode MetadataDatabase::PopulateInitialData( int64_t largest_change_id, const google_apis::FileResource& sync_root_folder, - const ScopedVector<google_apis::FileResource>& app_root_folders) { + const std::vector<std::unique_ptr<google_apis::FileResource>>& + app_root_folders) { index_->SetLargestChangeID(largest_change_id); UpdateLargestKnownChangeID(largest_change_id); @@ -889,7 +890,7 @@ SyncStatusCode MetadataDatabase::UpdateByChangeList( int64_t largest_change_id, - ScopedVector<google_apis::ChangeResource> changes) { + std::vector<std::unique_ptr<google_apis::ChangeResource>> changes) { DCHECK_LE(index_->GetLargestChangeID(), largest_change_id); for (size_t i = 0; i < changes.size(); ++i) { @@ -918,7 +919,7 @@ } SyncStatusCode MetadataDatabase::UpdateByFileResourceList( - ScopedVector<google_apis::FileResource> resources) { + std::vector<std::unique_ptr<google_apis::FileResource>> resources) { for (size_t i = 0; i < resources.size(); ++i) { std::unique_ptr<FileMetadata> metadata(CreateFileMetadataFromFileResource( GetLargestKnownChangeID(), *resources[i]));
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database.h b/chrome/browser/sync_file_system/drive_backend/metadata_database.h index dc89685..e47eca7 100644 --- a/chrome/browser/sync_file_system/drive_backend/metadata_database.h +++ b/chrome/browser/sync_file_system/drive_backend/metadata_database.h
@@ -17,7 +17,6 @@ #include "base/containers/hash_tables.h" #include "base/files/file_path.h" #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "base/memory/weak_ptr.h" #include "base/sequence_checker.h" #include "base/values.h" @@ -183,7 +182,8 @@ SyncStatusCode PopulateInitialData( int64_t largest_change_id, const google_apis::FileResource& sync_root_folder, - const ScopedVector<google_apis::FileResource>& app_root_folders); + const std::vector<std::unique_ptr<google_apis::FileResource>>& + app_root_folders); // Returns true if the folder associated to |app_id| is enabled. bool IsAppEnabled(const std::string& app_id) const; @@ -261,7 +261,7 @@ // needed. SyncStatusCode UpdateByChangeList( int64_t largest_change_id, - ScopedVector<google_apis::ChangeResource> changes); + std::vector<std::unique_ptr<google_apis::ChangeResource>> changes); // Updates database by |resource|. // Marks each tracker for modified file as dirty and adds new trackers if @@ -269,7 +269,7 @@ SyncStatusCode UpdateByFileResource( const google_apis::FileResource& resource); SyncStatusCode UpdateByFileResourceList( - ScopedVector<google_apis::FileResource> resources); + std::vector<std::unique_ptr<google_apis::FileResource>> resources); SyncStatusCode UpdateByDeletedRemoteFile(const std::string& file_id); SyncStatusCode UpdateByDeletedRemoteFileList(const FileIDList& file_ids);
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database_index.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database_index.cc index e2a092ee..c85fde8 100644 --- a/chrome/browser/sync_file_system/drive_backend/metadata_database_index.cc +++ b/chrome/browser/sync_file_system/drive_backend/metadata_database_index.cc
@@ -98,7 +98,7 @@ continue; } - contents->file_metadata.push_back(metadata.release()); + contents->file_metadata.push_back(std::move(metadata)); continue; } @@ -117,7 +117,7 @@ "Failed to parse a Tracker"); continue; } - contents->file_trackers.push_back(tracker.release()); + contents->file_trackers.push_back(std::move(tracker)); continue; } } @@ -168,12 +168,11 @@ } // Delete all unreachable trackers. - ScopedVector<FileTracker> reachable_trackers; + std::vector<std::unique_ptr<FileTracker>> reachable_trackers; for (size_t i = 0; i < contents->file_trackers.size(); ++i) { - FileTracker* tracker = contents->file_trackers[i]; + std::unique_ptr<FileTracker>& tracker = contents->file_trackers[i]; if (base::ContainsKey(visited_trackers, tracker->tracker_id())) { - reachable_trackers.push_back(tracker); - contents->file_trackers[i] = nullptr; + reachable_trackers.push_back(std::move(tracker)); } else { PutFileTrackerDeletionToDB(tracker->tracker_id(), db); } @@ -186,12 +185,11 @@ referred_file_ids.insert(contents->file_trackers[i]->file_id()); // Delete all unreferred metadata. - ScopedVector<FileMetadata> referred_file_metadata; + std::vector<std::unique_ptr<FileMetadata>> referred_file_metadata; for (size_t i = 0; i < contents->file_metadata.size(); ++i) { - FileMetadata* metadata = contents->file_metadata[i]; + std::unique_ptr<FileMetadata>& metadata = contents->file_metadata[i]; if (base::ContainsKey(referred_file_ids, metadata->file_id())) { - referred_file_metadata.push_back(metadata); - contents->file_metadata[i] = nullptr; + referred_file_metadata.push_back(std::move(metadata)); } else { PutFileMetadataDeletionToDB(metadata->file_id(), db); } @@ -238,12 +236,12 @@ service_metadata_ = std::move(service_metadata); for (size_t i = 0; i < contents->file_metadata.size(); ++i) - StoreFileMetadata(base::WrapUnique(contents->file_metadata[i])); - contents->file_metadata.weak_clear(); + StoreFileMetadata(std::move(contents->file_metadata[i])); + contents->file_metadata.clear(); for (size_t i = 0; i < contents->file_trackers.size(); ++i) - StoreFileTracker(base::WrapUnique(contents->file_trackers[i])); - contents->file_trackers.weak_clear(); + StoreFileTracker(std::move(contents->file_trackers[i])); + contents->file_trackers.clear(); UMA_HISTOGRAM_COUNTS("SyncFileSystem.MetadataNumber", metadata_by_id_.size()); UMA_HISTOGRAM_COUNTS("SyncFileSystem.TrackerNumber", tracker_by_id_.size());
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database_index.h b/chrome/browser/sync_file_system/drive_backend/metadata_database_index.h index 5c7aa62..38ff499 100644 --- a/chrome/browser/sync_file_system/drive_backend/metadata_database_index.h +++ b/chrome/browser/sync_file_system/drive_backend/metadata_database_index.h
@@ -17,7 +17,6 @@ #include "base/containers/hash_tables.h" #include "base/hash.h" #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "chrome/browser/sync_file_system/drive_backend/metadata_database_index_interface.h" #include "chrome/browser/sync_file_system/drive_backend/tracker_id_set.h" @@ -49,8 +48,8 @@ struct DatabaseContents { DatabaseContents(); ~DatabaseContents(); - ScopedVector<FileMetadata> file_metadata; - ScopedVector<FileTracker> file_trackers; + std::vector<std::unique_ptr<FileMetadata>> file_metadata; + std::vector<std::unique_ptr<FileTracker>> file_trackers; }; // Maintains indexes of MetadataDatabase on memory.
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database_index_unittest.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database_index_unittest.cc index 217b592c..6578079 100644 --- a/chrome/browser/sync_file_system/drive_backend/metadata_database_index_unittest.cc +++ b/chrome/browser/sync_file_system/drive_backend/metadata_database_index_unittest.cc
@@ -54,13 +54,13 @@ test_util::CreatePlaceholderTracker( "unsynced_file_id", kPlaceholderTrackerID, app_root_tracker.get()); - contents->file_metadata.push_back(sync_root_metadata.release()); - contents->file_trackers.push_back(sync_root_tracker.release()); - contents->file_metadata.push_back(app_root_metadata.release()); - contents->file_trackers.push_back(app_root_tracker.release()); - contents->file_metadata.push_back(file_metadata.release()); - contents->file_trackers.push_back(file_tracker.release()); - contents->file_trackers.push_back(placeholder_tracker.release()); + contents->file_metadata.push_back(std::move(sync_root_metadata)); + contents->file_trackers.push_back(std::move(sync_root_tracker)); + contents->file_metadata.push_back(std::move(app_root_metadata)); + contents->file_trackers.push_back(std::move(app_root_tracker)); + contents->file_metadata.push_back(std::move(file_metadata)); + contents->file_trackers.push_back(std::move(file_tracker)); + contents->file_trackers.push_back(std::move(placeholder_tracker)); return contents; }
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc index e456d4ce7..5d6d331f 100644 --- a/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc +++ b/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
@@ -462,9 +462,10 @@ file->mutable_details()->set_change_id(++current_change_id_); } - void PushToChangeList(std::unique_ptr<google_apis::ChangeResource> change, - ScopedVector<google_apis::ChangeResource>* changes) { - changes->push_back(change.release()); + void PushToChangeList( + std::unique_ptr<google_apis::ChangeResource> change, + std::vector<std::unique_ptr<google_apis::ChangeResource>>* changes) { + changes->push_back(std::move(change)); } leveldb::Status PutFileToDB(LevelDBWrapper* db, const FileMetadata& file) { @@ -586,7 +587,7 @@ } SyncStatusCode UpdateByChangeList( - ScopedVector<google_apis::ChangeResource> changes) { + std::vector<std::unique_ptr<google_apis::ChangeResource>> changes) { return metadata_database_->UpdateByChangeList(current_change_id_, std::move(changes)); } @@ -605,7 +606,8 @@ SyncStatusCode PopulateInitialData( int64_t largest_change_id, const google_apis::FileResource& sync_root_folder, - const ScopedVector<google_apis::FileResource>& app_root_folders) { + const std::vector<std::unique_ptr<google_apis::FileResource>>& + app_root_folders) { return metadata_database_->PopulateInitialData( largest_change_id, sync_root_folder, app_root_folders); } @@ -915,7 +917,7 @@ // Update change ID. ApplyNoopChangeToMetadata(&noop_file.metadata); - ScopedVector<google_apis::ChangeResource> changes; + std::vector<std::unique_ptr<google_apis::ChangeResource>> changes; PushToChangeList( CreateChangeResourceFromMetadata(renamed_file.metadata), &changes); PushToChangeList( @@ -1119,8 +1121,8 @@ std::unique_ptr<google_apis::FileResource> app_root_folder( CreateFileResourceFromMetadata(app_root.metadata)); - ScopedVector<google_apis::FileResource> app_root_folders; - app_root_folders.push_back(app_root_folder.release()); + std::vector<std::unique_ptr<google_apis::FileResource>> app_root_folders; + app_root_folders.push_back(std::move(app_root_folder)); EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase()); EXPECT_EQ(SYNC_STATUS_OK, PopulateInitialData(
diff --git a/chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc b/chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc index 0bee87d..ffebda20 100644 --- a/chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc +++ b/chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc
@@ -205,7 +205,7 @@ } size_t CountRemoteFileInSyncRoot() { - ScopedVector<google_apis::FileResource> files; + std::vector<std::unique_ptr<google_apis::FileResource>> files; EXPECT_EQ(google_apis::HTTP_SUCCESS, fake_drive_service_helper_->ListFilesInFolder( sync_root_folder_id_, &files));
diff --git a/chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer.cc b/chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer.cc index f578c43a..b3af159 100644 --- a/chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer.cc +++ b/chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer.cc
@@ -676,11 +676,8 @@ } children->reserve(children->size() + file_list->items().size()); - for (ScopedVector<google_apis::FileResource>::const_iterator itr = - file_list->items().begin(); - itr != file_list->items().end(); - ++itr) { - children->push_back((*itr)->file_id()); + for (const auto& file_resource : file_list->items()) { + children->push_back(file_resource->file_id()); } if (!file_list->next_link().is_empty()) {
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.cc b/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.cc index 6115d81..4d1dd0f 100644 --- a/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.cc +++ b/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.cc
@@ -180,11 +180,9 @@ return; } - ScopedVector<google_apis::FileResource>* items = file_list->mutable_items(); - for (ScopedVector<google_apis::FileResource>::iterator itr = items->begin(); - itr != items->end(); ++itr) { - google_apis::FileResource* entry = *itr; - + std::vector<std::unique_ptr<google_apis::FileResource>>* items = + file_list->mutable_items(); + for (auto& entry : *items) { // Ignore deleted folder. if (entry->labels().is_trashed()) continue; @@ -199,8 +197,7 @@ continue; if (!sync_root_folder_ || LessOnCreationTime(*entry, *sync_root_folder_)) { - sync_root_folder_.reset(entry); - *itr = nullptr; + sync_root_folder_ = std::move(entry); } } @@ -321,11 +318,12 @@ return; } - ScopedVector<google_apis::FileResource>* new_entries = + std::vector<std::unique_ptr<google_apis::FileResource>>* new_entries = file_list->mutable_items(); - app_root_folders_.insert(app_root_folders_.end(), - new_entries->begin(), new_entries->end()); - new_entries->weak_clear(); + app_root_folders_.reserve(app_root_folders_.size() + new_entries->size()); + std::move(new_entries->begin(), new_entries->end(), + std::back_inserter(app_root_folders_)); + new_entries->clear(); set_used_network(true); if (!file_list->next_link().is_empty()) {
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.h b/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.h index e720b40e..1fce116 100644 --- a/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.h +++ b/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.h
@@ -12,7 +12,6 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/memory/scoped_vector.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/sync_file_system/drive_backend/sync_task.h" #include "chrome/browser/sync_file_system/sync_callbacks.h" @@ -106,7 +105,7 @@ int find_sync_root_retry_count_; std::unique_ptr<MetadataDatabase> metadata_database_; - ScopedVector<google_apis::FileResource> app_root_folders_; + std::vector<std::unique_ptr<google_apis::FileResource>> app_root_folders_; int64_t largest_change_id_; std::string root_folder_id_;
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer_unittest.cc b/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer_unittest.cc index 7559a18..ec2f2ec 100644 --- a/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer_unittest.cc +++ b/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer_unittest.cc
@@ -11,6 +11,7 @@ #include "base/bind.h" #include "base/files/scoped_temp_dir.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/run_loop.h" #include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h" @@ -114,18 +115,24 @@ if (status != SYNC_STATUS_OK) return status; - // |app_root_list| must not own the resources here. Be sure to call - // weak_clear later. - ScopedVector<google_apis::FileResource> app_root_list; + // |app_root_list| must not own the resources here. Be sure to release + // ownership of all elements later. + // TODO(leonhsl) Need follow up: having two owners for a pointer is a + // dangerous pattern that we don't want to keep around. + std::vector<std::unique_ptr<google_apis::FileResource>> app_root_list; for (size_t i = 0; i < app_roots_count; ++i) { - app_root_list.push_back( - const_cast<google_apis::FileResource*>(app_roots[i])); + app_root_list.push_back(base::WrapUnique( + const_cast<google_apis::FileResource*>(app_roots[i]))); } status = database->PopulateInitialData( kInitialLargestChangeID, sync_root, app_root_list); - app_root_list.weak_clear(); + for_each(app_root_list.begin(), app_root_list.end(), + [](std::unique_ptr<google_apis::FileResource>& entry) { + entry.release(); + }); + app_root_list.clear(); return status; }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index a8261f1..db7302c 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1508,6 +1508,8 @@ "views/subtle_notification_view.h", "views/sync/bubble_sync_promo_view.cc", "views/sync/bubble_sync_promo_view.h", + "views/sync/profile_signin_confirmation_dialog_views.cc", + "views/sync/profile_signin_confirmation_dialog_views.h", "views/task_manager_view.cc", "views/task_manager_view.h", "views/website_settings/chosen_object_row.cc", @@ -1559,8 +1561,6 @@ "views/screen_capture_notification_ui_views.cc", "views/sync/one_click_signin_dialog_view.cc", "views/sync/one_click_signin_dialog_view.h", - "views/sync/profile_signin_confirmation_dialog_views.cc", - "views/sync/profile_signin_confirmation_dialog_views.h", ] }
diff --git a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.h b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.h index d23724f..a596b90 100644 --- a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.h +++ b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.h
@@ -38,16 +38,17 @@ content::WebContents* web_contents, Profile* profile, const std::string& username, - ui::ProfileSigninConfirmationDelegate* delegate, + std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate, bool offer_profile_creation); virtual ~ProfileSigninConfirmationDialogCocoa(); // Shows the dialog if needed. - static void Show(Browser* browser, - content::WebContents* web_contents, - Profile* profile, - const std::string& username, - ui::ProfileSigninConfirmationDelegate* delegate); + static void Show( + Browser* browser, + content::WebContents* web_contents, + Profile* profile, + const std::string& username, + std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate); // Closes the dialog, which deletes itself. void Close();
diff --git a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.mm b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.mm index dbd031b..eab52ff 100644 --- a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.mm +++ b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.mm
@@ -16,19 +16,15 @@ namespace { // static -void ShowDialog( - Browser* browser, - content::WebContents* web_contents, - Profile* profile, - const std::string& username, - ui::ProfileSigninConfirmationDelegate* delegate, - bool offer_profile_creation) { +void ShowDialog(Browser* browser, + content::WebContents* web_contents, + Profile* profile, + const std::string& username, + std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate, + bool offer_profile_creation) { // The dialog owns itself. - new ProfileSigninConfirmationDialogCocoa(browser, - web_contents, - profile, - username, - delegate, + new ProfileSigninConfirmationDialogCocoa(browser, web_contents, profile, + username, std::move(delegate), offer_profile_creation); } @@ -39,19 +35,18 @@ content::WebContents* web_contents, Profile* profile, const std::string& username, - ui::ProfileSigninConfirmationDelegate* delegate, + std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate, bool offer_profile_creation) { // Setup the dialog view controller. const base::Closure& closeDialogCallback = base::Bind(&ProfileSigninConfirmationDialogCocoa::Close, base::Unretained(this)); - controller_.reset( - [[ProfileSigninConfirmationViewController alloc] - initWithBrowser:browser - username:username - delegate:delegate - closeDialogCallback:closeDialogCallback - offerProfileCreation:offer_profile_creation]); + controller_.reset([[ProfileSigninConfirmationViewController alloc] + initWithBrowser:browser + username:username + delegate:std::move(delegate) + closeDialogCallback:closeDialogCallback + offerProfileCreation:offer_profile_creation]); // Setup the constrained window that will show the view. base::scoped_nsobject<NSWindow> window([[ConstrainedWindowCustomWindow alloc] @@ -71,10 +66,10 @@ content::WebContents* web_contents, Profile* profile, const std::string& username, - ui::ProfileSigninConfirmationDelegate* delegate) { + std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate) { ui::CheckShouldPromptForNewProfile( profile, base::Bind(ShowDialog, browser, web_contents, profile, username, - delegate)); + base::Passed(std::move(delegate)))); } void ProfileSigninConfirmationDialogCocoa::Close() {
diff --git a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller.h b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller.h index 2a70b08..8e4a35c 100644 --- a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller.h +++ b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_UI_COCOA_PROFILES_PROFILE_SIGNIN_CONFIRMATION_VIEW_CONTROLLER_ #import <Cocoa/Cocoa.h> +#include <memory> #include <string> #include "base/callback.h" @@ -33,7 +34,7 @@ bool offerProfileCreation_; // Dialog button callbacks. - ui::ProfileSigninConfirmationDelegate* delegate_; + std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate_; base::Closure closeDialogCallback_; // UI elements. @@ -48,10 +49,12 @@ } - (id)initWithBrowser:(Browser*)browser - username:(const std::string&)username - delegate:(ui::ProfileSigninConfirmationDelegate*)delegate - closeDialogCallback:(const base::Closure&)closeDialogCallback - offerProfileCreation:(bool)offer; + username:(const std::string&)username + delegate: + (std::unique_ptr<ui::ProfileSigninConfirmationDelegate>) + delegate + closeDialogCallback:(const base::Closure&)closeDialogCallback + offerProfileCreation:(bool)offer; - (IBAction)cancel:(id)sender; - (IBAction)ok:(id)sender; - (IBAction)close:(id)sender; @@ -59,12 +62,4 @@ @end -@interface ProfileSigninConfirmationViewController (TestingAPI) - -@property(readonly, nonatomic) ui::ProfileSigninConfirmationDelegate* delegate; -@property(readonly, nonatomic) NSButton* createProfileButton; -@property(readonly, nonatomic) NSTextView* explanationField; - -@end - #endif // CHROME_BROWSER_UI_COCOA_PROFILES_PROFILE_SIGNIN_CONFIRMATION_VIEW_CONTROLLER_
diff --git a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller.mm b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller.mm index 5a7480f..28f0873 100644 --- a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller.mm +++ b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller.mm
@@ -142,14 +142,16 @@ @implementation ProfileSigninConfirmationViewController - (id)initWithBrowser:(Browser*)browser - username:(const std::string&)username - delegate:(ui::ProfileSigninConfirmationDelegate*)delegate - closeDialogCallback:(const base::Closure&)closeDialogCallback - offerProfileCreation:(bool)offer { + username:(const std::string&)username + delegate: + (std::unique_ptr<ui::ProfileSigninConfirmationDelegate>) + delegate + closeDialogCallback:(const base::Closure&)closeDialogCallback + offerProfileCreation:(bool)offer { if ((self = [super initWithNibName:nil bundle:nil])) { browser_ = browser; username_ = username; - delegate_ = delegate; + delegate_ = std::move(delegate); closeDialogCallback_ = closeDialogCallback; offerProfileCreation_ = offer; } @@ -376,7 +378,7 @@ - (IBAction)cancel:(id)sender { if (delegate_) { delegate_->OnCancelSignin(); - delegate_ = NULL; + delegate_ = nullptr; closeDialogCallback_.Run(); } } @@ -384,7 +386,7 @@ - (IBAction)ok:(id)sender { if (delegate_) { delegate_->OnContinueSignin(); - delegate_ = NULL; + delegate_ = nullptr; closeDialogCallback_.Run(); } } @@ -392,7 +394,7 @@ - (IBAction)close:(id)sender { if (delegate_) { delegate_->OnCancelSignin(); - delegate_ = NULL; + delegate_ = nullptr; } closeDialogCallback_.Run(); } @@ -400,7 +402,7 @@ - (IBAction)createProfile:(id)sender { if (delegate_) { delegate_->OnSigninWithNewProfile(); - delegate_ = NULL; + delegate_ = nullptr; closeDialogCallback_.Run(); } } @@ -440,19 +442,3 @@ } @end - -@implementation ProfileSigninConfirmationViewController (TestingAPI) - -- (ui::ProfileSigninConfirmationDelegate*)delegate { - return delegate_; -} - -- (NSButton*)createProfileButton { - return createProfileButton_.get(); -} - -- (NSTextView*)explanationField { - return explanationField_.get(); -} - -@end
diff --git a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller_browsertest.mm b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller_browsertest.mm index 6380427..4311f676 100644 --- a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller_browsertest.mm +++ b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller_browsertest.mm
@@ -18,10 +18,32 @@ #import "testing/gtest_mac.h" #include "ui/base/l10n/l10n_util.h" -class ProfileSigninConfirmationViewControllerTest - : public InProcessBrowserTest, - public ui::ProfileSigninConfirmationDelegate { +@interface ProfileSigninConfirmationViewController (TestingAPI) +@property(readonly, nonatomic) ui::ProfileSigninConfirmationDelegate* delegate; +@property(readonly, nonatomic) NSButton* createProfileButton; +@property(readonly, nonatomic) NSTextView* explanationField; + +@end + +@implementation ProfileSigninConfirmationViewController (TestingAPI) + +- (ui::ProfileSigninConfirmationDelegate*)delegate { + return delegate_.get(); +} + +- (NSButton*)createProfileButton { + return createProfileButton_.get(); +} + +- (NSTextView*)explanationField { + return explanationField_.get(); +} + +@end + +class ProfileSigninConfirmationViewControllerTest + : public InProcessBrowserTest { public: ProfileSigninConfirmationViewControllerTest() : window_(nil), @@ -44,11 +66,11 @@ &ProfileSigninConfirmationViewControllerTest::OnClose, base::Unretained(this)); controller_.reset([[ProfileSigninConfirmationViewController alloc] - initWithBrowser:browser() - username:username() - delegate:this - closeDialogCallback:close - offerProfileCreation:offerProfileCreation]); + initWithBrowser:browser() + username:username() + delegate:base::MakeUnique<TestSigninDelegate>(this) + closeDialogCallback:close + offerProfileCreation:offerProfileCreation]); [[window_ contentView] addSubview:[controller_ view]]; [window_ makeKeyAndOrderFront:NSApp]; ASSERT_TRUE([window_ isVisible]); @@ -63,10 +85,6 @@ IDS_ENTERPRISE_SIGNIN_PROFILE_LINK_LEARN_MORE); } - // ui::ProfileSigninConfirmationDelegate: - void OnContinueSignin() override { continued_ = true; } - void OnCancelSignin() override { cancelled_ = true; } - void OnSigninWithNewProfile() override { created_ = true; } void OnClose() { closed_ = true; } // The window containing the dialog. @@ -82,6 +100,23 @@ bool closed_; private: + class TestSigninDelegate : public ui::ProfileSigninConfirmationDelegate { + public: + explicit TestSigninDelegate( + ProfileSigninConfirmationViewControllerTest* client) + : client_(client) {} + + // ui::ProfileSigninConfirmationDelegate: + void OnContinueSignin() override { client_->continued_ = true; } + void OnCancelSignin() override { client_->cancelled_ = true; } + void OnSigninWithNewProfile() override { client_->created_ = true; } + + private: + ProfileSigninConfirmationViewControllerTest* client_; + + DISALLOW_COPY_AND_ASSIGN(TestSigninDelegate); + }; + DISALLOW_COPY_AND_ASSIGN(ProfileSigninConfirmationViewControllerTest); };
diff --git a/chrome/browser/ui/cocoa/tab_dialogs_cocoa.h b/chrome/browser/ui/cocoa/tab_dialogs_cocoa.h index 1eb2bd5..4d81b16 100644 --- a/chrome/browser/ui/cocoa/tab_dialogs_cocoa.h +++ b/chrome/browser/ui/cocoa/tab_dialogs_cocoa.h
@@ -24,7 +24,7 @@ Browser* browser, Profile* profile, const std::string& username, - ui::ProfileSigninConfirmationDelegate* delegate) override; + std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate) override; void ShowManagePasswordsBubble(bool user_action) override; void HideManagePasswordsBubble() override; base::WeakPtr<ValidationMessageBubble> ShowValidationMessage(
diff --git a/chrome/browser/ui/cocoa/tab_dialogs_cocoa.mm b/chrome/browser/ui/cocoa/tab_dialogs_cocoa.mm index bc20ecf..a66b2ee 100644 --- a/chrome/browser/ui/cocoa/tab_dialogs_cocoa.mm +++ b/chrome/browser/ui/cocoa/tab_dialogs_cocoa.mm
@@ -11,6 +11,7 @@ #import "chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.h" #include "chrome/browser/ui/cocoa/tab_dialogs_views_mac.h" #import "chrome/browser/ui/cocoa/validation_message_bubble_cocoa.h" +#include "chrome/browser/ui/sync/profile_signin_confirmation_helper.h" #include "content/public/browser/web_contents.h" #include "ui/base/material_design/material_design_controller.h" @@ -64,9 +65,9 @@ Browser* browser, Profile* profile, const std::string& username, - ui::ProfileSigninConfirmationDelegate* delegate) { - ProfileSigninConfirmationDialogCocoa::Show( - browser, web_contents_, profile, username, delegate); + std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate) { + ProfileSigninConfirmationDialogCocoa::Show(browser, web_contents_, profile, + username, std::move(delegate)); } void TabDialogsCocoa::ShowManagePasswordsBubble(bool user_action) {
diff --git a/chrome/browser/ui/cocoa/tab_dialogs_views_mac.h b/chrome/browser/ui/cocoa/tab_dialogs_views_mac.h index 622777c..980201b 100644 --- a/chrome/browser/ui/cocoa/tab_dialogs_views_mac.h +++ b/chrome/browser/ui/cocoa/tab_dialogs_views_mac.h
@@ -15,6 +15,11 @@ // TabDialogs: void ShowCollectedCookies() override; + void ShowProfileSigninConfirmation( + Browser* browser, + Profile* profile, + const std::string& username, + std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate) override; private: DISALLOW_COPY_AND_ASSIGN(TabDialogsViewsMac);
diff --git a/chrome/browser/ui/cocoa/tab_dialogs_views_mac.mm b/chrome/browser/ui/cocoa/tab_dialogs_views_mac.mm index 6187e48..d71c1f2 100644 --- a/chrome/browser/ui/cocoa/tab_dialogs_views_mac.mm +++ b/chrome/browser/ui/cocoa/tab_dialogs_views_mac.mm
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/cocoa/tab_dialogs_views_mac.h" #include "chrome/browser/ui/views/collected_cookies_views.h" +#include "chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h" TabDialogsViewsMac::TabDialogsViewsMac(content::WebContents* contents) : TabDialogsCocoa(contents) {} @@ -15,3 +16,12 @@ // Deletes itself on close. new CollectedCookiesViews(web_contents()); } + +void TabDialogsViewsMac::ShowProfileSigninConfirmation( + Browser* browser, + Profile* profile, + const std::string& username, + std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate) { + ProfileSigninConfirmationDialogViews::ShowDialog(browser, profile, username, + std::move(delegate)); +}
diff --git a/chrome/browser/ui/collected_cookies_browsertest.cc b/chrome/browser/ui/collected_cookies_browsertest.cc index 0316265..e946733 100644 --- a/chrome/browser/ui/collected_cookies_browsertest.cc +++ b/chrome/browser/ui/collected_cookies_browsertest.cc
@@ -22,7 +22,7 @@ public: CollectedCookiesTest() {} - // TestDialogInterface: + // DialogBrowserTest: void ShowDialog(const std::string& name) override { ASSERT_TRUE(embedded_test_server()->Start());
diff --git a/chrome/browser/ui/libgtkui/gtk_util.cc b/chrome/browser/ui/libgtkui/gtk_util.cc index 56f565b9..9ecf876 100644 --- a/chrome/browser/ui/libgtkui/gtk_util.cc +++ b/chrome/browser/ui/libgtkui/gtk_util.cc
@@ -372,8 +372,11 @@ "border-radius: 0px;" "border-width: 0px;" "border-image-width: 0px;" + "box-shadow: none;" "padding: 0px;" "margin: 0px;" + "outline: none;" + "outline-width: 0px;" "}"); ApplyCssToContext(context, provider); } @@ -384,8 +387,11 @@ "border-style: solid;" "border-radius: 0px;" "border-width: 1px;" + "box-shadow: none;" "padding: 0px;" "margin: 0px;" + "outline: none;" + "outline-width: 0px;" "}"); ApplyCssToContext(context, provider); }
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc index 75b3376..672c4c3 100644 --- a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc +++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
@@ -242,11 +242,11 @@ content::RecordAction( base::UserMetricsAction("Signin_Show_EnterpriseAccountPrompt")); - TabDialogs::FromWebContents(web_contents)->ShowProfileSigninConfirmation( - browser_, - profile_, - signin->GetUsernameForAuthInProgress(), - new SigninDialogDelegate(weak_pointer_factory_.GetWeakPtr())); + TabDialogs::FromWebContents(web_contents) + ->ShowProfileSigninConfirmation(browser_, profile_, + signin->GetUsernameForAuthInProgress(), + base::MakeUnique<SigninDialogDelegate>( + weak_pointer_factory_.GetWeakPtr())); } void OneClickSigninSyncStarter::LoadPolicyWithCachedCredentials() {
diff --git a/chrome/browser/ui/tab_dialogs.h b/chrome/browser/ui/tab_dialogs.h index ca3fec18b..41ac3c1 100644 --- a/chrome/browser/ui/tab_dialogs.h +++ b/chrome/browser/ui/tab_dialogs.h
@@ -59,7 +59,7 @@ Browser* browser, Profile* profile, const std::string& username, - ui::ProfileSigninConfirmationDelegate* delegate) = 0; + std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate) = 0; // Shows or hides the ManagePasswords bubble. // Pass true for |user_action| if this is a user initiated action.
diff --git a/chrome/browser/ui/test/test_browser_dialog.cc b/chrome/browser/ui/test/test_browser_dialog.cc index 5faa2fa..18099e7 100644 --- a/chrome/browser/ui/test/test_browser_dialog.cc +++ b/chrome/browser/ui/test/test_browser_dialog.cc
@@ -88,11 +88,11 @@ gfx::NativeView parent = platform_util::GetViewForWindow(DialogParent()); views::Widget::Widgets widgets_before; - views::Widget::GetAllChildWidgets(parent, &widgets_before); + views::Widget::GetAllOwnedWidgets(parent, &widgets_before); ShowDialog(NameFromTestCase()); views::Widget::Widgets widgets_after; - views::Widget::GetAllChildWidgets(parent, &widgets_after); + views::Widget::GetAllOwnedWidgets(parent, &widgets_after); auto added = base::STLSetDifference<std::vector<views::Widget*>>( widgets_after, widgets_before);
diff --git a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc index 1ee37be..774b6095 100644 --- a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc +++ b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc
@@ -13,7 +13,6 @@ #include "chrome/browser/ui/browser_navigator.h" #include "chrome/browser/ui/browser_navigator_params.h" #include "chrome/browser/ui/browser_window.h" -#include "chrome/browser/ui/views/profiles/profile_chooser_view.h" #include "chrome/grit/chromium_strings.h" #include "chrome/grit/generated_resources.h" #include "components/constrained_window/constrained_window_views.h" @@ -22,6 +21,7 @@ #include "google_apis/gaia/gaia_auth_util.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/base/ui_features.h" #include "ui/gfx/font.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/range/range.h" @@ -36,13 +36,17 @@ #include "ui/views/widget/widget.h" #include "ui/views/window/dialog_client_view.h" +#if !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER) +#include "chrome/browser/ui/views/profiles/profile_chooser_view.h" +#endif + ProfileSigninConfirmationDialogViews::ProfileSigninConfirmationDialogViews( Browser* browser, const std::string& username, - ui::ProfileSigninConfirmationDelegate* delegate) + std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate) : browser_(browser), username_(username), - delegate_(delegate), + delegate_(std::move(delegate)), prompt_for_new_profile_(true) {} ProfileSigninConfirmationDialogViews::~ProfileSigninConfirmationDialogViews() {} @@ -52,7 +56,8 @@ Browser* browser, Profile* profile, const std::string& username, - ui::ProfileSigninConfirmationDelegate* delegate) { + std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate) { +#if !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER) // Hides the new avatar bubble if it is currently shown. The new avatar bubble // should be automatically closed when it loses focus. However on windows the // profile signin confirmation dialog is not modal yet thus it does not take @@ -61,10 +66,11 @@ // TODO(guohui): removes the workaround once the profile confirmation dialog // is fixed. ProfileChooserView::Hide(); +#endif ProfileSigninConfirmationDialogViews* dialog = - new ProfileSigninConfirmationDialogViews( - browser, username, delegate); + new ProfileSigninConfirmationDialogViews(browser, username, + std::move(delegate)); ui::CheckShouldPromptForNewProfile( profile, // This callback is guaranteed to be invoked, and once it is, the dialog @@ -117,7 +123,7 @@ delegate_->OnSigninWithNewProfile(); else delegate_->OnContinueSignin(); - delegate_ = NULL; + delegate_ = nullptr; } return true; } @@ -125,7 +131,7 @@ bool ProfileSigninConfirmationDialogViews::Cancel() { if (delegate_) { delegate_->OnCancelSignin(); - delegate_ = NULL; + delegate_ = nullptr; } return true; } @@ -246,7 +252,7 @@ DCHECK(prompt_for_new_profile_); if (delegate_) { delegate_->OnContinueSignin(); - delegate_ = NULL; + delegate_ = nullptr; } GetWidget()->Close(); }
diff --git a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h index ffa5f579..a466abd 100644 --- a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h +++ b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h
@@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_UI_VIEWS_SYNC_PROFILE_SIGNIN_CONFIRMATION_DIALOG_VIEWS_H_ #define CHROME_BROWSER_UI_VIEWS_SYNC_PROFILE_SIGNIN_CONFIRMATION_DIALOG_VIEWS_H_ +#include <memory> + #include "base/compiler_specific.h" #include "base/macros.h" #include "chrome/browser/ui/sync/profile_signin_confirmation_helper.h" @@ -23,16 +25,17 @@ public views::ButtonListener { public: // Create and show the dialog, which owns itself. - static void ShowDialog(Browser* browser, - Profile* profile, - const std::string& username, - ui::ProfileSigninConfirmationDelegate* delegate); + static void ShowDialog( + Browser* browser, + Profile* profile, + const std::string& username, + std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate); private: ProfileSigninConfirmationDialogViews( Browser* browser, const std::string& username, - ui::ProfileSigninConfirmationDelegate* delegate); + std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate); ~ProfileSigninConfirmationDialogViews() override; // views::DialogDelegateView: @@ -69,7 +72,7 @@ std::string username_; // Dialog button handler. - ui::ProfileSigninConfirmationDelegate* delegate_; + std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate_; // Whether the user should be prompted to create a new profile. bool prompt_for_new_profile_;
diff --git a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views_browsertest.cc b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views_browsertest.cc new file mode 100644 index 0000000..0837f0e --- /dev/null +++ b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views_browsertest.cc
@@ -0,0 +1,73 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h" + +#include "base/command_line.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/bookmarks/bookmark_model_factory.h" +#include "chrome/browser/ui/sync/profile_signin_confirmation_helper.h" +#include "chrome/browser/ui/tab_dialogs.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/browser/ui/test/test_browser_dialog.h" +#include "components/bookmarks/browser/bookmark_model.h" +#include "ui/base/ui_base_switches.h" + +namespace { + +// Test delegate passed to the confirmation dialog to report back the result. +class TestSigninDialogDelegate : public ui::ProfileSigninConfirmationDelegate { + public: + TestSigninDialogDelegate() {} + virtual ~TestSigninDialogDelegate() {} + + void OnCancelSignin() override {} + void OnContinueSignin() override {} + void OnSigninWithNewProfile() override {} + + private: + DISALLOW_COPY_AND_ASSIGN(TestSigninDialogDelegate); +}; + +} // namespace + +class ProfileSigninConfirmationDialogTest : public DialogBrowserTest { + public: + ProfileSigninConfirmationDialogTest() {} + + // content::BrowserTestBase: + void SetUpCommandLine(base::CommandLine* command_line) override { + command_line->AppendSwitch(switches::kExtendMdToSecondaryUi); + } + + // DialogBrowserTest: + void ShowDialog(const std::string& name) override { + Profile* profile = browser()->profile(); + + // Add a bookmark to ensure CheckShouldPromptForNewProfile() returns true. + bookmarks::BookmarkModel* bookmarks = + BookmarkModelFactory::GetForBrowserContext(profile); + bookmarks->AddURL(bookmarks->bookmark_bar_node(), 0, + base::ASCIIToUTF16("title"), + GURL("http://www.example.com")); + + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + TabDialogs::FromWebContents(web_contents) + ->ShowProfileSigninConfirmation( + browser(), profile, "username@example.com", + base::MakeUnique<TestSigninDialogDelegate>()); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ProfileSigninConfirmationDialogTest); +}; + +// Test that calls ShowDialog("default"). Interactive when run via +// browser_tests --gtest_filter=BrowserDialogTest.Invoke --interactive +// --dialog=ProfileSigninConfirmationDialogTest.InvokeDialog_default +IN_PROC_BROWSER_TEST_F(ProfileSigninConfirmationDialogTest, + InvokeDialog_default) { + RunDialog(); +}
diff --git a/chrome/browser/ui/views/tab_dialogs_views.cc b/chrome/browser/ui/views/tab_dialogs_views.cc index 46177c1..fa36944f 100644 --- a/chrome/browser/ui/views/tab_dialogs_views.cc +++ b/chrome/browser/ui/views/tab_dialogs_views.cc
@@ -53,10 +53,10 @@ Browser* browser, Profile* profile, const std::string& username, - ui::ProfileSigninConfirmationDelegate* delegate) { + std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate) { #if !defined(OS_CHROMEOS) - ProfileSigninConfirmationDialogViews::ShowDialog( - browser, profile, username, delegate); + ProfileSigninConfirmationDialogViews::ShowDialog(browser, profile, username, + std::move(delegate)); #else NOTREACHED(); #endif
diff --git a/chrome/browser/ui/views/tab_dialogs_views.h b/chrome/browser/ui/views/tab_dialogs_views.h index 83f4e473..c1bc6fc 100644 --- a/chrome/browser/ui/views/tab_dialogs_views.h +++ b/chrome/browser/ui/views/tab_dialogs_views.h
@@ -24,7 +24,7 @@ Browser* browser, Profile* profile, const std::string& username, - ui::ProfileSigninConfirmationDelegate* delegate) override; + std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate) override; void ShowManagePasswordsBubble(bool user_action) override; void HideManagePasswordsBubble() override; base::WeakPtr<ValidationMessageBubble> ShowValidationMessage(
diff --git a/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc b/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc index 71f4295..6aa065b 100644 --- a/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc +++ b/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc
@@ -353,7 +353,7 @@ base::ListValue* items = new base::ListValue(); for (size_t i = 0; i < parsed_app_list->items().size(); ++i) { - const google_apis::AppResource* app = parsed_app_list->items()[i]; + const google_apis::AppResource* app = parsed_app_list->items()[i].get(); auto app_data = base::MakeUnique<base::DictionaryValue>(); app_data->SetString("name", app->name()); app_data->SetString("application_id", app->application_id());
diff --git a/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.cc index cf2aa27b..925b0ba 100644 --- a/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.cc
@@ -12,7 +12,7 @@ #include "chrome/browser/chromeos/login/helper.h" #include "chrome/browser/chromeos/login/oobe_screen.h" #include "chrome/browser/chromeos/login/screens/core_oobe_actor.h" -#include "chrome/browser/chromeos/login/screens/eula_model.h" +#include "chrome/browser/chromeos/login/screens/eula_screen.h" #include "chrome/browser/chromeos/login/ui/login_web_dialog.h" #include "chrome/browser/chromeos/login/ui/webui_login_display.h" #include "chrome/browser/profiles/profile.h" @@ -84,14 +84,12 @@ EulaScreenHandler::EulaScreenHandler(CoreOobeActor* core_oobe_actor) : BaseScreenHandler(kJsScreenPath), - model_(NULL), - core_oobe_actor_(core_oobe_actor), - show_on_init_(false) { + core_oobe_actor_(core_oobe_actor) { } EulaScreenHandler::~EulaScreenHandler() { - if (model_) - model_->OnViewDestroyed(this); + if (screen_) + screen_->OnViewDestroyed(this); } void EulaScreenHandler::Show() { @@ -105,15 +103,15 @@ void EulaScreenHandler::Hide() { } -void EulaScreenHandler::Bind(EulaModel& model) { - model_ = &model; - BaseScreenHandler::SetBaseScreen(model_); +void EulaScreenHandler::Bind(EulaScreen* screen) { + screen_ = screen; + BaseScreenHandler::SetBaseScreen(screen_); if (page_is_ready()) Initialize(); } void EulaScreenHandler::Unbind() { - model_ = nullptr; + screen_ = nullptr; BaseScreenHandler::SetBaseScreen(nullptr); } @@ -170,14 +168,14 @@ } void EulaScreenHandler::Initialize() { - if (!page_is_ready() || !model_) + if (!page_is_ready() || !screen_) return; - core_oobe_actor_->SetUsageStats(model_->IsUsageStatsEnabled()); + core_oobe_actor_->SetUsageStats(screen_->IsUsageStatsEnabled()); // This OEM EULA is a file:// URL which we're unable to load in iframe. // Instead if it's defined we use chrome://terms/oem that will load same file. - if (!model_->GetOemEulaUrl().is_empty()) + if (!screen_->GetOemEulaUrl().is_empty()) core_oobe_actor_->SetOemEulaUrl(chrome::kChromeUITermsOemURL); if (show_on_init_) { @@ -215,8 +213,8 @@ } void EulaScreenHandler::HandleOnInstallationSettingsPopupOpened() { - if (model_) - model_->InitiatePasswordFetch(); + if (screen_) + screen_->InitiatePasswordFetch(); } } // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h index b09cae9..a2031ea 100644 --- a/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h
@@ -34,7 +34,7 @@ // EulaView implementation: void Show() override; void Hide() override; - void Bind(EulaModel& model) override; + void Bind(EulaScreen* screen) override; void Unbind() override; void OnPasswordFetched(const std::string& tpm_password) override; @@ -52,14 +52,14 @@ void HandleOnChromeOSCredits(); void HandleOnInstallationSettingsPopupOpened(); - EulaModel* model_; - CoreOobeActor* core_oobe_actor_; + EulaScreen* screen_ = nullptr; + CoreOobeActor* core_oobe_actor_ = nullptr; // Help application used for help dialogs. scoped_refptr<HelpAppLauncher> help_app_; // Keeps whether screen should be shown right after initialization. - bool show_on_init_; + bool show_on_init_ = false; DISALLOW_COPY_AND_ASSIGN(EulaScreenHandler); };
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 00ea574..f7c7431c 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -2119,6 +2119,7 @@ "../browser/ui/views/frame/browser_non_client_frame_view_browsertest_win.cc", "../browser/ui/views/frame/browser_window_property_manager_browsertest_win.cc", "../browser/ui/views/select_file_dialog_extension_browsertest.cc", + "../browser/ui/views/sync/profile_signin_confirmation_dialog_views_browsertest.cc", ] deps += [ "//ui/views" ] if (!is_chromeos && (!is_mac || mac_views_browser)) { @@ -2349,6 +2350,7 @@ "../browser/service_process/service_process_control_browsertest.cc", # inline login UI is disabled on chromeos + "../browser/ui/views/sync/profile_signin_confirmation_dialog_views_browsertest.cc", "../browser/ui/webui/signin/inline_login_ui_browsertest.cc", # chromeos does not use the desktop user manager
diff --git a/chrome/test/data/webui/settings/site_list_tests.js b/chrome/test/data/webui/settings/site_list_tests.js index a8e60e97..95bb6b6 100644 --- a/chrome/test/data/webui/settings/site_list_tests.js +++ b/chrome/test/data/webui/settings/site_list_tests.js
@@ -462,6 +462,28 @@ }); }); + test('action menu closes when list changes', function() { + setUpCategory(settings.ContentSettingsTypes.GEOLOCATION, + settings.PermissionValues.ALLOW, prefs); + var actionMenu = testElement.$$('dialog[is=cr-action-menu]'); + return browserProxy.whenCalled('getExceptionList').then( + function(contentType) { + Polymer.dom.flush(); // Populates action menu. + openActionMenu(0); + assertTrue(actionMenu.open); + + browserProxy.resetResolver('getExceptionList'); + // Simulate a change in the underlying model. + cr.webUIListenerCallback( + 'contentSettingSitePermissionChanged', + settings.ContentSettingsTypes.GEOLOCATION); + return browserProxy.whenCalled('getExceptionList'); + }).then(function() { + // Check that the action menu was closed. + assertFalse(actionMenu.open); + }); + }); + test('exceptions are not reordered in non-ALL_SITES', function() { setUpCategory(settings.ContentSettingsTypes.GEOLOCATION, settings.PermissionValues.BLOCK, prefsMixedProvider);
diff --git a/components/domain_reliability/beacon.cc b/components/domain_reliability/beacon.cc index 8c51e8fb..8a8a549f 100644 --- a/components/domain_reliability/beacon.cc +++ b/components/domain_reliability/beacon.cc
@@ -24,7 +24,7 @@ base::TimeTicks upload_time, base::TimeTicks last_network_change_time, const GURL& collector_url, - const ScopedVector<std::string>& path_prefixes) const { + const std::vector<std::unique_ptr<std::string>>& path_prefixes) const { std::unique_ptr<DictionaryValue> beacon_value(new DictionaryValue()); DCHECK(url.is_valid()); GURL sanitized_url = SanitizeURLForReport(url, collector_url, path_prefixes);
diff --git a/components/domain_reliability/beacon.h b/components/domain_reliability/beacon.h index 2162b58f..8d352b9 100644 --- a/components/domain_reliability/beacon.h +++ b/components/domain_reliability/beacon.h
@@ -8,7 +8,6 @@ #include <memory> #include <string> -#include "base/memory/scoped_vector.h" #include "base/time/time.h" #include "components/domain_reliability/domain_reliability_export.h" #include "net/base/net_error_details.h" @@ -40,7 +39,7 @@ base::TimeTicks upload_time, base::TimeTicks last_network_change_time, const GURL& collector_url, - const ScopedVector<std::string>& path_prefixes) const; + const std::vector<std::unique_ptr<std::string>>& path_prefixes) const; // The URL that the beacon is reporting on, if included. GURL url;
diff --git a/components/domain_reliability/config.cc b/components/domain_reliability/config.cc index 765e0fa4..21c93cc1 100644 --- a/components/domain_reliability/config.cc +++ b/components/domain_reliability/config.cc
@@ -13,7 +13,6 @@ #include <utility> #include "base/json/json_reader.h" -#include "base/json/json_value_converter.h" #include "base/profiler/scoped_tracker.h" #include "base/strings/pattern.h" #include "base/strings/string_util.h" @@ -70,7 +69,7 @@ return false; } - for (const auto* url : collectors) { + for (const auto& url : collectors) { if (!url->is_valid()) return false; }
diff --git a/components/domain_reliability/config.h b/components/domain_reliability/config.h index 533d891..9f4ebb0 100644 --- a/components/domain_reliability/config.h +++ b/components/domain_reliability/config.h
@@ -42,11 +42,11 @@ GURL origin; bool include_subdomains; - ScopedVector<GURL> collectors; + std::vector<std::unique_ptr<GURL>> collectors; double success_sample_rate; double failure_sample_rate; - ScopedVector<std::string> path_prefixes; + std::vector<std::unique_ptr<std::string>> path_prefixes; private: DISALLOW_COPY_AND_ASSIGN(DomainReliabilityConfig);
diff --git a/components/domain_reliability/config_unittest.cc b/components/domain_reliability/config_unittest.cc index d8c7f6d..be701b0 100644 --- a/components/domain_reliability/config_unittest.cc +++ b/components/domain_reliability/config_unittest.cc
@@ -7,6 +7,7 @@ #include <memory> #include <string> +#include "base/memory/ptr_util.h" #include "base/time/time.h" #include "testing/gtest/include/gtest/gtest.h" @@ -17,7 +18,8 @@ DomainReliabilityConfig* config = new DomainReliabilityConfig(); config->origin = GURL("https://example/"); config->include_subdomains = false; - config->collectors.push_back(new GURL("https://example/upload")); + config->collectors.push_back( + base::MakeUnique<GURL>("https://example/upload")); config->failure_sample_rate = 1.0; config->success_sample_rate = 0.0; EXPECT_TRUE(config->IsValid()); @@ -26,8 +28,8 @@ std::unique_ptr<DomainReliabilityConfig> MakeSampleConfig() { std::unique_ptr<DomainReliabilityConfig> config(MakeBaseConfig()); - config->path_prefixes.push_back(new std::string("/css/")); - config->path_prefixes.push_back(new std::string("/js/")); + config->path_prefixes.push_back(base::MakeUnique<std::string>("/css/")); + config->path_prefixes.push_back(base::MakeUnique<std::string>("/js/")); EXPECT_TRUE(config->IsValid()); return config; } @@ -49,8 +51,7 @@ EXPECT_FALSE(config->IsValid()); config = MakeSampleConfig(); - delete config->collectors[0]; - config->collectors[0] = new GURL(); + config->collectors[0] = base::MakeUnique<GURL>(); EXPECT_FALSE(config->IsValid()); config = MakeSampleConfig();
diff --git a/components/domain_reliability/google_configs.cc b/components/domain_reliability/google_configs.cc index 00f55d22..d61c9c2c 100644 --- a/components/domain_reliability/google_configs.cc +++ b/components/domain_reliability/google_configs.cc
@@ -551,10 +551,11 @@ GURL::Replacements replacements; replacements.SetPathStr(kGoogleOriginSpecificCollectorPathString); config->collectors.push_back( - new GURL(config->origin.ReplaceComponents(replacements))); + base::MakeUnique<GURL>(config->origin.ReplaceComponents(replacements))); } for (size_t i = 0; i < arraysize(kGoogleStandardCollectors); i++) - config->collectors.push_back(new GURL(kGoogleStandardCollectors[i])); + config->collectors.push_back( + base::MakeUnique<GURL>(kGoogleStandardCollectors[i])); config->success_sample_rate = 0.05; config->failure_sample_rate = 1.00; config->path_prefixes.clear();
diff --git a/components/domain_reliability/header.cc b/components/domain_reliability/header.cc index 1e9cb6a..05a6379 100644 --- a/components/domain_reliability/header.cc +++ b/components/domain_reliability/header.cc
@@ -7,7 +7,6 @@ #include <stdint.h> #include <string> - #include "base/memory/ptr_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_tokenizer.h" @@ -158,7 +157,7 @@ } bool ParseReportUri(const std::vector<base::StringPiece> in, - ScopedVector<GURL>* out) { + std::vector<std::unique_ptr<GURL>>* out) { if (in.size() < 1u) return false; @@ -170,7 +169,7 @@ GURL url(unquoted); if (!url.is_valid() || !content::IsOriginSecure(url)) return false; - out->push_back(new GURL(url)); + out->push_back(base::MakeUnique<GURL>(url)); } return true; @@ -201,7 +200,7 @@ // static std::unique_ptr<DomainReliabilityHeader> DomainReliabilityHeader::Parse( base::StringPiece value) { - ScopedVector<GURL> report_uri; + std::vector<std::unique_ptr<GURL>> report_uri; base::TimeDelta max_age; bool include_subdomains = false; @@ -284,7 +283,7 @@ DCHECK_EQ(0, max_age_s); } else { string += "report-uri="; - for (const auto* uri : config_->collectors) + for (const auto& uri : config_->collectors) string += uri->spec() + " "; // Remove trailing space. string.erase(string.length() - 1, 1);
diff --git a/components/domain_reliability/header_unittest.cc b/components/domain_reliability/header_unittest.cc index 0ba21c3..cbb0b1f 100644 --- a/components/domain_reliability/header_unittest.cc +++ b/components/domain_reliability/header_unittest.cc
@@ -28,8 +28,9 @@ std::unique_ptr<DomainReliabilityHeader> parsed_; }; -bool CheckReportUris(const char* pipe_separated_expected_report_uris, - const ScopedVector<GURL>& actual_report_uris) { +bool CheckReportUris( + const char* pipe_separated_expected_report_uris, + const std::vector<std::unique_ptr<GURL>>& actual_report_uris) { if (!pipe_separated_expected_report_uris) return actual_report_uris.empty();
diff --git a/components/domain_reliability/test_util.cc b/components/domain_reliability/test_util.cc index bb060fa0..5bfbb2e 100644 --- a/components/domain_reliability/test_util.cc +++ b/components/domain_reliability/test_util.cc
@@ -6,6 +6,7 @@ #include "base/bind.h" #include "base/callback.h" +#include "base/memory/ptr_util.h" #include "components/domain_reliability/scheduler.h" #include "net/url_request/url_request_status.h" #include "testing/gtest/include/gtest/gtest.h" @@ -169,7 +170,8 @@ const GURL& origin) { DomainReliabilityConfig* config = new DomainReliabilityConfig(); config->origin = origin; - config->collectors.push_back(new GURL("https://exampleuploader/upload")); + config->collectors.push_back( + base::MakeUnique<GURL>("https://exampleuploader/upload")); config->failure_sample_rate = 1.0; config->success_sample_rate = 0.0;
diff --git a/components/domain_reliability/util.cc b/components/domain_reliability/util.cc index f4af66913..20bf756 100644 --- a/components/domain_reliability/util.cc +++ b/components/domain_reliability/util.cc
@@ -170,22 +170,23 @@ return; } -// N.B. This uses a ScopedVector because that's what JSONValueConverter uses -// for repeated fields of any type, and Config uses JSONValueConverter to parse -// JSON configs. -GURL SanitizeURLForReport(const GURL& beacon_url, - const GURL& collector_url, - const ScopedVector<std::string>& path_prefixes) { +// N.B. This uses a std::vector<std::unique_ptr<>> because that's what +// JSONValueConverter uses for repeated fields of any type, and Config uses +// JSONValueConverter to parse JSON configs. +GURL SanitizeURLForReport( + const GURL& beacon_url, + const GURL& collector_url, + const std::vector<std::unique_ptr<std::string>>& path_prefixes) { if (CanReportFullBeaconURLToCollector(beacon_url, collector_url)) return beacon_url.GetAsReferrer(); std::string path = beacon_url.path(); const std::string empty_path; const std::string* longest_path_prefix = &empty_path; - for (const std::string* path_prefix : path_prefixes) { + for (const auto& path_prefix : path_prefixes) { if (path.substr(0, path_prefix->length()) == *path_prefix && path_prefix->length() > longest_path_prefix->length()) { - longest_path_prefix = path_prefix; + longest_path_prefix = path_prefix.get(); } }
diff --git a/components/domain_reliability/util.h b/components/domain_reliability/util.h index f8bb2040..3ef2e75 100644 --- a/components/domain_reliability/util.h +++ b/components/domain_reliability/util.h
@@ -11,7 +11,6 @@ #include "base/callback_forward.h" #include "base/compiler_specific.h" #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "base/time/clock.h" #include "base/time/tick_clock.h" #include "base/time/time.h" @@ -51,9 +50,10 @@ base::TimeDelta retry_after, DomainReliabilityUploader::UploadResult* result); -GURL SanitizeURLForReport(const GURL& beacon_url, - const GURL& collector_url, - const ScopedVector<std::string>& path_prefixes); +GURL SanitizeURLForReport( + const GURL& beacon_url, + const GURL& collector_url, + const std::vector<std::unique_ptr<std::string>>& path_prefixes); // Mockable wrapper around TimeTicks::Now and Timer. Mock version is in // test_util.h.
diff --git a/components/drive/chromeos/change_list_processor.cc b/components/drive/chromeos/change_list_processor.cc index ab2f3bd..833b64f 100644 --- a/components/drive/chromeos/change_list_processor.cc +++ b/components/drive/chromeos/change_list_processor.cc
@@ -5,7 +5,10 @@ #include "components/drive/chromeos/change_list_processor.h" #include <stddef.h> + +#include <memory> #include <utility> +#include <vector> #include "base/metrics/histogram.h" #include "base/strings/string_number_conversions.h" @@ -71,7 +74,8 @@ ChangeList::ChangeList(const google_apis::ChangeList& change_list) : next_url_(change_list.next_link()), largest_changestamp_(change_list.largest_change_id()) { - const ScopedVector<google_apis::ChangeResource>& items = change_list.items(); + const std::vector<std::unique_ptr<google_apis::ChangeResource>>& items = + change_list.items(); entries_.resize(items.size()); parent_resource_ids_.resize(items.size()); size_t entries_index = 0; @@ -90,7 +94,8 @@ ChangeList::ChangeList(const google_apis::FileList& file_list) : next_url_(file_list.next_link()), largest_changestamp_(0) { - const ScopedVector<google_apis::FileResource>& items = file_list.items(); + const std::vector<std::unique_ptr<google_apis::FileResource>>& items = + file_list.items(); entries_.resize(items.size()); parent_resource_ids_.resize(items.size()); size_t entries_index = 0;
diff --git a/components/drive/chromeos/fake_file_system.cc b/components/drive/chromeos/fake_file_system.cc index a7ef97f..69b7a28 100644 --- a/components/drive/chromeos/fake_file_system.cc +++ b/components/drive/chromeos/fake_file_system.cc
@@ -5,7 +5,10 @@ #include "components/drive/chromeos/fake_file_system.h" #include <stddef.h> + +#include <memory> #include <utility> +#include <vector> #include "base/bind.h" #include "base/bind_helpers.h" @@ -404,7 +407,8 @@ } DCHECK(file_list); - const ScopedVector<google_apis::FileResource>& entries = file_list->items(); + const std::vector<std::unique_ptr<google_apis::FileResource>>& entries = + file_list->items(); for (size_t i = 0; i < entries.size(); ++i) { std::unique_ptr<ResourceEntry> entry(new ResourceEntry); std::string parent_resource_id;
diff --git a/components/drive/chromeos/file_system/search_operation.cc b/components/drive/chromeos/file_system/search_operation.cc index a2608c3..e2005caf 100644 --- a/components/drive/chromeos/file_system/search_operation.cc +++ b/components/drive/chromeos/file_system/search_operation.cc
@@ -5,6 +5,8 @@ #include "components/drive/chromeos/file_system/search_operation.h" #include <stddef.h> + +#include <memory> #include <string> #include <utility> #include <vector> @@ -37,7 +39,8 @@ DCHECK(resource_metadata); DCHECK(result); - const ScopedVector<google_apis::FileResource>& entries = file_list->items(); + const std::vector<std::unique_ptr<google_apis::FileResource>>& entries = + file_list->items(); result->reserve(entries.size()); for (size_t i = 0; i < entries.size(); ++i) { std::string local_id;
diff --git a/components/drive/drive_app_registry.cc b/components/drive/drive_app_registry.cc index f6cbc502..37c976d 100644 --- a/components/drive/drive_app_registry.cc +++ b/components/drive/drive_app_registry.cc
@@ -7,8 +7,10 @@ #include <stddef.h> #include <algorithm> +#include <memory> #include <set> #include <utility> +#include <vector> #include "base/callback.h" #include "base/files/file_path.h" @@ -20,9 +22,10 @@ namespace { // Add {selector -> app_id} mapping to |map|. -void AddAppSelectorList(const ScopedVector<std::string>& selectors, - const std::string& app_id, - std::multimap<std::string, std::string>* map) { +void AddAppSelectorList( + const std::vector<std::unique_ptr<std::string>>& selectors, + const std::string& app_id, + std::multimap<std::string, std::string>* map) { for (size_t i = 0; i < selectors.size(); ++i) map->insert(std::make_pair(*selectors[i], app_id)); }
diff --git a/components/drive/service/fake_drive_service.cc b/components/drive/service/fake_drive_service.cc index 26b23f3..c7ae70d 100644 --- a/components/drive/service/fake_drive_service.cc +++ b/components/drive/service/fake_drive_service.cc
@@ -6,8 +6,10 @@ #include <stddef.h> +#include <memory> #include <string> #include <utility> +#include <vector> #include "base/files/file_util.h" #include "base/json/json_string_value_serializer.h" @@ -132,7 +134,8 @@ for (size_t i = 0; i < change_list->items().size(); ++i) { const ChangeResource& entry = *change_list->items()[i]; if (entry.file()) - file_list->mutable_items()->push_back(new FileResource(*entry.file())); + file_list->mutable_items()->push_back( + base::MakeUnique<FileResource>(*entry.file())); } callback.Run(error, std::move(file_list)); } @@ -1662,7 +1665,7 @@ // Filter out entries per parameters like |directory_resource_id| and // |search_query|. - ScopedVector<ChangeResource> entries; + std::vector<std::unique_ptr<ChangeResource>> entries; int num_entries_matched = 0; for (auto it = entries_.begin(); it != entries_.end(); ++it) { const ChangeResource& entry = it->second->change_resource; @@ -1720,7 +1723,7 @@ entry_copied->set_file(base::MakeUnique<FileResource>(*entry.file())); } entry_copied->set_modification_date(entry.modification_date()); - entries.push_back(entry_copied.release()); + entries.push_back(std::move(entry_copied)); } }
diff --git a/components/error_page/renderer/net_error_helper_core.cc b/components/error_page/renderer/net_error_helper_core.cc index 3451b7e..f040f97f 100644 --- a/components/error_page/renderer/net_error_helper_core.cc +++ b/components/error_page/renderer/net_error_helper_core.cc
@@ -6,6 +6,7 @@ #include <stddef.h> +#include <memory> #include <set> #include <string> #include <utility> @@ -20,7 +21,6 @@ #include "base/location.h" #include "base/logging.h" #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "base/metrics/histogram_macros.h" #include "base/metrics/sparse_histogram.h" #include "base/strings/string16.h" @@ -103,7 +103,7 @@ struct NavigationCorrectionResponse { std::string event_id; std::string fingerprint; - ScopedVector<NavigationCorrection> corrections; + std::vector<std::unique_ptr<NavigationCorrection>> corrections; static void RegisterJSONConverter( base::JSONValueConverter<NavigationCorrectionResponse>* converter) { @@ -302,9 +302,8 @@ std::unique_ptr<ErrorPageParams> params(new ErrorPageParams()); params->override_suggestions.reset(new base::ListValue()); std::unique_ptr<base::ListValue> parsed_corrections(new base::ListValue()); - for (ScopedVector<NavigationCorrection>::const_iterator it = - response.corrections.begin(); - it != response.corrections.end(); ++it) { + for (auto it = response.corrections.begin(); it != response.corrections.end(); + ++it) { // Doesn't seem like a good idea to show these. if ((*it)->is_porn || (*it)->is_soft_porn) continue;
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc index 65e8540..b1da402 100644 --- a/content/browser/security_exploit_browsertest.cc +++ b/content/browser/security_exploit_browsertest.cc
@@ -180,7 +180,11 @@ SecurityExploitBrowserTest() {} void SetUpCommandLine(base::CommandLine* command_line) override { - ASSERT_TRUE(embedded_test_server()->Start()); + // EmbeddedTestServer::InitializeAndListen() initializes its |base_url_| + // which is required below. This cannot invoke Start() however as that kicks + // off the "EmbeddedTestServer IO Thread" which then races with + // initialization in ContentBrowserTest::SetUp(), http://crbug.com/674545. + ASSERT_TRUE(embedded_test_server()->InitializeAndListen()); // Add a host resolver rule to map all outgoing requests to the test server. // This allows us to use "real" hostnames in URLs, which we can use to @@ -194,6 +198,10 @@ } void SetUpOnMainThread() override { + // Complete the manual Start() after ContentBrowserTest's own + // initialization, ref. comment on InitializeAndListen() above. + embedded_test_server()->StartAcceptingConnections(); + BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&net::URLRequestSlowDownloadJob::AddUrlHandler));
diff --git a/content/child/site_isolation_stats_gatherer_browsertest.cc b/content/child/site_isolation_stats_gatherer_browsertest.cc index 852ddab..9150a97a 100644 --- a/content/child/site_isolation_stats_gatherer_browsertest.cc +++ b/content/child/site_isolation_stats_gatherer_browsertest.cc
@@ -29,7 +29,12 @@ ~SiteIsolationStatsGathererBrowserTest() override {} void SetUpCommandLine(base::CommandLine* command_line) override { - ASSERT_TRUE(embedded_test_server()->Start()); + // EmbeddedTestServer::InitializeAndListen() initializes its |base_url_| + // which is required below. This cannot invoke Start() however as that kicks + // off the "EmbeddedTestServer IO Thread" which then races with + // initialization in ContentBrowserTest::SetUp(), http://crbug.com/674545. + ASSERT_TRUE(embedded_test_server()->InitializeAndListen()); + // Add a host resolver rule to map all outgoing requests to the test server. // This allows us to use "real" hostnames in URLs, which we can use to // create arbitrary SiteInstances. @@ -43,6 +48,12 @@ command_line->AppendSwitch(switches::kDisableWebSecurity); } + void SetUpOnMainThread() override { + // Complete the manual Start() after ContentBrowserTest's own + // initialization, ref. comment on InitializeAndListen() above. + embedded_test_server()->StartAcceptingConnections(); + } + void InspectHistograms(const base::HistogramTester& histograms, bool should_be_blocked, const std::string& resource_name) {
diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc index d3a458c..8bbb6b3 100644 --- a/content/renderer/media/android/webmediaplayer_android.cc +++ b/content/renderer/media/android/webmediaplayer_android.cc
@@ -182,8 +182,10 @@ DCHECK(main_thread_checker_.CalledOnValidThread()); - if (delegate_) + if (delegate_) { delegate_id_ = delegate_->AddObserver(this); + delegate_->SetIdle(delegate_id_, true); + } player_id_ = player_manager_->RegisterMediaPlayer(this); @@ -295,8 +297,8 @@ bool can_video_play_in_background = base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableMediaSuspend) || - (IsBackgroundVideoCandidate() && - delegate_ && delegate_->IsPlayingBackgroundVideo()); + (IsBackgroundVideoCandidate() && delegate_ && + delegate_->IsBackgroundVideoPlaybackUnlocked()); if (!can_video_play_in_background) { is_play_pending_ = true; return; @@ -828,8 +830,10 @@ // If we're paused after we receive metadata for the first time, tell the // delegate we can now be safely suspended due to inactivity if a subsequent // play event does not occur. - if (paused() && delegate_) - delegate_->DidPause(delegate_id_, false); + if (paused() && delegate_) { + delegate_->DidPause(delegate_id_); + delegate_->SetIdle(delegate_id_, true); + } } } @@ -1204,19 +1208,28 @@ // be known at this point -- there are no video only containers, so only // send audio if we know for sure its audio. The browser side player will // fill in the correct value later for media sessions. - delegate_->DidPlay(delegate_id_, hasVideo(), !hasVideo(), isRemote(), - media::DurationToMediaContentType(duration_)); + if (isRemote()) { + delegate_->PlayerGone(delegate_id_); + } else { + delegate_->DidPlay(delegate_id_, hasVideo(), !hasVideo(), + media::DurationToMediaContentType(duration_)); + } + delegate_->SetIdle(delegate_id_, false); } else { // Even if OnPlaybackComplete() has not been called yet, Blink may have // already fired the ended event based on current time relative to // duration -- so we need to check both possibilities here. - delegate_->DidPause(delegate_id_, - playback_completed_ || currentTime() >= duration()); + if (playback_completed_ || currentTime() >= duration()) { + delegate_->PlayerGone(delegate_id_); + } else { + delegate_->DidPause(delegate_id_); + } + delegate_->SetIdle(delegate_id_, true); } } } -void WebMediaPlayerAndroid::OnHidden() { +void WebMediaPlayerAndroid::OnFrameHidden() { // Pause audible video preserving its session. if (hasVideo() && IsBackgroundVideoCandidate() && !paused()) { Pause(false); @@ -1224,29 +1237,30 @@ return; } - OnSuspendRequested(false); + OnIdleTimeout(); } -void WebMediaPlayerAndroid::OnShown() { +void WebMediaPlayerAndroid::OnFrameClosed() { + SuspendAndReleaseResources(); +} + +void WebMediaPlayerAndroid::OnFrameShown() { if (is_play_pending_) play(); } -bool WebMediaPlayerAndroid::OnSuspendRequested(bool must_suspend) { - if (!must_suspend && - base::CommandLine::ForCurrentProcess()->HasSwitch( +void WebMediaPlayerAndroid::OnIdleTimeout() { + if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableMediaSuspend)) { - return true; + return; } - // If we're idle or playing video, pause and release resources; audio only - // players are allowed to continue unless indicated otherwise by the call. - if (must_suspend || (paused() && playback_completed_) || - (hasVideo() && !IsBackgroundVideoCandidate())) { + // If we're playing video or ended, pause and release resources; audio only + // players are allowed to continue. + if ((hasVideo() && !IsBackgroundVideoCandidate()) || + (paused() && playback_completed_)) { SuspendAndReleaseResources(); } - - return true; } void WebMediaPlayerAndroid::OnPlay() { @@ -1327,7 +1341,8 @@ } return base::FeatureList::IsEnabled(media::kResumeBackgroundVideo) && - hasAudio() && !isRemote() && delegate_ && delegate_->IsHidden(); + hasAudio() && !isRemote() && delegate_ && delegate_->IsFrameHidden() && + !delegate_->IsFrameClosed(); } } // namespace content
diff --git a/content/renderer/media/android/webmediaplayer_android.h b/content/renderer/media/android/webmediaplayer_android.h index 3d84ff0..10c095c 100644 --- a/content/renderer/media/android/webmediaplayer_android.h +++ b/content/renderer/media/android/webmediaplayer_android.h
@@ -212,9 +212,10 @@ void SuspendAndReleaseResources() override; // WebMediaPlayerDelegate::Observer implementation. - void OnHidden() override; - void OnShown() override; - bool OnSuspendRequested(bool must_suspend) override; + void OnFrameHidden() override; + void OnFrameClosed() override; + void OnFrameShown() override; + void OnIdleTimeout() override; void OnPlay() override; void OnPause() override; void OnVolumeMultiplierUpdate(double multiplier) override;
diff --git a/content/renderer/media/media_recorder_handler.cc b/content/renderer/media/media_recorder_handler.cc index d505226b..d798c82f 100644 --- a/content/renderer/media/media_recorder_handler.cc +++ b/content/renderer/media/media_recorder_handler.cc
@@ -274,8 +274,11 @@ DCHECK(main_render_thread_checker_.CalledOnValidThread()); if (!webm_muxer_) return; - webm_muxer_->OnEncodedVideo(params, std::move(encoded_data), timestamp, - is_key_frame); + if (!webm_muxer_->OnEncodedVideo(params, std::move(encoded_data), timestamp, + is_key_frame)) { + DLOG(ERROR) << "Error muxing video data"; + client_->onError("Error muxing video data"); + } } void MediaRecorderHandler::OnEncodedAudio( @@ -283,8 +286,13 @@ std::unique_ptr<std::string> encoded_data, base::TimeTicks timestamp) { DCHECK(main_render_thread_checker_.CalledOnValidThread()); - if (webm_muxer_) - webm_muxer_->OnEncodedAudio(params, std::move(encoded_data), timestamp); + if (!webm_muxer_) + return; + if (!webm_muxer_->OnEncodedAudio(params, std::move(encoded_data), + timestamp)) { + DLOG(ERROR) << "Error muxing audio data"; + client_->onError("Error muxing audio data"); + } } void MediaRecorderHandler::WriteData(base::StringPiece data) {
diff --git a/content/renderer/media/media_recorder_handler_unittest.cc b/content/renderer/media/media_recorder_handler_unittest.cc index 8f968d69..6d6d6d0 100644 --- a/content/renderer/media/media_recorder_handler_unittest.cc +++ b/content/renderer/media/media_recorder_handler_unittest.cc
@@ -116,6 +116,10 @@ registry_.AddAudioTrack(kTestAudioTrackId); } + void ForceOneErrorInWebmMuxer() { + media_recorder_handler_->webm_muxer_->ForceOneLibWebmErrorForTesting(); + } + std::unique_ptr<media::AudioBus> NextAudioBus() { std::unique_ptr<media::AudioBus> bus(media::AudioBus::Create( kTestAudioChannels, @@ -339,4 +343,53 @@ media_recorder_handler_.reset(); } +// Starts up recording and forces a WebmMuxer's libwebm error. +TEST_P(MediaRecorderHandlerTest, WebmMuxerErrorWhileEncoding) { + // Video-only test: Audio would be very similar. + if (GetParam().has_audio) + return; + + AddTracks(); + + const WebString mime_type(base::UTF8ToUTF16(GetParam().mime_type)); + const WebString codecs(base::UTF8ToUTF16(GetParam().codecs)); + EXPECT_TRUE(media_recorder_handler_->initialize(this, registry_.test_stream(), + mime_type, codecs, 0, 0)); + EXPECT_TRUE(media_recorder_handler_->start(0)); + + InSequence s; + const scoped_refptr<media::VideoFrame> video_frame = + media::VideoFrame::CreateBlackFrame(gfx::Size(160, 80)); + + { + const size_t kEncodedSizeThreshold = 16; + base::RunLoop run_loop; + base::Closure quit_closure = run_loop.QuitClosure(); + EXPECT_CALL(*this, writeData(_, _, _, _)).Times(AtLeast(1)); + EXPECT_CALL(*this, writeData(_, Gt(kEncodedSizeThreshold), _, _)) + .Times(1) + .WillOnce(RunClosure(quit_closure)); + + OnVideoFrameForTesting(video_frame); + run_loop.Run(); + } + + ForceOneErrorInWebmMuxer(); + + { + base::RunLoop run_loop; + base::Closure quit_closure = run_loop.QuitClosure(); + EXPECT_CALL(*this, writeData(_, _, _, _)).Times(0); + EXPECT_CALL(*this, onError(_)).Times(1).WillOnce(RunClosure(quit_closure)); + + OnVideoFrameForTesting(video_frame); + run_loop.Run(); + } + + + // Expect a last call on destruction, with size 0 and |lastInSlice| true. + EXPECT_CALL(*this, writeData(nullptr, 0, true, _)).Times(1); + media_recorder_handler_.reset(); +} + } // namespace content
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate.cc b/content/renderer/media/renderer_webmediaplayer_delegate.cc index 5712a347..92d1140e 100644 --- a/content/renderer/media/renderer_webmediaplayer_delegate.cc +++ b/content/renderer/media/renderer_webmediaplayer_delegate.cc
@@ -32,13 +32,12 @@ RendererWebMediaPlayerDelegate::RendererWebMediaPlayerDelegate( content::RenderFrame* render_frame) : RenderFrameObserver(render_frame), - idle_cleanup_timer_(true, true), default_tick_clock_(new base::DefaultTickClock()), tick_clock_(default_tick_clock_.get()) { idle_cleanup_interval_ = base::TimeDelta::FromSeconds(5); idle_timeout_ = base::TimeDelta::FromSeconds(15); - // To conserve resources, cleanup idle players more often on low end devices. + // Idle players time out more aggressively on low end devices. is_low_end_device_ = base::SysInfo::IsLowEndDevice(); #if defined(OS_ANDROID) @@ -51,87 +50,146 @@ RendererWebMediaPlayerDelegate::~RendererWebMediaPlayerDelegate() {} -int RendererWebMediaPlayerDelegate::AddObserver(Observer* observer) { - const int delegate_id = id_map_.Add(observer); - // Start players in the idle state to ensure we capture players which are - // consuming resources, but which have never played. - AddIdleDelegate(delegate_id); - return delegate_id; +bool RendererWebMediaPlayerDelegate::IsFrameHidden() { + if (is_frame_hidden_for_testing_) + return true; + + return (render_frame() && render_frame()->IsHidden()) || is_frame_closed_; } -void RendererWebMediaPlayerDelegate::RemoveObserver(int delegate_id) { - DCHECK(id_map_.Lookup(delegate_id)); - id_map_.Remove(delegate_id); - RemoveIdleDelegate(delegate_id); - playing_videos_.erase(delegate_id); +bool RendererWebMediaPlayerDelegate::IsFrameClosed() { + return is_frame_closed_; +} + +bool RendererWebMediaPlayerDelegate::IsBackgroundVideoPlaybackUnlocked() { + // TODO(sandersd): Include a check for kResumeBackgroundVideo? + return background_video_allowed_; +} + +int RendererWebMediaPlayerDelegate::AddObserver(Observer* observer) { + return id_map_.Add(observer); +} + +void RendererWebMediaPlayerDelegate::RemoveObserver(int player_id) { + DCHECK(id_map_.Lookup(player_id)); + id_map_.Remove(player_id); + idle_player_map_.erase(player_id); + stale_players_.erase(player_id); + playing_videos_.erase(player_id); + + Send( + new MediaPlayerDelegateHostMsg_OnMediaDestroyed(routing_id(), player_id)); + + ScheduleUpdateTask(); } void RendererWebMediaPlayerDelegate::DidPlay( - int delegate_id, + int player_id, bool has_video, bool has_audio, - bool is_remote, MediaContentType media_content_type) { - DCHECK(id_map_.Lookup(delegate_id)); - has_played_media_ = true; - if (has_video && !is_remote) - playing_videos_.insert(delegate_id); - else - playing_videos_.erase(delegate_id); - RemoveIdleDelegate(delegate_id); + DVLOG(2) << __func__ << "(" << player_id << ", " << has_video << ", " + << has_audio << ", " << static_cast<int>(media_content_type) << ")"; + DCHECK(id_map_.Lookup(player_id)); - // Upon receipt of a playback request, suspend everything that's not used. - if (is_low_end_device_) - CleanupIdleDelegates(base::TimeDelta()); + has_played_media_ = true; + if (has_video) { + if (!playing_videos_.count(player_id)) { + playing_videos_.insert(player_id); + has_played_video_ = true; + } + } else { + playing_videos_.erase(player_id); + } Send(new MediaPlayerDelegateHostMsg_OnMediaPlaying( - routing_id(), delegate_id, has_video, has_audio, is_remote, + routing_id(), player_id, has_video, has_audio, false, media_content_type)); + + ScheduleUpdateTask(); } -void RendererWebMediaPlayerDelegate::DidPause(int delegate_id, - bool reached_end_of_stream) { - DCHECK(id_map_.Lookup(delegate_id)); - AddIdleDelegate(delegate_id); - if (reached_end_of_stream) - playing_videos_.erase(delegate_id); - Send(new MediaPlayerDelegateHostMsg_OnMediaPaused(routing_id(), delegate_id, - reached_end_of_stream)); +void RendererWebMediaPlayerDelegate::DidPause(int player_id) { + DVLOG(2) << __func__ << "(" << player_id << ")"; + DCHECK(id_map_.Lookup(player_id)); + playing_videos_.erase(player_id); + Send(new MediaPlayerDelegateHostMsg_OnMediaPaused(routing_id(), player_id, + false)); + + // Required to keep background playback statistics up to date. + ScheduleUpdateTask(); } -void RendererWebMediaPlayerDelegate::PlayerGone(int delegate_id) { - DCHECK(id_map_.Lookup(delegate_id)); - playing_videos_.erase(delegate_id); - Send(new MediaPlayerDelegateHostMsg_OnMediaDestroyed(routing_id(), - delegate_id)); +void RendererWebMediaPlayerDelegate::PlayerGone(int player_id) { + DVLOG(2) << __func__ << "(" << player_id << ")"; + DCHECK(id_map_.Lookup(player_id)); + playing_videos_.erase(player_id); + Send( + new MediaPlayerDelegateHostMsg_OnMediaDestroyed(routing_id(), player_id)); + + // Required to keep background playback statistics up to date. + ScheduleUpdateTask(); } -bool RendererWebMediaPlayerDelegate::IsHidden() { - return render_frame()->IsHidden(); +void RendererWebMediaPlayerDelegate::SetIdle(int player_id, bool is_idle) { + DVLOG(2) << __func__ << "(" << player_id << ", " << is_idle << ")"; + + if (is_idle == IsIdle(player_id)) + return; + + if (is_idle) { + idle_player_map_[player_id] = tick_clock_->NowTicks(); + } else { + idle_player_map_.erase(player_id); + stale_players_.erase(player_id); + } + + ScheduleUpdateTask(); } -bool RendererWebMediaPlayerDelegate::IsPlayingBackgroundVideo() { - return is_playing_background_video_; +bool RendererWebMediaPlayerDelegate::IsIdle(int player_id) { + return idle_player_map_.count(player_id) || stale_players_.count(player_id); +} + +void RendererWebMediaPlayerDelegate::ClearStaleFlag(int player_id) { + DVLOG(2) << __func__ << "(" << player_id << ")"; + + if (!stale_players_.erase(player_id)) + return; + + // Set the idle time such that the player will be considered stale the next + // time idle cleanup runs. + idle_player_map_[player_id] = tick_clock_->NowTicks() - idle_timeout_; + + ScheduleUpdateTask(); +} + +bool RendererWebMediaPlayerDelegate::IsStale(int player_id) { + return stale_players_.count(player_id); } void RendererWebMediaPlayerDelegate::WasHidden() { - for (IDMap<Observer*>::iterator it(&id_map_); !it.IsAtEnd(); it.Advance()) - it.GetCurrentValue()->OnHidden(); - RecordAction(base::UserMetricsAction("Media.Hidden")); + + for (IDMap<Observer*>::iterator it(&id_map_); !it.IsAtEnd(); it.Advance()) + it.GetCurrentValue()->OnFrameHidden(); + + ScheduleUpdateTask(); } void RendererWebMediaPlayerDelegate::WasShown() { - SetIsPlayingBackgroundVideo(false); - for (IDMap<Observer*>::iterator it(&id_map_); !it.IsAtEnd(); it.Advance()) - it.GetCurrentValue()->OnShown(); - RecordAction(base::UserMetricsAction("Media.Shown")); + is_frame_closed_ = false; + background_video_allowed_ = false; + + for (IDMap<Observer*>::iterator it(&id_map_); !it.IsAtEnd(); it.Advance()) + it.GetCurrentValue()->OnFrameShown(); + + ScheduleUpdateTask(); } bool RendererWebMediaPlayerDelegate::OnMessageReceived( const IPC::Message& msg) { - bool handled = true; IPC_BEGIN_MESSAGE_MAP(RendererWebMediaPlayerDelegate, msg) IPC_MESSAGE_HANDLER(MediaPlayerDelegateMsg_Pause, OnMediaDelegatePause) IPC_MESSAGE_HANDLER(MediaPlayerDelegateMsg_Play, OnMediaDelegatePlay) @@ -139,9 +197,9 @@ OnMediaDelegateSuspendAllMediaPlayers) IPC_MESSAGE_HANDLER(MediaPlayerDelegateMsg_UpdateVolumeMultiplier, OnMediaDelegateVolumeMultiplierUpdate) - IPC_MESSAGE_UNHANDLED(handled = false) + IPC_MESSAGE_UNHANDLED(return false) IPC_END_MESSAGE_MAP() - return handled; + return true; } void RendererWebMediaPlayerDelegate::SetIdleCleanupParamsForTesting( @@ -154,128 +212,158 @@ is_low_end_device_ = is_low_end_device; } -void RendererWebMediaPlayerDelegate::OnMediaDelegatePause(int delegate_id) { - Observer* observer = id_map_.Lookup(delegate_id); - if (observer) { - if (playing_videos_.find(delegate_id) != playing_videos_.end()) - SetIsPlayingBackgroundVideo(false); - observer->OnPause(); - } - - RecordAction(base::UserMetricsAction("Media.Controls.RemotePause")); +bool RendererWebMediaPlayerDelegate::IsIdleCleanupTimerRunningForTesting() + const { + return idle_cleanup_timer_.IsRunning(); } -void RendererWebMediaPlayerDelegate::OnMediaDelegatePlay(int delegate_id) { - Observer* observer = id_map_.Lookup(delegate_id); - if (observer) { - if (playing_videos_.find(delegate_id) != playing_videos_.end()) - SetIsPlayingBackgroundVideo(IsHidden()); - observer->OnPlay(); +void RendererWebMediaPlayerDelegate::SetFrameHiddenForTesting(bool is_hidden) { + if (is_hidden == is_frame_hidden_for_testing_) + return; + + if (is_hidden) { + is_frame_hidden_for_testing_ = true; + } else { + is_frame_hidden_for_testing_ = false; + background_video_allowed_ = false; } + ScheduleUpdateTask(); +} + +void RendererWebMediaPlayerDelegate::OnMediaDelegatePause(int player_id) { + RecordAction(base::UserMetricsAction("Media.Controls.RemotePause")); + + Observer* observer = id_map_.Lookup(player_id); + if (observer) { + background_video_allowed_ = false; + observer->OnPause(); + } +} + +void RendererWebMediaPlayerDelegate::OnMediaDelegatePlay(int player_id) { RecordAction(base::UserMetricsAction("Media.Controls.RemotePlay")); + + Observer* observer = id_map_.Lookup(player_id); + if (observer) { + // TODO(sandersd): Ideally we would only set the flag if the player has + // video, but we don't reliably know if a paused player has video. + if (IsFrameHidden() && !IsFrameClosed()) + background_video_allowed_ = true; + observer->OnPlay(); + } } void RendererWebMediaPlayerDelegate::OnMediaDelegateSuspendAllMediaPlayers() { + is_frame_closed_ = true; + for (IDMap<Observer*>::iterator it(&id_map_); !it.IsAtEnd(); it.Advance()) - it.GetCurrentValue()->OnSuspendRequested(true); + it.GetCurrentValue()->OnFrameClosed(); } void RendererWebMediaPlayerDelegate::OnMediaDelegateVolumeMultiplierUpdate( - int delegate_id, + int player_id, double multiplier) { - Observer* observer = id_map_.Lookup(delegate_id); + Observer* observer = id_map_.Lookup(player_id); if (observer) observer->OnVolumeMultiplierUpdate(multiplier); } -void RendererWebMediaPlayerDelegate::AddIdleDelegate(int delegate_id) { - idle_delegate_map_[delegate_id] = tick_clock_->NowTicks(); - if (!idle_cleanup_timer_.IsRunning()) { +void RendererWebMediaPlayerDelegate::ScheduleUpdateTask() { + if (!pending_update_task_) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(&RendererWebMediaPlayerDelegate::UpdateTask, AsWeakPtr())); + pending_update_task_ = true; + } +} + +void RendererWebMediaPlayerDelegate::UpdateTask() { + DVLOG(3) << __func__; + pending_update_task_ = false; + + // Check whether a player was played since the last UpdateTask(). We basically + // treat this as a parameter to UpdateTask(), except that it can be changed + // between posting the task and UpdateTask() executing. + bool has_played_video_since_last_update_task = has_played_video_; + has_played_video_ = false; + + // Record UMAs for background video playback. + RecordBackgroundVideoPlayback(); + + // Clean up idle players. + bool aggressive_cleanup = false; + + // When we reach the maximum number of idle players, clean them up + // aggressively. Values chosen after testing on a Galaxy Nexus device for + // http://crbug.com/612909. + if (idle_player_map_.size() > (is_low_end_device_ ? 2u : 8u)) + aggressive_cleanup = true; + + // When a player plays on a low-end device, clean up idle players + // aggressively. + if (has_played_video_since_last_update_task && is_low_end_device_) + aggressive_cleanup = true; + + CleanUpIdlePlayers(aggressive_cleanup ? base::TimeDelta() : idle_timeout_); + + // If there are still idle players, schedule an attempt to clean them up. + // This construct ensures that the next callback is always + // |idle_cleanup_interval_| from now. + idle_cleanup_timer_.Stop(); + if (!idle_player_map_.empty()) { idle_cleanup_timer_.Start( FROM_HERE, idle_cleanup_interval_, - base::Bind(&RendererWebMediaPlayerDelegate::CleanupIdleDelegates, - base::Unretained(this), idle_timeout_)); + base::Bind(&RendererWebMediaPlayerDelegate::UpdateTask, + base::Unretained(this))); } - - // When we reach the maximum number of idle players, aggressively suspend idle - // delegates to try and remain under the limit. Values chosen after testing on - // a Galaxy Nexus device for http://crbug.com/612909. - if (idle_delegate_map_.size() > (is_low_end_device_ ? 2u : 8u)) - CleanupIdleDelegates(base::TimeDelta()); } -void RendererWebMediaPlayerDelegate::RemoveIdleDelegate(int delegate_id) { - // To avoid invalidating the iterator, just mark the delegate for deletion - // using a sentinel value of an empty TimeTicks. - if (idle_cleanup_running_) { - idle_delegate_map_[delegate_id] = base::TimeTicks(); - return; - } +void RendererWebMediaPlayerDelegate::RecordBackgroundVideoPlayback() { +#if defined(OS_ANDROID) + // TODO(avayvod): This would be useful to collect on desktop too and express + // in actual media watch time vs. just elapsed time. + // See https://crbug.com/638726. + bool has_playing_background_video = + IsFrameHidden() && !IsFrameClosed() && !playing_videos_.empty(); - idle_delegate_map_.erase(delegate_id); - if (idle_delegate_map_.empty()) - idle_cleanup_timer_.Stop(); -} + if (has_playing_background_video != was_playing_background_video_) { + was_playing_background_video_ = has_playing_background_video; -void RendererWebMediaPlayerDelegate::CleanupIdleDelegates( - base::TimeDelta timeout) { - // Drop reentrant cleanups which can occur during forced suspension when the - // number of idle delegates is too high for a given device. - if (idle_cleanup_running_) - return; - - // Iterate over the delegates and suspend the idle ones. Note: The call to - // OnSuspendRequested() can trigger calls into RemoveIdleDelegate(), so for - // iterator validity we set |idle_cleanup_running_| to true and defer - // deletions. - DCHECK(!idle_cleanup_running_); - base::AutoReset<bool> scoper(&idle_cleanup_running_, true); - const base::TimeTicks now = tick_clock_->NowTicks(); - for (auto& idle_delegate_entry : idle_delegate_map_) { - if (now - idle_delegate_entry.second > timeout) { - if (id_map_.Lookup(idle_delegate_entry.first) - ->OnSuspendRequested(false)) { - // If the player accepted the suspension, mark it for removal - // from future polls to avoid running the timer forever. - idle_delegate_entry.second = base::TimeTicks(); - } + if (has_playing_background_video) { + RecordAction(base::UserMetricsAction("Media.Session.BackgroundResume")); + background_video_start_time_ = base::TimeTicks::Now(); + } else { + RecordAction(base::UserMetricsAction("Media.Session.BackgroundSuspend")); + UMA_HISTOGRAM_CUSTOM_TIMES( + "Media.Android.BackgroundVideoTime", + base::TimeTicks::Now() - background_video_start_time_, + base::TimeDelta::FromSeconds(7), base::TimeDelta::FromHours(10), 50); } } - - // Take care of any removals that happened during the above iteration. - for (auto it = idle_delegate_map_.begin(); it != idle_delegate_map_.end();) { - if (it->second.is_null()) - it = idle_delegate_map_.erase(it); - else - ++it; - } - - // Shutdown the timer if no delegates are left. - if (idle_delegate_map_.empty()) - idle_cleanup_timer_.Stop(); +#endif // OS_ANDROID } -void RendererWebMediaPlayerDelegate::SetIsPlayingBackgroundVideo( - bool is_playing) { - if (is_playing_background_video_ == is_playing) return; +void RendererWebMediaPlayerDelegate::CleanUpIdlePlayers( + base::TimeDelta timeout) { + const base::TimeTicks now = tick_clock_->NowTicks(); -// TODO(avayvod): This would be useful to collect on desktop too and express in -// actual media watch time vs. just elapsed time. See https://crbug.com/638726. -#if defined(OS_ANDROID) - if (is_playing_background_video_) { - UMA_HISTOGRAM_CUSTOM_TIMES( - "Media.Android.BackgroundVideoTime", - base::TimeTicks::Now() - background_video_playing_start_time_, - base::TimeDelta::FromSeconds(7), base::TimeDelta::FromHours(10), 50); - RecordAction(base::UserMetricsAction("Media.Session.BackgroundSuspend")); - } else { - background_video_playing_start_time_ = base::TimeTicks::Now(); - RecordAction(base::UserMetricsAction("Media.Session.BackgroundResume")); + // Create a list of stale players before making any possibly reentrant calls + // to OnIdleTimeout(). + std::vector<int> stale_players; + for (const auto& it : idle_player_map_) { + if (now - it.second >= timeout) + stale_players.push_back(it.first); } -#endif // OS_ANDROID - is_playing_background_video_ = is_playing; + // Notify stale players. + for (int player_id : stale_players) { + Observer* player = id_map_.Lookup(player_id); + if (player && idle_player_map_.erase(player_id)) { + stale_players_.insert(player_id); + player->OnIdleTimeout(); + } + } } void RendererWebMediaPlayerDelegate::OnDestruct() {
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate.h b/content/renderer/media/renderer_webmediaplayer_delegate.h index a8aa0e1..d3f7155 100644 --- a/content/renderer/media/renderer_webmediaplayer_delegate.h +++ b/content/renderer/media/renderer_webmediaplayer_delegate.h
@@ -11,7 +11,9 @@ #include "base/id_map.h" #include "base/macros.h" +#include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" +#include "base/single_thread_task_runner.h" #include "base/time/default_tick_clock.h" #include "base/timer/timer.h" #include "content/common/content_export.h" @@ -26,8 +28,8 @@ enum class MediaContentType; -// An interface to allow a WebMediaPlayerImpl to communicate changes of state -// to objects that need to know. +// Standard implementation of WebMediaPlayerDelegate; communicates state to +// the MediaPlayerDelegateHost. class CONTENT_EXPORT RendererWebMediaPlayerDelegate : public content::RenderFrameObserver, public NON_EXPORTED_BASE(WebMediaPlayerDelegate), @@ -41,17 +43,21 @@ bool has_played_media() const { return has_played_media_; } // WebMediaPlayerDelegate implementation. + bool IsFrameHidden() override; + bool IsFrameClosed() override; + bool IsBackgroundVideoPlaybackUnlocked() override; int AddObserver(Observer* observer) override; - void RemoveObserver(int delegate_id) override; - void DidPlay(int delegate_id, + void RemoveObserver(int player_id) override; + void DidPlay(int player_id, bool has_video, bool has_audio, - bool is_remote, MediaContentType media_content_type) override; - void DidPause(int delegate_id, bool reached_end_of_stream) override; - void PlayerGone(int delegate_id) override; - bool IsHidden() override; - bool IsPlayingBackgroundVideo() override; + void DidPause(int player_id) override; + void PlayerGone(int player_id) override; + void SetIdle(int player_id, bool is_idle) override; + bool IsIdle(int player_id) override; + void ClearStaleFlag(int player_id) override; + bool IsStale(int player_id) override; // content::RenderFrameObserver overrides. void WasHidden() override; @@ -65,61 +71,71 @@ void SetIdleCleanupParamsForTesting(base::TimeDelta idle_timeout, base::TickClock* tick_clock, bool is_low_end_device); - bool IsIdleCleanupTimerRunningForTesting() const { - return idle_cleanup_timer_.IsRunning(); - } + bool IsIdleCleanupTimerRunningForTesting() const; + + // Note: Does not call OnFrameHidden()/OnFrameShown(). + void SetFrameHiddenForTesting(bool is_hidden); friend class RendererWebMediaPlayerDelegateTest; private: - void OnMediaDelegatePause(int delegate_id); - void OnMediaDelegatePlay(int delegate_id); + void OnMediaDelegatePause(int player_id); + void OnMediaDelegatePlay(int player_id); void OnMediaDelegateSuspendAllMediaPlayers(); - void OnMediaDelegateVolumeMultiplierUpdate(int delegate_id, - double multiplier); + void OnMediaDelegateVolumeMultiplierUpdate(int player_id, double multiplier); - // Adds or removes a delegate from |idle_delegate_map_|. The first insertion - // or last removal will start or stop |idle_cleanup_timer_| respectively. - void AddIdleDelegate(int delegate_id); - void RemoveIdleDelegate(int delegate_id); + // Schedules UpdateTask() to run soon. + void ScheduleUpdateTask(); - // Runs periodically to suspend idle delegates in |idle_delegate_map_| which + // Processes state changes, dispatches CleanupIdlePlayers(). + void UpdateTask(); + + // Records UMAs about background playback. + void RecordBackgroundVideoPlayback(); + + // Runs periodically to notify stale players in |idle_player_map_| which // have been idle for longer than |timeout|. - void CleanupIdleDelegates(base::TimeDelta timeout); + void CleanUpIdlePlayers(base::TimeDelta timeout); - // Setter for |is_playing_background_video_| that updates the metrics. - void SetIsPlayingBackgroundVideo(bool is_playing); - + // True if any media has ever been played in this render frame. Affects + // autoplay logic in RenderFrameImpl. bool has_played_media_ = false; + + bool background_video_allowed_ = false; + bool is_frame_closed_ = false; + bool is_frame_hidden_for_testing_ = false; + + // State related to scheduling UpdateTask(). These are cleared each time + // UpdateTask() runs. + bool has_played_video_ = false; + bool pending_update_task_ = false; + IDMap<Observer*> id_map_; - // Tracks which delegates have entered an idle state. After some period of - // inactivity these players will be suspended to release unused resources. - bool idle_cleanup_running_ = false; - std::map<int, base::TimeTicks> idle_delegate_map_; - base::Timer idle_cleanup_timer_; + // Tracks which players have entered an idle state. After some period of + // inactivity these players will be notified and become stale. + std::map<int, base::TimeTicks> idle_player_map_; + std::set<int> stale_players_; + base::OneShotTimer idle_cleanup_timer_; - // Amount of time allowed to elapse after a delegate enters the paused before - // the delegate is suspended. + // Amount of time allowed to elapse after a player becomes idle before + // it can transition to stale. base::TimeDelta idle_timeout_; - // The polling interval used for checking the delegates to see if any have - // exceeded |idle_timeout_| since their last pause state. + // The polling interval used for checking the players to see if any have + // exceeded |idle_timeout_| since becoming idle. base::TimeDelta idle_cleanup_interval_; - // Clock used for calculating when delegates have expired. May be overridden - // for testing. + // Clock used for calculating when players have become stale. May be + // overridden for testing. std::unique_ptr<base::DefaultTickClock> default_tick_clock_; base::TickClock* tick_clock_; - // If a video is playing in the background. Set when user resumes a video - // allowing it to play and reset when either user pauses it or it goes - // foreground. - bool is_playing_background_video_ = false; - #if defined(OS_ANDROID) + bool was_playing_background_video_ = false; + // Keeps track of when the background video playback started for metrics. - base::TimeTicks background_video_playing_start_time_; + base::TimeTicks background_video_start_time_; #endif // OS_ANDROID // The currently playing local videos. Used to determine whether
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc b/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc index 30fc19df..98610244 100644 --- a/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc +++ b/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc
@@ -30,11 +30,6 @@ constexpr base::TimeDelta kIdleTimeout = base::TimeDelta::FromSeconds(1); } -ACTION_P(RunClosure, closure) { - closure.Run(); - return true; -} - class MockWebMediaPlayerDelegateObserver : public WebMediaPlayerDelegate::Observer { public: @@ -42,9 +37,10 @@ ~MockWebMediaPlayerDelegateObserver() {} // WebMediaPlayerDelegate::Observer implementation. - MOCK_METHOD0(OnHidden, void()); - MOCK_METHOD0(OnShown, void()); - MOCK_METHOD1(OnSuspendRequested, bool(bool)); + MOCK_METHOD0(OnFrameHidden, void()); + MOCK_METHOD0(OnFrameClosed, void()); + MOCK_METHOD0(OnFrameShown, void()); + MOCK_METHOD0(OnIdleTimeout, void()); MOCK_METHOD0(OnPlay, void()); MOCK_METHOD0(OnPause, void()); MOCK_METHOD1(OnVolumeMultiplierUpdate, void(double)); @@ -73,12 +69,8 @@ protected: IPC::TestSink& test_sink() { return render_thread_->sink(); } - bool HasPlayingVideo(int delegate_id) { - return delegate_manager_->playing_videos_.count(delegate_id); - } - - void SetPlayingBackgroundVideo(bool is_playing) { - delegate_manager_->is_playing_background_video_ = is_playing; + void SetBackgroundVideoPlaybackUnlocked(bool is_unlocked) { + delegate_manager_->background_video_allowed_ = is_unlocked; } void CallOnMediaDelegatePlay(int delegate_id) { @@ -94,6 +86,13 @@ &tick_clock_, true); } + void RunLoopOnce() { + base::RunLoop run_loop; + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + run_loop.QuitClosure()); + run_loop.Run(); + } + std::unique_ptr<RendererWebMediaPlayerDelegate> delegate_manager_; StrictMock<MockWebMediaPlayerDelegateObserver> observer_1_, observer_2_, observer_3_; @@ -112,7 +111,7 @@ const bool kHasVideo = true, kHasAudio = false, kIsRemote = false; const media::MediaContentType kMediaContentType = media::MediaContentType::Transient; - delegate_manager_->DidPlay(delegate_id, kHasVideo, kHasAudio, kIsRemote, + delegate_manager_->DidPlay(delegate_id, kHasVideo, kHasAudio, kMediaContentType); const IPC::Message* msg = test_sink().GetUniqueMessageMatching( @@ -131,8 +130,8 @@ // Verify the paused message. { test_sink().ClearMessages(); - const bool kReachedEndOfStream = true; - delegate_manager_->DidPause(delegate_id, kReachedEndOfStream); + const bool kReachedEndOfStream = false; + delegate_manager_->DidPause(delegate_id); const IPC::Message* msg = test_sink().GetUniqueMessageMatching( MediaPlayerDelegateHostMsg_OnMediaPaused::ID); @@ -162,10 +161,10 @@ TEST_F(RendererWebMediaPlayerDelegateTest, DeliversObserverNotifications) { const int delegate_id = delegate_manager_->AddObserver(&observer_1_); - EXPECT_CALL(observer_1_, OnHidden()); + EXPECT_CALL(observer_1_, OnFrameHidden()); delegate_manager_->WasHidden(); - EXPECT_CALL(observer_1_, OnShown()); + EXPECT_CALL(observer_1_, OnFrameShown()); delegate_manager_->WasShown(); EXPECT_CALL(observer_1_, OnPause()); @@ -182,7 +181,7 @@ kTestMultiplier); delegate_manager_->OnMessageReceived(volume_msg); - EXPECT_CALL(observer_1_, OnSuspendRequested(true)); + EXPECT_CALL(observer_1_, OnFrameClosed()); MediaPlayerDelegateMsg_SuspendAllMediaPlayers suspend_msg(0); delegate_manager_->OnMessageReceived(suspend_msg); } @@ -191,21 +190,19 @@ ASSERT_FALSE(delegate_manager_->IsIdleCleanupTimerRunningForTesting()); } -TEST_F(RendererWebMediaPlayerDelegateTest, AddingAnObserverStartsTheTimer) { - delegate_manager_->AddObserver(&observer_1_); +TEST_F(RendererWebMediaPlayerDelegateTest, AddingAnIdleObserverStartsTheTimer) { + const int delegate_id_1 = delegate_manager_->AddObserver(&observer_1_); + delegate_manager_->SetIdle(delegate_id_1, true); + RunLoopOnce(); ASSERT_TRUE(delegate_manager_->IsIdleCleanupTimerRunningForTesting()); } TEST_F(RendererWebMediaPlayerDelegateTest, RemovingAllObserversStopsTheTimer) { - delegate_manager_->RemoveObserver( - delegate_manager_->AddObserver(&observer_1_)); - ASSERT_FALSE(delegate_manager_->IsIdleCleanupTimerRunningForTesting()); -} - -TEST_F(RendererWebMediaPlayerDelegateTest, PlayingDelegatesAreNotIdle) { const int delegate_id_1 = delegate_manager_->AddObserver(&observer_1_); - delegate_manager_->DidPlay(delegate_id_1, true, true, false, - media::MediaContentType::Persistent); + delegate_manager_->SetIdle(delegate_id_1, true); + RunLoopOnce(); + delegate_manager_->RemoveObserver(delegate_id_1); + RunLoopOnce(); ASSERT_FALSE(delegate_manager_->IsIdleCleanupTimerRunningForTesting()); } @@ -213,60 +210,44 @@ SetIsLowEndDeviceForTesting(); const int delegate_id_1 = delegate_manager_->AddObserver(&observer_1_); - delegate_manager_->AddObserver(&observer_2_); + delegate_manager_->SetIdle(delegate_id_1, true); + const int delegate_id_2 = delegate_manager_->AddObserver(&observer_2_); + delegate_manager_->SetIdle(delegate_id_2, true); + RunLoopOnce(); // Calling play on the first player should suspend the other idle player. - EXPECT_CALL(observer_2_, OnSuspendRequested(false)); - tick_clock_.Advance(base::TimeDelta::FromMicroseconds(1)); - delegate_manager_->DidPlay(delegate_id_1, true, true, false, + EXPECT_CALL(observer_2_, OnIdleTimeout()); + delegate_manager_->DidPlay(delegate_id_1, true, true, media::MediaContentType::Persistent); + delegate_manager_->SetIdle(delegate_id_1, false); + tick_clock_.Advance(base::TimeDelta::FromMicroseconds(1)); + RunLoopOnce(); } TEST_F(RendererWebMediaPlayerDelegateTest, MaxLowEndIdleDelegates) { SetIsLowEndDeviceForTesting(); - delegate_manager_->AddObserver(&observer_1_); - delegate_manager_->AddObserver(&observer_2_); + int delegate_id_1 = delegate_manager_->AddObserver(&observer_1_); + delegate_manager_->SetIdle(delegate_id_1, true); + int delegate_id_2 = delegate_manager_->AddObserver(&observer_2_); + delegate_manager_->SetIdle(delegate_id_2, true); + RunLoopOnce(); - // Just adding a third idle observer should suspend the others. - EXPECT_CALL(observer_1_, OnSuspendRequested(false)); - EXPECT_CALL(observer_2_, OnSuspendRequested(false)); + // Just adding a third idle observer should suspend all idle players. + EXPECT_CALL(observer_1_, OnIdleTimeout()); + EXPECT_CALL(observer_2_, OnIdleTimeout()); + int delegate_id_3 = delegate_manager_->AddObserver(&observer_3_); + delegate_manager_->SetIdle(delegate_id_3, true); + EXPECT_CALL(observer_3_, OnIdleTimeout()); tick_clock_.Advance(base::TimeDelta::FromMicroseconds(1)); - delegate_manager_->AddObserver(&observer_3_); -} - -// Make sure it's safe to call DidPause(), which modifies the idle delegate -// list, from OnSuspendRequested(), which iterates over the idle delegate list. -TEST_F(RendererWebMediaPlayerDelegateTest, ReentrantDelegateCallsAreSafe) { - const int delegate_id_1 = delegate_manager_->AddObserver(&observer_1_); - EXPECT_CALL(observer_1_, OnSuspendRequested(false)) - .WillOnce(RunClosure(base::Bind(&RendererWebMediaPlayerDelegate::DidPause, - base::Unretained(delegate_manager_.get()), - delegate_id_1, false))); - // Run an idle cleanup. - tick_clock_.Advance(kIdleTimeout + base::TimeDelta::FromMicroseconds(1)); - base::RunLoop().RunUntilIdle(); + RunLoopOnce(); } TEST_F(RendererWebMediaPlayerDelegateTest, SuspendRequestsAreOnlySentOnceIfHandled) { - delegate_manager_->AddObserver(&observer_1_); - // Return true from OnSuspendRequested() to indicate that it was handled. So - // even though the player did not call PlayerGone() it should be removed from - // future idle cleanup polls. - EXPECT_CALL(observer_1_, OnSuspendRequested(false)).WillOnce(Return(true)); - tick_clock_.Advance(kIdleTimeout + base::TimeDelta::FromMicroseconds(1)); - base::RunLoop().RunUntilIdle(); -} - -TEST_F(RendererWebMediaPlayerDelegateTest, - SuspendRequestsAreSentAgainIfNotHandled) { - delegate_manager_->AddObserver(&observer_1_); - // Return false from OnSuspendRequested() to indicate that it was not handled. - // The observer should get another OnSuspendRequested. - EXPECT_CALL(observer_1_, OnSuspendRequested(false)) - .WillOnce(Return(false)) - .WillOnce(Return(true)); + int delegate_id_1 = delegate_manager_->AddObserver(&observer_1_); + delegate_manager_->SetIdle(delegate_id_1, true); + EXPECT_CALL(observer_1_, OnIdleTimeout()); tick_clock_.Advance(kIdleTimeout + base::TimeDelta::FromMicroseconds(1)); base::RunLoop().RunUntilIdle(); } @@ -274,135 +255,59 @@ TEST_F(RendererWebMediaPlayerDelegateTest, IdleDelegatesAreSuspended) { // Add one non-idle observer and one idle observer. const int delegate_id_1 = delegate_manager_->AddObserver(&observer_1_); - delegate_manager_->DidPlay(delegate_id_1, true, true, false, - media::MediaContentType::Persistent); - delegate_manager_->AddObserver(&observer_2_); + const int delegate_id_2 = delegate_manager_->AddObserver(&observer_2_); + delegate_manager_->SetIdle(delegate_id_2, true); // The idle cleanup task should suspend the second delegate while the first is // kept alive. { - EXPECT_CALL(observer_2_, OnSuspendRequested(false)).WillOnce(Return(true)); + EXPECT_CALL(observer_2_, OnIdleTimeout()); tick_clock_.Advance(kIdleTimeout + base::TimeDelta::FromMicroseconds(1)); - base::RunLoop().RunUntilIdle(); + RunLoopOnce(); } - // Pausing should count as idle if playback didn't reach end of stream, but - // in this case the player will not remove the MediaSession. - delegate_manager_->DidPause(delegate_id_1, false /* reached_end_of_stream */); - const int delegate_id_3 = delegate_manager_->AddObserver(&observer_3_); - delegate_manager_->DidPlay(delegate_id_3, true, true, false, - media::MediaContentType::Persistent); - - // Adding the observer should instantly queue the timeout task. Once run only - // the first player should be suspended. + // Once the player is idle, it should be suspended after |kIdleTimeout|. + delegate_manager_->SetIdle(delegate_id_1, true); { - EXPECT_CALL(observer_1_, OnSuspendRequested(false)).WillOnce(Return(true)); - base::RunLoop run_loop; - base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - run_loop.QuitClosure()); + EXPECT_CALL(observer_1_, OnIdleTimeout()); tick_clock_.Advance(kIdleTimeout + base::TimeDelta::FromMicroseconds(1)); - run_loop.Run(); - } - - delegate_manager_->DidPlay(delegate_id_1, true, true, false, - media::MediaContentType::Persistent); - - // Pausing after reaching end of stream should count as idle. - delegate_manager_->DidPause(delegate_id_1, true /* reached_end_of_stream */); - - // Once the timeout task runs the first delegate should be suspended while the - // third is kept alive. - { - EXPECT_CALL(observer_1_, OnSuspendRequested(false)).WillOnce(Return(true)); - base::RunLoop run_loop; - base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - run_loop.QuitClosure()); - tick_clock_.Advance(kIdleTimeout + base::TimeDelta::FromMicroseconds(1)); - run_loop.Run(); + RunLoopOnce(); } } -TEST_F(RendererWebMediaPlayerDelegateTest, PlayingVideosSet) { - int delegate_id = delegate_manager_->AddObserver(&observer_1_); - EXPECT_FALSE(HasPlayingVideo(delegate_id)); - - // Playing a local video adds it to the set. - delegate_manager_->DidPlay(delegate_id, true, true, false, - MediaContentType::Persistent); - EXPECT_TRUE(HasPlayingVideo(delegate_id)); - - // Pause doesn't remove the video from the set. - delegate_manager_->DidPause(delegate_id, false); - EXPECT_TRUE(HasPlayingVideo(delegate_id)); - - // Reaching the end removes the video from the set. - delegate_manager_->DidPause(delegate_id, true); - EXPECT_FALSE(HasPlayingVideo(delegate_id)); - - // Removing the player removes the video from the set. - delegate_manager_->DidPlay(delegate_id, true, true, false, - MediaContentType::Persistent); - delegate_manager_->PlayerGone(delegate_id); - EXPECT_FALSE(HasPlayingVideo(delegate_id)); - - // Playing a remote video removes it from the set. - delegate_manager_->DidPlay(delegate_id, true, true, false, - MediaContentType::Persistent); - delegate_manager_->DidPlay(delegate_id, true, true, true, - MediaContentType::Persistent); - EXPECT_FALSE(HasPlayingVideo(delegate_id)); - - // Playing a local video without audio adds it to the set (because of WMPA). - delegate_manager_->DidPlay(delegate_id, true, false, false, - MediaContentType::Persistent); - EXPECT_TRUE(HasPlayingVideo(delegate_id)); - - // Playing a local audio removes it from the set. - delegate_manager_->DidPlay(delegate_id, false, true, false, - MediaContentType::Persistent); - EXPECT_FALSE(HasPlayingVideo(delegate_id)); - - // Removing the observer also removes the video from the set. - delegate_manager_->DidPlay(delegate_id, true, true, false, - MediaContentType::Persistent); - delegate_manager_->RemoveObserver(delegate_id); - EXPECT_FALSE(HasPlayingVideo(delegate_id)); -} - -TEST_F(RendererWebMediaPlayerDelegateTest, IsPlayingBackgroundVideo) { +TEST_F(RendererWebMediaPlayerDelegateTest, IsBackgroundVideoPlaybackUnlocked) { NiceMock<MockWebMediaPlayerDelegateObserver> observer; int delegate_id = delegate_manager_->AddObserver(&observer); - EXPECT_FALSE(delegate_manager_->IsPlayingBackgroundVideo()); + EXPECT_FALSE(delegate_manager_->IsBackgroundVideoPlaybackUnlocked()); // Showing the frame always clears the flag. - SetPlayingBackgroundVideo(true); + SetBackgroundVideoPlaybackUnlocked(true); delegate_manager_->WasShown(); - EXPECT_FALSE(delegate_manager_->IsPlayingBackgroundVideo()); - - // Pausing anything other than a local playing video doesn't affect the flag. - SetPlayingBackgroundVideo(true); - CallOnMediaDelegatePause(delegate_id); - EXPECT_TRUE(delegate_manager_->IsPlayingBackgroundVideo()); + EXPECT_FALSE(delegate_manager_->IsBackgroundVideoPlaybackUnlocked()); // Pausing a currently playing video clears the flag. - delegate_manager_->DidPlay(delegate_id, true, true, false, + delegate_manager_->DidPlay(delegate_id, true, true, MediaContentType::Persistent); + SetBackgroundVideoPlaybackUnlocked(true); CallOnMediaDelegatePause(delegate_id); - EXPECT_FALSE(delegate_manager_->IsPlayingBackgroundVideo()); + EXPECT_FALSE(delegate_manager_->IsBackgroundVideoPlaybackUnlocked()); - // TODO(avayvod): this test can't mock the IsHidden() method. + // TODO(avayvod): this test can't mock the IsFrameHidden() method. // Just test that the value changes or doesn't depending on whether the video // is currently playing. - bool old_value = !delegate_manager_->IsHidden(); - SetPlayingBackgroundVideo(old_value); - delegate_manager_->DidPause(delegate_id, true); - CallOnMediaDelegatePlay(delegate_id); - EXPECT_EQ(old_value, delegate_manager_->IsPlayingBackgroundVideo()); - - delegate_manager_->DidPlay(delegate_id, true, true, false, - MediaContentType::Persistent); - CallOnMediaDelegatePlay(delegate_id); - EXPECT_NE(old_value, delegate_manager_->IsPlayingBackgroundVideo()); + if (delegate_manager_->IsFrameHidden()) { + SetBackgroundVideoPlaybackUnlocked(false); + CallOnMediaDelegatePlay(delegate_id); + EXPECT_TRUE(delegate_manager_->IsBackgroundVideoPlaybackUnlocked()); + CallOnMediaDelegatePause(delegate_id); + EXPECT_FALSE(delegate_manager_->IsBackgroundVideoPlaybackUnlocked()); + } else { + SetBackgroundVideoPlaybackUnlocked(false); + CallOnMediaDelegatePlay(delegate_id); + EXPECT_FALSE(delegate_manager_->IsBackgroundVideoPlaybackUnlocked()); + CallOnMediaDelegatePause(delegate_id); + EXPECT_FALSE(delegate_manager_->IsBackgroundVideoPlaybackUnlocked()); + } } #if defined(OS_ANDROID) @@ -413,30 +318,30 @@ base::HistogramTester histogram_tester; histogram_tester.ExpectTotalCount("Media.Android.BackgroundVideoTime", 0); - // Pausing or showing doesn't record anything as background playback - // hasn't started yet. - delegate_manager_->DidPlay(delegate_id, true, true, false, + // Play/pause while not hidden doesn't record anything. + delegate_manager_->DidPlay(delegate_id, true, true, MediaContentType::Persistent); - CallOnMediaDelegatePause(delegate_id); + RunLoopOnce(); + delegate_manager_->DidPause(delegate_id); + RunLoopOnce(); histogram_tester.ExpectTotalCount("Media.Android.BackgroundVideoTime", 0); - delegate_manager_->DidPlay(delegate_id, true, true, false, + // Play/pause while hidden does. + delegate_manager_->SetFrameHiddenForTesting(true); + delegate_manager_->DidPlay(delegate_id, true, true, MediaContentType::Persistent); - delegate_manager_->WasShown(); - histogram_tester.ExpectTotalCount("Media.Android.BackgroundVideoTime", 0); - - // Doing this things after the background playback has started should record - // the time. - delegate_manager_->DidPlay(delegate_id, true, true, false, - MediaContentType::Persistent); - SetPlayingBackgroundVideo(true); - CallOnMediaDelegatePause(delegate_id); + RunLoopOnce(); + delegate_manager_->DidPause(delegate_id); + RunLoopOnce(); histogram_tester.ExpectTotalCount("Media.Android.BackgroundVideoTime", 1); - delegate_manager_->DidPlay(delegate_id, true, true, false, + // As does ending background playback by becoming visible. + delegate_manager_->SetFrameHiddenForTesting(true); + delegate_manager_->DidPlay(delegate_id, true, true, MediaContentType::Persistent); - SetPlayingBackgroundVideo(true); - delegate_manager_->WasShown(); + RunLoopOnce(); + delegate_manager_->SetFrameHiddenForTesting(false); + RunLoopOnce(); histogram_tester.ExpectTotalCount("Media.Android.BackgroundVideoTime", 2); }
diff --git a/content/renderer/media/webmediaplayer_ms.cc b/content/renderer/media/webmediaplayer_ms.cc index 96efe619..6ee3c0d 100644 --- a/content/renderer/media/webmediaplayer_ms.cc +++ b/content/renderer/media/webmediaplayer_ms.cc
@@ -295,8 +295,9 @@ // TODO(perkj, magjed): We use OneShot focus type here so that it takes // audio focus once it starts, and then will not respond to further audio // focus changes. See http://crbug.com/596516 for more details. - delegate_->DidPlay(delegate_id_, hasVideo(), hasAudio(), false, + delegate_->DidPlay(delegate_id_, hasVideo(), hasAudio(), media::MediaContentType::OneShot); + delegate_->SetIdle(delegate_id_, false); } paused_ = false; @@ -320,8 +321,10 @@ if (audio_renderer_) audio_renderer_->Pause(); - if (delegate_) - delegate_->DidPause(delegate_id_, false); + if (delegate_) { + delegate_->DidPause(delegate_id_); + delegate_->SetIdle(delegate_id_, true); + } paused_ = true; } @@ -503,7 +506,7 @@ return 0; } -void WebMediaPlayerMS::OnHidden() { +void WebMediaPlayerMS::OnFrameHidden() { #if defined(OS_ANDROID) DCHECK(thread_checker_.CalledOnValidThread()); @@ -524,7 +527,25 @@ #endif // defined(OS_ANDROID) } -void WebMediaPlayerMS::OnShown() { +void WebMediaPlayerMS::OnFrameClosed() { +#if defined(OS_ANDROID) + if (!paused_) { + pause(); + should_play_upon_shown_ = true; + } + + if (delegate_) + delegate_->PlayerGone(delegate_id_); + + if (frame_deliverer_) { + io_task_runner_->PostTask( + FROM_HERE, base::Bind(&FrameDeliverer::SetRenderFrameSuspended, + base::Unretained(frame_deliverer_.get()), true)); + } +#endif // defined(OS_ANDROID) +} + +void WebMediaPlayerMS::OnFrameShown() { #if defined(OS_ANDROID) DCHECK(thread_checker_.CalledOnValidThread()); @@ -540,27 +561,7 @@ #endif // defined(OS_ANDROID) } -bool WebMediaPlayerMS::OnSuspendRequested(bool must_suspend) { -#if defined(OS_ANDROID) - if (!must_suspend) - return false; - - if (!paused_) { - pause(); - should_play_upon_shown_ = true; - } - - if (delegate_) - delegate_->PlayerGone(delegate_id_); - - if (frame_deliverer_) { - io_task_runner_->PostTask( - FROM_HERE, base::Bind(&FrameDeliverer::SetRenderFrameSuspended, - base::Unretained(frame_deliverer_.get()), true)); - } -#endif // defined(OS_ANDROID) - return true; -} +void WebMediaPlayerMS::OnIdleTimeout() {} void WebMediaPlayerMS::OnPlay() { // TODO(perkj, magjed): It's not clear how WebRTC should work with an
diff --git a/content/renderer/media/webmediaplayer_ms.h b/content/renderer/media/webmediaplayer_ms.h index bbc8d2e..a4b032f 100644 --- a/content/renderer/media/webmediaplayer_ms.h +++ b/content/renderer/media/webmediaplayer_ms.h
@@ -143,9 +143,10 @@ size_t videoDecodedByteCount() const override; // WebMediaPlayerDelegate::Observer implementation. - void OnHidden() override; - void OnShown() override; - bool OnSuspendRequested(bool must_suspend) override; + void OnFrameHidden() override; + void OnFrameClosed() override; + void OnFrameShown() override; + void OnIdleTimeout() override; void OnPlay() override; void OnPause() override; void OnVolumeMultiplierUpdate(double multiplier) override;
diff --git a/content/renderer/media/webmediaplayer_ms_unittest.cc b/content/renderer/media/webmediaplayer_ms_unittest.cc index bed8922..66f6cff 100644 --- a/content/renderer/media/webmediaplayer_ms_unittest.cc +++ b/content/renderer/media/webmediaplayer_ms_unittest.cc
@@ -55,15 +55,15 @@ void DidPlay(int delegate_id, bool has_video, bool has_audio, - bool is_remote, media::MediaContentType type) override { EXPECT_EQ(delegate_id_, delegate_id); EXPECT_FALSE(playing_); playing_ = true; + has_video_ = has_video; is_gone_ = false; } - void DidPause(int delegate_id, bool reached_end_of_stream) override { + void DidPause(int delegate_id) override { EXPECT_EQ(delegate_id_, delegate_id); EXPECT_TRUE(playing_); EXPECT_FALSE(is_gone_); @@ -75,9 +75,28 @@ is_gone_ = true; } - bool IsHidden() override { return is_hidden_; } + void SetIdle(int delegate_id, bool is_idle) override { + EXPECT_EQ(delegate_id_, delegate_id); + is_idle_ = is_idle; + } - bool IsPlayingBackgroundVideo() override { return false; } + bool IsIdle(int delegate_id) override { + EXPECT_EQ(delegate_id_, delegate_id); + return is_idle_; + } + + void ClearStaleFlag(int delegate_id) override { + EXPECT_EQ(delegate_id_, delegate_id); + } + + bool IsStale(int delegate_id) override { + EXPECT_EQ(delegate_id_, delegate_id); + return false; + } + + bool IsFrameHidden() override { return is_hidden_; } + bool IsFrameClosed() override { return false; } + bool IsBackgroundVideoPlaybackUnlocked() override { return false; } void set_hidden(bool is_hidden) { is_hidden_ = is_hidden; } @@ -85,8 +104,10 @@ int delegate_id_ = 1234; Observer* observer_ = nullptr; bool playing_ = false; + bool has_video_ = false; bool is_hidden_ = false; bool is_gone_ = true; + bool is_idle_ = false; DISALLOW_COPY_AND_ASSIGN(FakeWebMediaPlayerDelegate); }; @@ -907,18 +928,18 @@ // A hidden player should start still be playing upon shown. delegate_.set_hidden(false); - player_->OnShown(); + player_->OnFrameShown(); EXPECT_FALSE(player_->paused()); // A hidden event should not pause the player. delegate_.set_hidden(true); - player_->OnHidden(); + player_->OnFrameHidden(); EXPECT_FALSE(player_->paused()); // A user generated pause() should clear the automatic resumption. player_->pause(); delegate_.set_hidden(false); - player_->OnShown(); + player_->OnFrameShown(); EXPECT_TRUE(player_->paused()); // A user generated play() should start playback. @@ -926,15 +947,15 @@ EXPECT_FALSE(player_->paused()); // An OnSuspendRequested() without forced suspension should do nothing. - player_->OnSuspendRequested(false); + player_->OnIdleTimeout(); EXPECT_FALSE(player_->paused()); // An OnSuspendRequested() with forced suspension should pause playback. - player_->OnSuspendRequested(true); + player_->OnFrameClosed(); EXPECT_TRUE(player_->paused()); // OnShown() should restart after a forced suspension. - player_->OnShown(); + player_->OnFrameShown(); EXPECT_FALSE(player_->paused()); EXPECT_CALL(*this, DoSetWebLayer(false));
diff --git a/google_apis/drive/drive_api_parser.h b/google_apis/drive/drive_api_parser.h index 75ff0e7..43fa4f1 100644 --- a/google_apis/drive/drive_api_parser.h +++ b/google_apis/drive/drive_api_parser.h
@@ -10,11 +10,11 @@ #include <memory> #include <string> #include <utility> +#include <vector> #include "base/compiler_specific.h" #include "base/gtest_prod_util.h" #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "base/strings/string_piece.h" #include "base/time/time.h" #include "url/gurl.h" @@ -189,35 +189,37 @@ // List of primary mime types supported by this WebApp. Primary status should // trigger this WebApp becoming the default handler of file instances that // have these mime types. - const ScopedVector<std::string>& primary_mimetypes() const { + const std::vector<std::unique_ptr<std::string>>& primary_mimetypes() const { return primary_mimetypes_; } // List of secondary mime types supported by this WebApp. Secondary status // should make this WebApp show up in "Open with..." pop-up menu of the // default action menu for file with matching mime types. - const ScopedVector<std::string>& secondary_mimetypes() const { + const std::vector<std::unique_ptr<std::string>>& secondary_mimetypes() const { return secondary_mimetypes_; } // List of primary file extensions supported by this WebApp. Primary status // should trigger this WebApp becoming the default handler of file instances // that match these extensions. - const ScopedVector<std::string>& primary_file_extensions() const { + const std::vector<std::unique_ptr<std::string>>& primary_file_extensions() + const { return primary_file_extensions_; } // List of secondary file extensions supported by this WebApp. Secondary // status should make this WebApp show up in "Open with..." pop-up menu of the // default action menu for file with matching extensions. - const ScopedVector<std::string>& secondary_file_extensions() const { + const std::vector<std::unique_ptr<std::string>>& secondary_file_extensions() + const { return secondary_file_extensions_; } // Returns Icons for this application. An application can have multiple // icons for different purpose (application, document, shared document) // in several sizes. - const ScopedVector<DriveAppIcon>& icons() const { + const std::vector<std::unique_ptr<DriveAppIcon>>& icons() const { return icons_; } @@ -234,22 +236,22 @@ } void set_removable(bool removable) { removable_ = removable; } void set_primary_mimetypes( - ScopedVector<std::string> primary_mimetypes) { + std::vector<std::unique_ptr<std::string>> primary_mimetypes) { primary_mimetypes_ = std::move(primary_mimetypes); } void set_secondary_mimetypes( - ScopedVector<std::string> secondary_mimetypes) { + std::vector<std::unique_ptr<std::string>> secondary_mimetypes) { secondary_mimetypes_ = std::move(secondary_mimetypes); } void set_primary_file_extensions( - ScopedVector<std::string> primary_file_extensions) { + std::vector<std::unique_ptr<std::string>> primary_file_extensions) { primary_file_extensions_ = std::move(primary_file_extensions); } void set_secondary_file_extensions( - ScopedVector<std::string> secondary_file_extensions) { + std::vector<std::unique_ptr<std::string>> secondary_file_extensions) { secondary_file_extensions_ = std::move(secondary_file_extensions); } - void set_icons(ScopedVector<DriveAppIcon> icons) { + void set_icons(std::vector<std::unique_ptr<DriveAppIcon>> icons) { icons_ = std::move(icons); } void set_create_url(const GURL& url) { @@ -271,11 +273,11 @@ bool supports_create_; bool removable_; GURL create_url_; - ScopedVector<std::string> primary_mimetypes_; - ScopedVector<std::string> secondary_mimetypes_; - ScopedVector<std::string> primary_file_extensions_; - ScopedVector<std::string> secondary_file_extensions_; - ScopedVector<DriveAppIcon> icons_; + std::vector<std::unique_ptr<std::string>> primary_mimetypes_; + std::vector<std::unique_ptr<std::string>> secondary_mimetypes_; + std::vector<std::unique_ptr<std::string>> primary_file_extensions_; + std::vector<std::unique_ptr<std::string>> secondary_file_extensions_; + std::vector<std::unique_ptr<DriveAppIcon>> icons_; DISALLOW_COPY_AND_ASSIGN(AppResource); }; @@ -299,12 +301,16 @@ const std::string& etag() const { return etag_; } // Returns a vector of applications. - const ScopedVector<AppResource>& items() const { return items_; } + const std::vector<std::unique_ptr<AppResource>>& items() const { + return items_; + } void set_etag(const std::string& etag) { etag_ = etag; } - void set_items(ScopedVector<AppResource> items) { items_ = std::move(items); } + void set_items(std::vector<std::unique_ptr<AppResource>> items) { + items_ = std::move(items); + } private: friend class DriveAPIParserTest; @@ -315,7 +321,7 @@ bool Parse(const base::Value& value); std::string etag_; - ScopedVector<AppResource> items_; + std::vector<std::unique_ptr<AppResource>> items_; DISALLOW_COPY_AND_ASSIGN(AppList); }; @@ -613,8 +619,12 @@ const GURL& next_link() const { return next_link_; } // Returns a set of files in this list. - const ScopedVector<FileResource>& items() const { return items_; } - ScopedVector<FileResource>* mutable_items() { return &items_; } + const std::vector<std::unique_ptr<FileResource>>& items() const { + return items_; + } + std::vector<std::unique_ptr<FileResource>>* mutable_items() { + return &items_; + } void set_next_link(const GURL& next_link) { next_link_ = next_link; @@ -629,7 +639,7 @@ bool Parse(const base::Value& value); GURL next_link_; - ScopedVector<FileResource> items_; + std::vector<std::unique_ptr<FileResource>> items_; DISALLOW_COPY_AND_ASSIGN(FileList); }; @@ -721,8 +731,12 @@ int64_t largest_change_id() const { return largest_change_id_; } // Returns a set of changes in this list. - const ScopedVector<ChangeResource>& items() const { return items_; } - ScopedVector<ChangeResource>* mutable_items() { return &items_; } + const std::vector<std::unique_ptr<ChangeResource>>& items() const { + return items_; + } + std::vector<std::unique_ptr<ChangeResource>>* mutable_items() { + return &items_; + } void set_next_link(const GURL& next_link) { next_link_ = next_link; @@ -741,7 +755,7 @@ GURL next_link_; int64_t largest_change_id_; - ScopedVector<ChangeResource> items_; + std::vector<std::unique_ptr<ChangeResource>> items_; DISALLOW_COPY_AND_ASSIGN(ChangeList); };
diff --git a/google_apis/drive/drive_api_requests.h b/google_apis/drive/drive_api_requests.h index 1802d0d..9ccd9fa7 100644 --- a/google_apis/drive/drive_api_requests.h +++ b/google_apis/drive/drive_api_requests.h
@@ -15,6 +15,7 @@ #include "base/callback_forward.h" #include "base/location.h" #include "base/macros.h" +#include "base/memory/scoped_vector.h" #include "base/sequenced_task_runner.h" #include "base/task_runner_util.h" #include "base/time/time.h"
diff --git a/ios/chrome/browser/payments/BUILD.gn b/ios/chrome/browser/payments/BUILD.gn index 87f988e..19ebe31 100644 --- a/ios/chrome/browser/payments/BUILD.gn +++ b/ios/chrome/browser/payments/BUILD.gn
@@ -30,8 +30,6 @@ "payment_request_utils.mm", "payment_request_view_controller.h", "payment_request_view_controller.mm", - "payment_request_web_state_observer.h", - "payment_request_web_state_observer.mm", "shipping_address_selection_coordinator.h", "shipping_address_selection_coordinator.mm", "shipping_address_selection_view_controller.h",
diff --git a/ios/chrome/browser/payments/payment_request_manager.mm b/ios/chrome/browser/payments/payment_request_manager.mm index 657183145..b3565d7 100644 --- a/ios/chrome/browser/payments/payment_request_manager.mm +++ b/ios/chrome/browser/payments/payment_request_manager.mm
@@ -17,7 +17,6 @@ #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/payments/js_payment_request_manager.h" #import "ios/chrome/browser/payments/payment_request_coordinator.h" -#import "ios/chrome/browser/payments/payment_request_web_state_observer.h" #include "ios/web/public/favicon_status.h" #include "ios/web/public/navigation_item.h" #include "ios/web/public/navigation_manager.h" @@ -28,14 +27,15 @@ #import "ios/web/public/web_state/js/crw_js_injection_receiver.h" #include "ios/web/public/web_state/url_verification_constants.h" #include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state_observer_bridge.h" namespace { // Command prefix for injected JavaScript. const std::string kCommandPrefix = "paymentRequest"; } // namespace -@interface PaymentRequestManager ()<PaymentRequestCoordinatorDelegate, - PaymentRequestWebStateDelegate> { +@interface PaymentRequestManager ()<CRWWebStateObserver, + PaymentRequestCoordinatorDelegate> { // View controller used to present the PaymentRequest view controller. base::WeakNSObject<UIViewController> _baseViewController; @@ -46,7 +46,7 @@ web::WebState* _webState; // Observer for |_webState|. - std::unique_ptr<PaymentRequestWebStateObserver> _webStateObserver; + std::unique_ptr<web::WebStateObserverBridge> _webStateObserver; // Object that manages JavaScript injection into the web view. base::WeakNSObject<JSPaymentRequestManager> _paymentRequestJsManager; @@ -101,10 +101,6 @@ _personalDataManager = autofill::PersonalDataManagerFactory::GetForBrowserState( browserState->GetOriginalChromeBrowserState()); - - // Set up the web state observer. This lasts as long as this object does, - // but it will observe and un-observe the web tabs as it changes over time. - _webStateObserver.reset(new PaymentRequestWebStateObserver(self)); } return self; } @@ -122,7 +118,7 @@ [webState->GetJSInjectionReceiver() instanceOfClass:[JSPaymentRequestManager class]])); _webState = webState; - _webStateObserver->ObserveWebState(webState); + _webStateObserver.reset(new web::WebStateObserverBridge(webState, self)); [self enableCurrentWebState]; } else { _webState = nullptr; @@ -171,7 +167,7 @@ return; } - if (_enabled && [self webStateContentIsSecureHTML]) { + if (_enabled) { if (!_webStateEnabled) { base::WeakNSObject<PaymentRequestManager> weakSelf(self); auto callback = @@ -186,8 +182,6 @@ _webStateEnabled = YES; } - - [self initializeWebViewForPaymentRequest]; } else { [self disableCurrentWebState]; } @@ -203,7 +197,7 @@ - (void)disconnectWebState { if (_webState) { _paymentRequestJsManager.reset(); - _webStateObserver->ObserveWebState(nullptr); + _webStateObserver.reset(); [self disableCurrentWebState]; } } @@ -211,10 +205,6 @@ - (void)initializeWebViewForPaymentRequest { DCHECK(_webStateEnabled); - if (![self webStateContentIsSecureHTML]) { - return; - } - [_paymentRequestJsManager inject]; _isScriptInjected = YES; } @@ -324,14 +314,14 @@ completionHandler:nil]; } -#pragma mark - PaymentRequestWebStateDelegate methods +#pragma mark - CRWWebStateObserver methods -- (void)pageLoadedWithStatus:(web::PageLoadCompletionStatus)loadStatus { - if (loadStatus != web::PageLoadCompletionStatus::SUCCESS) - return; - - [self dismissUI]; +- (void)webState:(web::WebState*)webState + didCommitNavigationWithDetails: + (const web::LoadCommittedDetails&)load_details { _isScriptInjected = NO; + [self dismissUI]; + [self initializeWebViewForPaymentRequest]; [self enableCurrentWebState]; }
diff --git a/ios/chrome/browser/payments/payment_request_web_state_observer.h b/ios/chrome/browser/payments/payment_request_web_state_observer.h deleted file mode 100644 index 7f2d9bf..0000000 --- a/ios/chrome/browser/payments/payment_request_web_state_observer.h +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright 2016 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 IOS_CHROME_BROWSER_PAYMENTS_PAYMENT_REQUEST_WEB_STATE_OBSERVER_H_ -#define IOS_CHROME_BROWSER_PAYMENTS_PAYMENT_REQUEST_WEB_STATE_OBSERVER_H_ - -#import <UIKit/UIKit.h> - -#include "ios/web/public/web_state/web_state_observer.h" - -@protocol PaymentRequestWebStateDelegate<NSObject> -@optional -- (void)pageLoadedWithStatus:(web::PageLoadCompletionStatus)loadStatus; - -@end - -class PaymentRequestWebStateObserver : public web::WebStateObserver { - public: - explicit PaymentRequestWebStateObserver( - id<PaymentRequestWebStateDelegate> delegate); - ~PaymentRequestWebStateObserver() override; - - void ObserveWebState(web::WebState* web_state); - - private: - void PageLoaded( - web::PageLoadCompletionStatus load_completion_status) override; - - id<PaymentRequestWebStateDelegate> delegate_; -}; - -#endif // IOS_CHROME_BROWSER_PAYMENTS_PAYMENT_REQUEST_WEB_STATE_OBSERVER_H_
diff --git a/ios/chrome/browser/payments/payment_request_web_state_observer.mm b/ios/chrome/browser/payments/payment_request_web_state_observer.mm deleted file mode 100644 index f8c2b23..0000000 --- a/ios/chrome/browser/payments/payment_request_web_state_observer.mm +++ /dev/null
@@ -1,22 +0,0 @@ -// Copyright 2016 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. - -#import "ios/chrome/browser/payments/payment_request_web_state_observer.h" - -PaymentRequestWebStateObserver::PaymentRequestWebStateObserver( - id<PaymentRequestWebStateDelegate> delegate) - : web::WebStateObserver(), delegate_(delegate) {} - -PaymentRequestWebStateObserver::~PaymentRequestWebStateObserver() {} - -void PaymentRequestWebStateObserver::ObserveWebState(web::WebState* web_state) { - Observe(web_state); -} - -void PaymentRequestWebStateObserver::PageLoaded( - web::PageLoadCompletionStatus load_completion_status) { - if ([delegate_ respondsToSelector:@selector(pageLoadedWithStatus:)]) { - [delegate_ pageLoadedWithStatus:load_completion_status]; - } -}
diff --git a/media/audio/audio_output_proxy_unittest.cc b/media/audio/audio_output_proxy_unittest.cc index 78588f9..06b2090 100644 --- a/media/audio/audio_output_proxy_unittest.cc +++ b/media/audio/audio_output_proxy_unittest.cc
@@ -463,6 +463,23 @@ proxy->Close(); } + void DispatcherDestroyed_AfterStop( + std::unique_ptr<AudioOutputDispatcher> dispatcher) { + MockAudioOutputStream stream(&manager_, params_); + EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _)) + .WillOnce(Return(&stream)); + EXPECT_CALL(stream, Open()).WillOnce(Return(true)); + EXPECT_CALL(stream, Close()).Times(1); + EXPECT_CALL(stream, SetVolume(_)).Times(1); + + AudioOutputProxy* proxy = dispatcher->CreateStreamProxy(); + EXPECT_TRUE(proxy->Open()); + proxy->Start(&callback_); + proxy->Stop(); + dispatcher.reset(); + proxy->Close(); + } + base::MessageLoop message_loop_; std::unique_ptr<AudioOutputDispatcherImpl> dispatcher_impl_; MockAudioManager manager_; @@ -609,6 +626,14 @@ DispatcherDestroyed_BeforeStop(std::move(resampler_)); } +TEST_F(AudioOutputProxyTest, DispatcherDestroyed_AfterStop) { + DispatcherDestroyed_AfterStop(std::move(dispatcher_impl_)); +} + +TEST_F(AudioOutputResamplerTest, DispatcherDestroyed_AfterStop) { + DispatcherDestroyed_AfterStop(std::move(resampler_)); +} + // Simulate AudioOutputStream::Create() failure with a low latency stream and // ensure AudioOutputResampler falls back to the high latency path. TEST_F(AudioOutputResamplerTest, LowLatencyCreateFailedFallback) {
diff --git a/media/audio/audio_output_resampler.cc b/media/audio/audio_output_resampler.cc index 5dbba5d..9439a63 100644 --- a/media/audio/audio_output_resampler.cc +++ b/media/audio/audio_output_resampler.cc
@@ -242,8 +242,9 @@ } AudioOutputResampler::~AudioOutputResampler() { - for (auto& iter : callbacks_) { - StopStream(iter.first); + for (const auto& item : callbacks_) { + if (item.second->started()) + StopStreamInternal(item); } } @@ -362,25 +363,15 @@ void AudioOutputResampler::StopStream(AudioOutputProxy* stream_proxy) { DCHECK(task_runner_->BelongsToCurrentThread()); - dispatcher_->StopStream(stream_proxy); - // Now that StopStream() has completed the underlying physical stream should - // be stopped and no longer calling OnMoreData(), making it safe to Stop() the - // OnMoreDataConverter. CallbackMap::iterator it = callbacks_.find(stream_proxy); - if (it != callbacks_.end()) { - it->second->Stop(); - - // Destroy idle streams if any errors occurred during output; this ensures - // bad streams will not be reused. Note: Errors may occur during the Stop() - // call above. - if (it->second->error_occurred()) - dispatcher_->CloseAllIdleStreams(); - } + DCHECK(it != callbacks_.end()); + StopStreamInternal(*it); } void AudioOutputResampler::CloseStream(AudioOutputProxy* stream_proxy) { DCHECK(task_runner_->BelongsToCurrentThread()); + dispatcher_->CloseStream(stream_proxy); // We assume that StopStream() is always called prior to CloseStream(), so @@ -396,6 +387,27 @@ } } +void AudioOutputResampler::StopStreamInternal( + const CallbackMap::value_type& item) { + AudioOutputProxy* stream_proxy = item.first; + OnMoreDataConverter* callback = item.second.get(); + DCHECK(callback->started()); + + // Stop the underlying physical stream. + dispatcher_->StopStream(stream_proxy); + + // Now that StopStream() has completed the underlying physical stream should + // be stopped and no longer calling OnMoreData(), making it safe to Stop() the + // OnMoreDataConverter. + callback->Stop(); + + // Destroy idle streams if any errors occurred during output; this ensures + // bad streams will not be reused. Note: Errors may occur during the Stop() + // call above. + if (callback->error_occurred()) + dispatcher_->CloseAllIdleStreams(); +} + OnMoreDataConverter::OnMoreDataConverter(const AudioParameters& input_params, const AudioParameters& output_params) : io_ratio_(static_cast<double>(input_params.GetBytesPerSecond()) /
diff --git a/media/audio/audio_output_resampler.h b/media/audio/audio_output_resampler.h index cbd9c9e1..da512e0 100644 --- a/media/audio/audio_output_resampler.h +++ b/media/audio/audio_output_resampler.h
@@ -48,6 +48,9 @@ void CloseStream(AudioOutputProxy* stream_proxy) override; private: + using CallbackMap = + std::map<AudioOutputProxy*, std::unique_ptr<OnMoreDataConverter>>; + // Converts low latency based output parameters into high latency // appropriate output parameters in error situations. void SetupFallbackParams(); @@ -58,13 +61,14 @@ // Used to initialize |dispatcher_|. void Initialize(); + // Stops the stream corresponding to the |item| in |callbacks_|. + void StopStreamInternal(const CallbackMap::value_type& item); + // Dispatcher to proxy all AudioOutputDispatcher calls too. std::unique_ptr<AudioOutputDispatcherImpl> dispatcher_; // Map of outstanding OnMoreDataConverter objects. A new object is created // on every StartStream() call and destroyed on CloseStream(). - typedef std::map<AudioOutputProxy*, std::unique_ptr<OnMoreDataConverter>> - CallbackMap; CallbackMap callbacks_; // Used by AudioOutputDispatcherImpl; kept so we can reinitialize on the fly.
diff --git a/media/base/audio_renderer_mixer_unittest.cc b/media/base/audio_renderer_mixer_unittest.cc index f0912f4..9a1bd79 100644 --- a/media/base/audio_renderer_mixer_unittest.cc +++ b/media/base/audio_renderer_mixer_unittest.cc
@@ -553,7 +553,7 @@ // support single item lists and we don't want these test cases to run for every // parameter set. INSTANTIATE_TEST_CASE_P( - AudioRendererMixerBehavioralTest, + /* no prefix */, AudioRendererMixerBehavioralTest, testing::ValuesIn(std::vector<AudioRendererMixerTestData>( 1,
diff --git a/media/blink/webmediaplayer_delegate.h b/media/blink/webmediaplayer_delegate.h index 62c93bc..0795c8d 100644 --- a/media/blink/webmediaplayer_delegate.h +++ b/media/blink/webmediaplayer_delegate.h
@@ -12,73 +12,113 @@ enum class MediaContentType; -// An interface to allow a WebMediaPlayer to communicate changes of state to -// objects that need to know. +// An interface to collect WebMediaPlayer state changes and to fan out commands +// from the browser. class WebMediaPlayerDelegate { public: + // Note: WebMediaPlayerDelegate implementations should not call an Observer + // method on a stack that includes a call from the player. + // Note: It is likely that players will call WebMediaPlayerDelegate methods + // from within Observer callbacks. class Observer { public: - // Called when the WebMediaPlayer enters the background or foreground - // respectively. Note: Some implementations will stop playback when hidden, - // and thus subsequently call WebMediaPlayerDelegate::PlayerGone(). - virtual void OnHidden() = 0; - virtual void OnShown() = 0; + // Called when the host frame is hidden (usually by tab switching). + // Note: OnFrameHidden() is not called when the frame is closed, even though + // IsFrameHidden() will start returning true. + virtual void OnFrameHidden() = 0; - // Requests a WebMediaPlayer instance to release all idle resources. If - // |must_suspend| is true, the player must stop playback, release all idle - // resources, and finally call WebMediaPlayerDelegate::PlayerGone(). If - // |must_suspend| is false, the player may ignore the request. Optionally, - // it may do some or all of the same actions as when |must_suspend| is true. - // To be clear, the player is not required to call PlayerGone() when - // |must_suspend| is false. - // Return false to reject the request and indicate that further calls to - // OnSuspendRequested() are required. Otherwise the Observer is removed - // from the idle list. - virtual bool OnSuspendRequested(bool must_suspend) = 0; + // Called when the host frame is closed. + // Note: It is possible for a closed frame to be shown again. (Android only; + // other platforms tear down players when the host frame is closed.) There + // is no callback for frame opening, observers are expected to wait until + // OnFrameShown(). + // TODO(sandersd): Experiment to verify exactly what gets called when + // restoring a closed tab on Android. + virtual void OnFrameClosed() = 0; + // Called when the host frame is shown (usually by tab switching). + virtual void OnFrameShown() = 0; + + // Called when an idle player has become stale, usually interpreted to mean + // that it is unlikely to be interacted with in the near future. + // + // Players should typically respond by releasing resources, for example by + // discarding their decoders. + virtual void OnIdleTimeout() = 0; + + // Called when external controls are activated. virtual void OnPlay() = 0; virtual void OnPause() = 0; - // Playout volume should be set to current_volume * multiplier. The range is - // [0, 1] and is typically 1. + // Called to control audio ducking. Output volume should be set to + // |player_volume| * |multiplier|. The range of |multiplier| is [0, 1], + // where 1 indicates normal (non-ducked) playback. virtual void OnVolumeMultiplierUpdate(double multiplier) = 0; }; - WebMediaPlayerDelegate() {} + // Returns true if the host frame is hidden or closed. + virtual bool IsFrameHidden() = 0; - // Subscribe or unsubscribe from observer callbacks respectively. A client - // must use the delegate id returned by AddObserver() for all other calls. + // Returns true if the host frame is closed. + virtual bool IsFrameClosed() = 0; + + // Returns |true| if background video playback permission has been granted, + // for example by a media session 'play' command. + virtual bool IsBackgroundVideoPlaybackUnlocked() = 0; + + // Subscribe to observer callbacks. A player must use the returned |player_id| + // for the rest of the calls below. virtual int AddObserver(Observer* observer) = 0; - virtual void RemoveObserver(int delegate_id) = 0; - // The specified player started playing media. - virtual void DidPlay(int delegate_id, + // Unsubscribe from observer callbacks. + virtual void RemoveObserver(int player_id) = 0; + + // Notify playback started. This will request appropriate wake locks and, if + // applicable, show a pause button in external controls. + // + // DidPlay() should not be called for remote playback. + virtual void DidPlay(int player_id, bool has_video, bool has_audio, - bool is_remote, media::MediaContentType media_content_type) = 0; - // The specified player stopped playing media. This may be called at any time - // with or without a DidPlay() having previously occurred. Calling this will - // cause the delegate to be registered for idle suspension. I.e., after some - // time elapses without a DidPlay(), OnSuspendRequested() will be issued. - virtual void DidPause(int delegate_id, bool reached_end_of_stream) = 0; + // Notify that playback is paused. This will drop wake locks and, if + // applicable, show a play button in external controls. + // TODO(sandersd): It may be helpful to get |has_audio| and |has_video| here, + // so that we can do the right thing with media that starts paused. + virtual void DidPause(int player_id) = 0; - // The specified player was destroyed or suspended and will no longer accept - // Observer::OnPlay() or Observer::OnPause() calls. This may be called - // multiple times in row. Note: Clients must still call RemoveObserver() to - // unsubscribe from callbacks. - virtual void PlayerGone(int delegate_id) = 0; + // Notify that playback is stopped. This will drop wake locks and remove any + // external controls. + // + // Clients must still call RemoveObserver() to unsubscribe from observer + // callbacks. + virtual void PlayerGone(int player_id) = 0; - // Returns whether the render frame is currently hidden. - virtual bool IsHidden() = 0; + // Set the player's idle state. While idle, a player may recieve an + // OnIdleTimeout() callback. + // TODO(sandersd): Merge this into DidPlay()/DidPause()/PlayerGone(). + virtual void SetIdle(int player_id, bool is_idle) = 0; - // Returns whether there's a video playing in background within the render - // frame. - virtual bool IsPlayingBackgroundVideo() = 0; + // Get the player's idle state. A stale player is considered idle. + // TODO(sandersd): Remove this. It is only used in tests and in one special + // case in WMPI. + virtual bool IsIdle(int player_id) = 0; + + // Returns a stale player to an idle state, and resumes OnIdleTimeout() calls + // without an additional idle timeout. + // TODO(sandersd): This exists only to support WMPI's didLoadingProgress() + // workaround. A better option may be to take a 'minimum idle' duration in + // SetIdle(). + virtual void ClearStaleFlag(int player_id) = 0; + + // Returns |true| if the player is stale; that is that OnIdleTimeout() was + // called and returned |true|. + virtual bool IsStale(int player_id) = 0; protected: - virtual ~WebMediaPlayerDelegate() {} + WebMediaPlayerDelegate() = default; + virtual ~WebMediaPlayerDelegate() = default; }; } // namespace media
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc index b0e7d1c..aabb040 100644 --- a/media/blink/webmediaplayer_impl.cc +++ b/media/blink/webmediaplayer_impl.cc
@@ -149,9 +149,9 @@ return base::TimeDelta::FromSecondsD(p_this->currentTime()); } -// How much time must have elapsed since loading last progressed before the -// player is eligible for idle suspension. -constexpr base::TimeDelta kLoadingToIdleTimeout = +// How much time must have elapsed since loading last progressed before we +// assume that the decoder will have had time to complete preroll. +constexpr base::TimeDelta kPrerollAttemptTimeout = base::TimeDelta::FromSeconds(3); } // namespace @@ -182,8 +182,7 @@ const WebMediaPlayerParams& params) : frame_(frame), delegate_state_(DelegateState::GONE), - is_idle_(false), - must_suspend_(false), + delegate_has_audio_(false), network_state_(WebMediaPlayer::NetworkStateEmpty), ready_state_(WebMediaPlayer::ReadyStateHaveNothing), highest_ready_state_(WebMediaPlayer::ReadyStateHaveNothing), @@ -243,6 +242,7 @@ use_fallback_path_(false), is_encrypted_(false), underflow_count_(0), + preroll_attempt_pending_(false), observer_(params.media_observer()) { DCHECK(!adjust_allocated_memory_cb_.is_null()); DCHECK(renderer_factory_); @@ -253,8 +253,10 @@ force_video_overlays_ = base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kForceVideoOverlays); - if (delegate_) + if (delegate_) { delegate_id_ = delegate_->AddObserver(this); + delegate_->SetIdle(delegate_id_, true); + } media_log_->AddEvent( media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_CREATED)); @@ -425,8 +427,10 @@ return; } #endif + // TODO(sandersd): Do we want to reset the idle timer here? + if (delegate_) + delegate_->SetIdle(delegate_id_, false); paused_ = false; - is_idle_ = false; pipeline_.SetPlaybackRate(playback_rate_); background_pause_timer_.Stop(); @@ -531,11 +535,11 @@ if (watch_time_reporter_) watch_time_reporter_->OnSeeking(); - // TODO(sandersd): Ideally we would not clear the idle state if - // |pipeline_controller_| can elide the seek. - is_idle_ = false; + // TODO(sandersd): Move |seeking_| to PipelineController. + // TODO(sandersd): Do we want to reset the idle timer here? + if (delegate_) + delegate_->SetIdle(delegate_id_, false); ended_ = false; - seeking_ = true; seek_time_ = time; if (paused_) @@ -815,6 +819,26 @@ return blink::WebTimeRanges(&seekable_range, 1); } +bool WebMediaPlayerImpl::IsPrerollAttemptNeeded() { + // TODO(sandersd): Replace with |highest_ready_state_since_seek_| if we need + // to ensure that preroll always gets a chance to complete. + // See http://crbug.com/671525. + if (highest_ready_state_ >= ReadyState::ReadyStateHaveFutureData) + return false; + + if (preroll_attempt_pending_) + return true; + + // Freshly initialized; there has never been any loading progress. (Otherwise + // |preroll_attempt_pending_| would be true when the start time is null.) + if (preroll_attempt_start_time_.is_null()) + return false; + + base::TimeDelta preroll_attempt_duration = + tick_clock_->NowTicks() - preroll_attempt_start_time_; + return preroll_attempt_duration < kPrerollAttemptTimeout; +} + bool WebMediaPlayerImpl::didLoadingProgress() { DCHECK(main_task_runner_->BelongsToCurrentThread()); @@ -823,19 +847,22 @@ const bool data_progress = buffered_data_source_host_.DidLoadingProgress(); const bool did_loading_progress = pipeline_progress || data_progress; - // If we've idle suspended before reaching kHaveFutureData and loading has - // progressed we need to spin up the renderer and figure out if we have enough - // data yet; |client_| may be waiting on this signal to trigger playback. The - // idle timeout is long enough that this is a low-cost operation. - if (highest_ready_state_ < ReadyState::ReadyStateHaveFutureData && - pipeline_controller_.IsSuspended() && did_loading_progress && is_idle_) { - is_idle_ = false; + if (did_loading_progress && + highest_ready_state_ < ReadyState::ReadyStateHaveFutureData) { + // Reset the preroll attempt clock. + preroll_attempt_pending_ = true; + preroll_attempt_start_time_ = base::TimeTicks(); + + // Clear any 'stale' flag and give the pipeline a chance to resume. If we + // are already resumed, this will cause |preroll_attempt_start_time_| to be + // set. + // TODO(sandersd): Should this be on the same stack? It might be surprising + // that didLoadingProgress() can synchronously change state. + if (delegate_) + delegate_->ClearStaleFlag(delegate_id_); UpdatePlayState(); } - if (did_loading_progress) - last_time_loading_progressed_ = tick_clock_->NowTicks(); - return did_loading_progress; } @@ -1253,8 +1280,10 @@ data_source_->OnBufferingHaveEnough(false); // Blink expects a timeChanged() in response to a seek(). - if (should_notify_time_changed_) + if (should_notify_time_changed_) { + should_notify_time_changed_ = false; client_->timeChanged(); + } // Once we have enough, start reporting the total memory usage. We'll also // report once playback starts. @@ -1375,7 +1404,7 @@ video_weblayer_->layer()->SetContentsOpaque(opaque_); } -void WebMediaPlayerImpl::OnHidden() { +void WebMediaPlayerImpl::OnFrameHidden() { DCHECK(main_task_runner_->BelongsToCurrentThread()); if (watch_time_reporter_) @@ -1400,8 +1429,15 @@ ScheduleIdlePauseTimer(); } -void WebMediaPlayerImpl::OnShown() { +void WebMediaPlayerImpl::OnFrameClosed() { DCHECK(main_task_runner_->BelongsToCurrentThread()); + UpdatePlayState(); +} + +void WebMediaPlayerImpl::OnFrameShown() { + DCHECK(main_task_runner_->BelongsToCurrentThread()); + background_pause_timer_.Stop(); + if (watch_time_reporter_) watch_time_reporter_->OnShown(); @@ -1410,9 +1446,6 @@ base::Bind(&VideoFrameCompositor::SetForegroundTime, base::Unretained(compositor_), base::TimeTicks::Now())); - must_suspend_ = false; - background_pause_timer_.Stop(); - if (paused_when_hidden_) { paused_when_hidden_ = false; OnPlay(); // Calls UpdatePlayState() so return afterwards. @@ -1424,37 +1457,17 @@ UpdatePlayState(); } -bool WebMediaPlayerImpl::OnSuspendRequested(bool must_suspend) { +void WebMediaPlayerImpl::OnIdleTimeout() { DCHECK(main_task_runner_->BelongsToCurrentThread()); - if (must_suspend) { - must_suspend_ = true; - UpdatePlayState(); - return true; + // If we are attempting preroll, clear the stale flag. + if (IsPrerollAttemptNeeded()) { + if (delegate_) + delegate_->ClearStaleFlag(delegate_id_); + return; } - // If we're beyond HaveFutureData, we can safely suspend at any time. - if (highest_ready_state_ >= WebMediaPlayer::ReadyStateHaveFutureData) { - is_idle_ = true; - UpdatePlayState(); - return true; - } - - // Before HaveFutureData blink will not call play(), so we must be careful to - // only suspend if we'll eventually receive an event that will trigger a - // resume. If the last time loading progressed was a while ago, and we still - // haven't reached HaveFutureData, we assume that we're waiting on more data - // to continue pre-rolling. When that data is loaded the pipeline will be - // resumed by didLoadingProgress(). - if (last_time_loading_progressed_.is_null() || - (tick_clock_->NowTicks() - last_time_loading_progressed_) > - kLoadingToIdleTimeout) { - is_idle_ = true; - UpdatePlayState(); - return true; - } - - return false; + UpdatePlayState(); } void WebMediaPlayerImpl::OnPlay() { @@ -1791,43 +1804,46 @@ bool is_backgrounded = IsBackgroundedSuspendEnabled() && IsHidden(); PlayState state = UpdatePlayState_ComputePlayState( is_remote, is_streaming, is_suspended, is_backgrounded); - SetDelegateState(state.delegate_state); + SetDelegateState(state.delegate_state, state.is_idle); SetMemoryReportingState(state.is_memory_reporting_enabled); SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_); } -void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state) { +void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state, + bool is_idle) { if (!delegate_) return; - if (delegate_state_ == new_state) { - if (delegate_state_ != DelegateState::PLAYING || - autoplay_muted_ == client_->isAutoplayingMuted()) { - return; - } + // Prevent duplicate delegate calls. + // TODO(sandersd): Move this deduplication into the delegate itself. + // TODO(sandersd): WebContentsObserverSanityChecker does not allow sending the + // 'playing' IPC more than once in a row, even if the metadata has changed. + // Figure out whether it should. + bool has_audio = hasAudio() && !client_->isAutoplayingMuted(); + if (delegate_state_ == new_state && + (delegate_state_ != DelegateState::PLAYING || + delegate_has_audio_ == has_audio)) { + return; } - delegate_state_ = new_state; + delegate_has_audio_ = has_audio; - switch (delegate_state_) { + switch (new_state) { case DelegateState::GONE: delegate_->PlayerGone(delegate_id_); break; case DelegateState::PLAYING: { - autoplay_muted_ = client_->isAutoplayingMuted(); - bool has_audio = autoplay_muted_ ? false : hasAudio(); delegate_->DidPlay( - delegate_id_, hasVideo(), has_audio, false, + delegate_id_, hasVideo(), has_audio, media::DurationToMediaContentType(pipeline_.GetMediaDuration())); break; } case DelegateState::PAUSED: - delegate_->DidPause(delegate_id_, false); - break; - case DelegateState::ENDED: - delegate_->DidPause(delegate_id_, true); + delegate_->DidPause(delegate_id_); break; } + + delegate_->SetIdle(delegate_id_, is_idle); } void WebMediaPlayerImpl::SetMemoryReportingState( @@ -1873,12 +1889,20 @@ can_suspend_state_ = CanSuspendState::YES; #endif - if (can_suspend_state_ == CanSuspendState::NO) - return; - - if (is_suspended) { + if (is_suspended && can_suspend_state_ != CanSuspendState::NO) { + // If we were not resumed for long enough to satisfy the preroll attempt, + // reset the clock. + if (!preroll_attempt_pending_ && IsPrerollAttemptNeeded()) { + preroll_attempt_pending_ = true; + preroll_attempt_start_time_ = base::TimeTicks(); + } pipeline_controller_.Suspend(); } else { + // When resuming, start the preroll attempt clock. + if (preroll_attempt_pending_) { + preroll_attempt_pending_ = false; + preroll_attempt_start_time_ = tick_clock_->NowTicks(); + } pipeline_controller_.Resume(); } } @@ -1890,6 +1914,9 @@ bool is_backgrounded) { PlayState result; + bool must_suspend = delegate_ && delegate_->IsFrameClosed(); + bool is_stale = delegate_ && delegate_->IsStale(delegate_id_); + // This includes both data source (before pipeline startup) and pipeline // errors. bool has_error = IsNetworkStateError(network_state_); @@ -1910,7 +1937,7 @@ bool can_play_backgrounded = is_backgrounded_video && !is_remote && hasAudio() && IsResumeBackgroundVideosEnabled(); bool is_background_playing = - delegate_ && delegate_->IsPlayingBackgroundVideo(); + delegate_ && delegate_->IsBackgroundVideoPlaybackUnlocked(); bool background_suspended = !is_streaming && is_backgrounded_video && !(can_play_backgrounded && is_background_playing); bool background_pause_suspended = @@ -1923,16 +1950,16 @@ // TODO(sandersd): Make the delegate suspend idle players immediately when // hidden. bool idle_suspended = - !is_streaming && is_idle_ && paused_ && !seeking_ && !overlay_enabled_; + !is_streaming && is_stale && paused_ && !seeking_ && !overlay_enabled_; // If we're already suspended, see if we can wait for user interaction. Prior - // to HaveFutureData, we require |is_idle_| to remain suspended. |is_idle_| + // to HaveFutureData, we require |is_stale| to remain suspended. |is_stale| // will be cleared when we receive data which may take us to HaveFutureData. bool can_stay_suspended = - (is_idle_ || have_future_data) && is_suspended && paused_ && !seeking_; + (is_stale || have_future_data) && is_suspended && paused_ && !seeking_; // Combined suspend state. - result.is_suspended = is_remote || must_suspend_ || idle_suspended || + result.is_suspended = is_remote || must_suspend || idle_suspended || background_suspended || background_pause_suspended || can_stay_suspended; @@ -1956,30 +1983,34 @@ // TODO(sandersd): If Blink told us the paused state sooner, we could create // the media session sooner. bool can_play = !has_error && !is_remote && have_future_data; - bool has_session_playing = - can_play && !must_suspend_ && !background_suspended; + bool has_session_playing = can_play && !must_suspend && !background_suspended; // |has_session_suspended| means the player is suspended from the media // element point of view but paused and can be resumed from the delegate point // of view. Therefore it behaves like |paused_| for the delegate. - bool has_session_suspended = can_play && !must_suspend_ && + bool has_session_suspended = can_play && !must_suspend && background_suspended && can_play_backgrounded; bool has_session = has_session_playing || has_session_suspended; if (!has_session) { result.delegate_state = DelegateState::GONE; + result.is_idle = delegate_ && delegate_->IsIdle(delegate_id_); } else if (paused_ || has_session_suspended) { + // TODO(sandersd): Is it possible to have a suspended session, be ended, + // and not be paused? If so we should be in a PLAYING state. result.delegate_state = - ended_ ? DelegateState::ENDED : DelegateState::PAUSED; + ended_ ? DelegateState::GONE : DelegateState::PAUSED; + result.is_idle = !seeking_; } else { result.delegate_state = DelegateState::PLAYING; + result.is_idle = false; } // It's not critical if some cases where memory usage can change are missed, // since media memory changes are usually gradual. result.is_memory_reporting_enabled = - can_play && !result.is_suspended && !paused_; + can_play && !result.is_suspended && (!paused_ || seeking_); return result; } @@ -2065,7 +2096,7 @@ pipeline_metadata_.natural_size, base::Bind(&GetCurrentTimeInternal, this))); watch_time_reporter_->OnVolumeChange(volume_); - if (IsHidden()) + if (delegate_ && delegate_->IsFrameHidden()) watch_time_reporter_->OnHidden(); else watch_time_reporter_->OnShown(); @@ -2074,7 +2105,7 @@ bool WebMediaPlayerImpl::IsHidden() const { DCHECK(main_task_runner_->BelongsToCurrentThread()); - return delegate_ && delegate_->IsHidden(); + return delegate_ && delegate_->IsFrameHidden() && !delegate_->IsFrameClosed(); } bool WebMediaPlayerImpl::IsStreaming() const {
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h index 1ce44b5..da1a062f 100644 --- a/media/blink/webmediaplayer_impl.h +++ b/media/blink/webmediaplayer_impl.h
@@ -187,9 +187,10 @@ void setPoster(const blink::WebURL& poster) override; // WebMediaPlayerDelegate::Observer implementation. - void OnHidden() override; - void OnShown() override; - bool OnSuspendRequested(bool must_suspend) override; + void OnFrameHidden() override; + void OnFrameClosed() override; + void OnFrameShown() override; + void OnIdleTimeout() override; void OnPlay() override; void OnPause() override; void OnVolumeMultiplierUpdate(double multiplier) override; @@ -226,20 +227,18 @@ // intersection. void ActivateViewportIntersectionMonitoring(bool activate); - // Distinct states that |delegate_| can be in. - // TODO(sandersd): This should move into WebMediaPlayerDelegate. - // (Public for testing.) + // Distinct states that |delegate_| can be in. (Public for testing.) enum class DelegateState { GONE, PLAYING, PAUSED, - ENDED, }; // Playback state variables computed together in UpdatePlayState(). // (Public for testing.) struct PlayState { DelegateState delegate_state; + bool is_idle; bool is_memory_reporting_enabled; bool is_suspended; }; @@ -346,7 +345,7 @@ bool is_streaming, bool is_suspended, bool is_backgrounded); - void SetDelegateState(DelegateState new_state); + void SetDelegateState(DelegateState new_state, bool is_idle); void SetMemoryReportingState(bool is_memory_reporting_enabled); void SetSuspendState(bool is_suspended); @@ -361,6 +360,15 @@ // paused state after some idle timeout. void ScheduleIdlePauseTimer(); + // Returns |true| before HaveFutureData whenever there has been loading + // progress and we have not been resumed for at least kLoadingToIdleTimeout + // since then. + // + // This is used to delay suspension long enough for preroll to complete, which + // is necessay because play() will not be called before HaveFutureData (and + // thus we think we are idle forever). + bool IsPrerollAttemptNeeded(); + void CreateWatchTimeReporter(); // Returns true if the player is hidden. @@ -406,14 +414,10 @@ blink::WebLocalFrame* frame_; // The playback state last reported to |delegate_|, to avoid setting duplicate - // states. (Which can have undesired effects like resetting the idle timer.) + // states. + // TODO(sandersd): The delegate should be implementing deduplication. DelegateState delegate_state_; - - // Set when OnSuspendRequested() is called with |must_suspend| unset. - bool is_idle_; - - // Set when OnSuspendRequested() is called with |must_suspend| set. - bool must_suspend_; + bool delegate_has_audio_; blink::WebMediaPlayer::NetworkState network_state_; blink::WebMediaPlayer::ReadyState ready_state_; @@ -608,8 +612,8 @@ GURL fallback_url_; bool use_fallback_path_; - // Called some-time after OnHidden() if the media was suspended in a playing - // state as part of the call to OnHidden(). + // Called sometime after the media is suspended in a playing state in + // OnFrameHidden(), causing the state to change to paused. base::OneShotTimer background_pause_timer_; // Monitors the watch time of the played content. @@ -620,17 +624,18 @@ int underflow_count_; std::unique_ptr<base::ElapsedTimer> underflow_timer_; - // The last time didLoadingProgress() returned true. - base::TimeTicks last_time_loading_progressed_; + // Used to track loading progress, used by IsPrerollAttemptNeeded(). + // |preroll_attempt_pending_| indicates that the clock has been reset + // (awaiting a resume to start), while |preroll_attempt_start_time_| tracks + // when a preroll attempt began. + bool preroll_attempt_pending_; + base::TimeTicks preroll_attempt_start_time_; std::unique_ptr<base::TickClock> tick_clock_; // Monitors the player events. base::WeakPtr<MediaObserver> observer_; - // Whether the player is currently in autoplay muted state. - bool autoplay_muted_ = false; - // The maximum video keyframe distance that allows triggering background // playback optimizations. // 10 seconds by default but can be overridden by a Finch experiment.
diff --git a/media/blink/webmediaplayer_impl_unittest.cc b/media/blink/webmediaplayer_impl_unittest.cc index a58b32b..b0fbb40 100644 --- a/media/blink/webmediaplayer_impl_unittest.cc +++ b/media/blink/webmediaplayer_impl_unittest.cc
@@ -111,13 +111,75 @@ ~MockWebMediaPlayerDelegate() = default; // WebMediaPlayerDelegate implementation. - MOCK_METHOD1(AddObserver, int(Observer*)); - MOCK_METHOD1(RemoveObserver, void(int)); - MOCK_METHOD5(DidPlay, void(int, bool, bool, bool, MediaContentType)); - MOCK_METHOD2(DidPause, void(int, bool)); + int AddObserver(Observer* observer) override { + DCHECK_EQ(nullptr, observer_); + observer_ = observer; + return player_id_; + } + + void RemoveObserver(int player_id) override { + DCHECK_EQ(player_id_, player_id); + observer_ = nullptr; + } + + MOCK_METHOD4(DidPlay, void(int, bool, bool, MediaContentType)); + MOCK_METHOD1(DidPause, void(int)); MOCK_METHOD1(PlayerGone, void(int)); - MOCK_METHOD0(IsHidden, bool()); - MOCK_METHOD0(IsPlayingBackgroundVideo, bool()); + MOCK_METHOD0(IsBackgroundVideoPlaybackUnlocked, bool()); + + void SetIdle(int player_id, bool is_idle) override { + DCHECK_EQ(player_id_, player_id); + is_idle_ = is_idle; + is_stale_ &= is_idle; + } + + bool IsIdle(int player_id) override { + DCHECK_EQ(player_id_, player_id); + return is_idle_; + } + + void ClearStaleFlag(int player_id) override { + DCHECK_EQ(player_id_, player_id); + is_stale_ = false; + } + + bool IsStale(int player_id) override { + DCHECK_EQ(player_id_, player_id); + return is_stale_; + } + + bool IsFrameHidden() override { return is_hidden_; } + + bool IsFrameClosed() override { return is_closed_; } + + void SetIdleForTesting(bool is_idle) { is_idle_ = is_idle; } + + void SetStaleForTesting(bool is_stale) { + is_idle_ |= is_stale; + is_stale_ = is_stale; + } + + // Returns true if the player does in fact expire. + bool ExpireForTesting() { + if (is_idle_ && !is_stale_) { + is_stale_ = true; + observer_->OnIdleTimeout(); + } + + return is_stale_; + } + + void SetFrameHiddenForTesting(bool is_hidden) { is_hidden_ = is_hidden; } + + void SetFrameClosedForTesting(bool is_closed) { is_closed_ = is_closed; } + + private: + Observer* observer_ = nullptr; + int player_id_ = 1234; + bool is_idle_ = false; + bool is_stale_ = false; + bool is_hidden_ = false; + bool is_closed_ = false; }; class WebMediaPlayerImplTest : public testing::Test { @@ -189,74 +251,33 @@ } WebMediaPlayerImpl::PlayState ComputePlayState() { - wmpi_->is_idle_ = false; - wmpi_->must_suspend_ = false; return wmpi_->UpdatePlayState_ComputePlayState(false, false, false, false); } - WebMediaPlayerImpl::PlayState ComputePlayStateSuspended() { - wmpi_->is_idle_ = false; - wmpi_->must_suspend_ = false; - return wmpi_->UpdatePlayState_ComputePlayState(false, false, true, false); - } - - WebMediaPlayerImpl::PlayState ComputeBackgroundedPlayState() { - wmpi_->is_idle_ = false; - wmpi_->must_suspend_ = false; + WebMediaPlayerImpl::PlayState ComputePlayState_FrameHidden() { return wmpi_->UpdatePlayState_ComputePlayState(false, false, false, true); } - WebMediaPlayerImpl::PlayState ComputeIdlePlayState() { - wmpi_->is_idle_ = true; - wmpi_->must_suspend_ = false; - return wmpi_->UpdatePlayState_ComputePlayState(false, false, false, false); - } - - WebMediaPlayerImpl::PlayState ComputeIdleSuspendedPlayState() { - wmpi_->is_idle_ = true; - wmpi_->must_suspend_ = false; + WebMediaPlayerImpl::PlayState ComputePlayState_Suspended() { return wmpi_->UpdatePlayState_ComputePlayState(false, false, true, false); } - WebMediaPlayerImpl::PlayState ComputeMustSuspendPlayState() { - wmpi_->is_idle_ = false; - wmpi_->must_suspend_ = true; - return wmpi_->UpdatePlayState_ComputePlayState(false, false, false, false); + WebMediaPlayerImpl::PlayState ComputePlayState_Remote() { + return wmpi_->UpdatePlayState_ComputePlayState(true, false, false, false); } - WebMediaPlayerImpl::PlayState ComputeStreamingPlayState(bool must_suspend) { - wmpi_->is_idle_ = true; - wmpi_->must_suspend_ = must_suspend; + WebMediaPlayerImpl::PlayState ComputePlayState_BackgroundedStreaming() { return wmpi_->UpdatePlayState_ComputePlayState(false, true, false, true); } - void SetDelegateState(WebMediaPlayerImpl::DelegateState state) { - wmpi_->SetDelegateState(state); - } - bool IsSuspended() { return wmpi_->pipeline_controller_.IsSuspended(); } void AddBufferedRanges() { wmpi_->buffered_data_source_host_.AddBufferedByteRange(0, 1); } - void SetupForResumingBackgroundVideo() { -#if !defined(OS_ANDROID) - // Need to enable media suspend to test resuming background videos. - base::CommandLine::ForCurrentProcess()->AppendSwitch( - switches::kEnableMediaSuspend); -#endif // !defined(OS_ANDROID) - scoped_feature_list_.InitAndEnableFeature(kResumeBackgroundVideo); - } - - void SetBackgroundVideoOptimization(bool enable) { - if (enable) { - scoped_feature_list_.InitAndEnableFeature( - kBackgroundVideoTrackOptimization); - } else { - scoped_feature_list_.InitAndDisableFeature( - kBackgroundVideoTrackOptimization); - } + void SetDelegateState(WebMediaPlayerImpl::DelegateState state) { + wmpi_->SetDelegateState(state, false); } bool ShouldDisableVideoWhenHidden() const { @@ -296,19 +317,17 @@ // The WebMediaPlayerImpl instance under test. std::unique_ptr<WebMediaPlayerImpl> wmpi_; - private: - base::test::ScopedFeatureList scoped_feature_list_; - DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerImplTest); }; TEST_F(WebMediaPlayerImplTest, ConstructAndDestroy) { InitializeWebMediaPlayerImpl(); + EXPECT_FALSE(IsSuspended()); } TEST_F(WebMediaPlayerImplTest, IdleSuspendIsEnabledBeforeLoadingBegins) { InitializeWebMediaPlayerImpl(); - wmpi_->OnSuspendRequested(false); + EXPECT_TRUE(delegate_.ExpireForTesting()); base::RunLoop().RunUntilIdle(); EXPECT_TRUE(IsSuspended()); } @@ -323,7 +342,7 @@ wmpi_->didLoadingProgress(); // Advance less than the loading timeout. clock->Advance(base::TimeDelta::FromSeconds(1)); - wmpi_->OnSuspendRequested(false); + EXPECT_FALSE(delegate_.ExpireForTesting()); base::RunLoop().RunUntilIdle(); EXPECT_FALSE(IsSuspended()); } @@ -337,344 +356,287 @@ wmpi_->didLoadingProgress(); // Advance more than the loading timeout. clock->Advance(base::TimeDelta::FromSeconds(4)); - wmpi_->OnSuspendRequested(false); + EXPECT_TRUE(delegate_.ExpireForTesting()); base::RunLoop().RunUntilIdle(); EXPECT_TRUE(IsSuspended()); } TEST_F(WebMediaPlayerImplTest, DidLoadingProgressTriggersResume) { + // Same setup as IdleSuspendIsEnabledBeforeLoadingBegins. InitializeWebMediaPlayerImpl(); - EXPECT_FALSE(IsSuspended()); - wmpi_->OnSuspendRequested(false); + EXPECT_TRUE(delegate_.ExpireForTesting()); base::RunLoop().RunUntilIdle(); EXPECT_TRUE(IsSuspended()); + + // Like IdleSuspendIsDisabledIfLoadingProgressedRecently, the idle timeout + // should be rejected if it hasn't been long enough. AddBufferedRanges(); wmpi_->didLoadingProgress(); + EXPECT_FALSE(delegate_.ExpireForTesting()); base::RunLoop().RunUntilIdle(); EXPECT_FALSE(IsSuspended()); } -TEST_F(WebMediaPlayerImplTest, ComputePlayState_AfterConstruction) { +TEST_F(WebMediaPlayerImplTest, ComputePlayState_Constructed) { InitializeWebMediaPlayerImpl(); - WebMediaPlayerImpl::PlayState state; - - state = ComputePlayState(); + WebMediaPlayerImpl::PlayState state = ComputePlayState(); EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); + EXPECT_TRUE(state.is_idle); EXPECT_FALSE(state.is_suspended); - - state = ComputeIdlePlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_TRUE(state.is_suspended); - - state = ComputeBackgroundedPlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_FALSE(state.is_suspended); - - state = ComputeMustSuspendPlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_TRUE(state.is_suspended); } -TEST_F(WebMediaPlayerImplTest, ComputePlayState_AfterMetadata) { +TEST_F(WebMediaPlayerImplTest, ComputePlayState_HaveMetadata) { InitializeWebMediaPlayerImpl(); - WebMediaPlayerImpl::PlayState state; SetMetadata(true, true); - - state = ComputePlayState(); + WebMediaPlayerImpl::PlayState state = ComputePlayState(); EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); + EXPECT_TRUE(state.is_idle); EXPECT_FALSE(state.is_suspended); - - state = ComputeIdlePlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_TRUE(state.is_suspended); - - state = ComputeBackgroundedPlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_TRUE(state.is_suspended); - - state = ComputeMustSuspendPlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_TRUE(state.is_suspended); } -TEST_F(WebMediaPlayerImplTest, ComputePlayState_AfterMetadata_AudioOnly) { +TEST_F(WebMediaPlayerImplTest, ComputePlayState_HaveFutureData) { InitializeWebMediaPlayerImpl(); - WebMediaPlayerImpl::PlayState state; - SetMetadata(true, false); - - state = ComputePlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_FALSE(state.is_suspended); - - state = ComputeIdlePlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_TRUE(state.is_suspended); - - SetPaused(false); - state = ComputeBackgroundedPlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_FALSE(state.is_suspended); - - state = ComputeMustSuspendPlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_TRUE(state.is_suspended); -} - -TEST_F(WebMediaPlayerImplTest, ComputePlayState_AfterFutureData) { - InitializeWebMediaPlayerImpl(); - WebMediaPlayerImpl::PlayState state; SetMetadata(true, true); SetReadyState(blink::WebMediaPlayer::ReadyStateHaveFutureData); - - state = ComputePlayState(); + WebMediaPlayerImpl::PlayState state = ComputePlayState(); EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PAUSED, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); + EXPECT_TRUE(state.is_idle); EXPECT_FALSE(state.is_suspended); - - state = ComputeBackgroundedPlayState(); - - if (base::FeatureList::IsEnabled(kResumeBackgroundVideo)) - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PAUSED, state.delegate_state); - else - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_TRUE(state.is_suspended); - - // Idle suspension is possible after HaveFutureData. - state = ComputeIdlePlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PAUSED, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_TRUE(state.is_suspended); - - state = ComputeMustSuspendPlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_TRUE(state.is_suspended); } TEST_F(WebMediaPlayerImplTest, ComputePlayState_Playing) { InitializeWebMediaPlayerImpl(); - WebMediaPlayerImpl::PlayState state; SetMetadata(true, true); SetReadyState(blink::WebMediaPlayer::ReadyStateHaveFutureData); SetPaused(false); - - state = ComputePlayState(); + WebMediaPlayerImpl::PlayState state = ComputePlayState(); EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PLAYING, state.delegate_state); - EXPECT_TRUE(state.is_memory_reporting_enabled); + EXPECT_FALSE(state.is_idle); EXPECT_FALSE(state.is_suspended); - - state = ComputeBackgroundedPlayState(); - if (base::FeatureList::IsEnabled(kResumeBackgroundVideo)) - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PAUSED, state.delegate_state); - else - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_TRUE(state.is_suspended); - - state = ComputeMustSuspendPlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_TRUE(state.is_suspended); + EXPECT_TRUE(state.is_memory_reporting_enabled); } -TEST_F(WebMediaPlayerImplTest, ComputePlayState_PlayingThenUnderflow) { +TEST_F(WebMediaPlayerImplTest, ComputePlayState_Underflow) { InitializeWebMediaPlayerImpl(); - WebMediaPlayerImpl::PlayState state; SetMetadata(true, true); SetReadyState(blink::WebMediaPlayer::ReadyStateHaveFutureData); SetPaused(false); SetReadyState(blink::WebMediaPlayer::ReadyStateHaveCurrentData); - - // Underflow should not trigger idle suspend. The user is still playing the - // the video, just waiting on the network. - state = ComputePlayState(); + WebMediaPlayerImpl::PlayState state = ComputePlayState(); EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PLAYING, state.delegate_state); - EXPECT_TRUE(state.is_memory_reporting_enabled); + EXPECT_FALSE(state.is_idle); EXPECT_FALSE(state.is_suspended); - - // Background suspend should still be possible during underflow. - state = ComputeBackgroundedPlayState(); - if (base::FeatureList::IsEnabled(kResumeBackgroundVideo)) - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PAUSED, state.delegate_state); - else - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_TRUE(state.is_suspended); - - // Forced suspend should still be possible during underflow. - state = ComputeMustSuspendPlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_TRUE(state.is_suspended); + EXPECT_TRUE(state.is_memory_reporting_enabled); } -TEST_F(WebMediaPlayerImplTest, ComputePlayState_Playing_AudioOnly) { +TEST_F(WebMediaPlayerImplTest, ComputePlayState_FrameHidden) { InitializeWebMediaPlayerImpl(); - WebMediaPlayerImpl::PlayState state; - SetMetadata(true, false); + SetMetadata(true, true); SetReadyState(blink::WebMediaPlayer::ReadyStateHaveFutureData); SetPaused(false); - state = ComputePlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PLAYING, state.delegate_state); - EXPECT_TRUE(state.is_memory_reporting_enabled); - EXPECT_FALSE(state.is_suspended); + { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(kResumeBackgroundVideo); - // Audio-only stays playing in the background. - state = ComputeBackgroundedPlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PLAYING, state.delegate_state); - EXPECT_TRUE(state.is_memory_reporting_enabled); - EXPECT_FALSE(state.is_suspended); + WebMediaPlayerImpl::PlayState state = ComputePlayState_FrameHidden(); + EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PAUSED, state.delegate_state); + EXPECT_TRUE(state.is_idle); + EXPECT_TRUE(state.is_suspended); + EXPECT_FALSE(state.is_memory_reporting_enabled); + } - // Backgrounding a paused audio only player should suspend, but keep the - // session alive for user interactions. - SetPaused(true); - state = ComputeBackgroundedPlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PAUSED, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_TRUE(state.is_suspended); + { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndDisableFeature(kResumeBackgroundVideo); - state = ComputeMustSuspendPlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_TRUE(state.is_suspended); + WebMediaPlayerImpl::PlayState state = ComputePlayState_FrameHidden(); + EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); + EXPECT_TRUE(state.is_idle); + EXPECT_TRUE(state.is_suspended); + EXPECT_FALSE(state.is_memory_reporting_enabled); + } } -TEST_F(WebMediaPlayerImplTest, ComputePlayState_Paused_Seek) { +TEST_F(WebMediaPlayerImplTest, ComputePlayState_FrameClosed) { InitializeWebMediaPlayerImpl(); - WebMediaPlayerImpl::PlayState state; + SetMetadata(true, true); + SetReadyState(blink::WebMediaPlayer::ReadyStateHaveFutureData); + SetPaused(false); + delegate_.SetFrameClosedForTesting(true); + WebMediaPlayerImpl::PlayState state = ComputePlayState(); + EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); + EXPECT_TRUE(state.is_idle); + EXPECT_TRUE(state.is_suspended); + EXPECT_FALSE(state.is_memory_reporting_enabled); +} + +TEST_F(WebMediaPlayerImplTest, ComputePlayState_PausedSeek) { + InitializeWebMediaPlayerImpl(); SetMetadata(true, true); SetReadyState(blink::WebMediaPlayer::ReadyStateHaveFutureData); SetSeeking(true); - - state = ComputePlayState(); + WebMediaPlayerImpl::PlayState state = ComputePlayState(); EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PAUSED, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); + EXPECT_FALSE(state.is_idle); EXPECT_FALSE(state.is_suspended); -} - -TEST_F(WebMediaPlayerImplTest, ComputePlayState_Paused_Fullscreen) { - InitializeWebMediaPlayerImpl(); - WebMediaPlayerImpl::PlayState state; - SetMetadata(true, true); - SetReadyState(blink::WebMediaPlayer::ReadyStateHaveFutureData); - SetFullscreen(true); - - state = ComputePlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PAUSED, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_FALSE(state.is_suspended); + EXPECT_TRUE(state.is_memory_reporting_enabled); } TEST_F(WebMediaPlayerImplTest, ComputePlayState_Ended) { InitializeWebMediaPlayerImpl(); - WebMediaPlayerImpl::PlayState state; SetMetadata(true, true); SetReadyState(blink::WebMediaPlayer::ReadyStateHaveFutureData); + SetPaused(false); SetEnded(true); - // The pipeline is not suspended immediately on ended. + // Before Blink pauses us (or seeks for looping content), the media session + // should be preserved. + WebMediaPlayerImpl::PlayState state; state = ComputePlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::ENDED, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); + EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PLAYING, state.delegate_state); + EXPECT_FALSE(state.is_idle); EXPECT_FALSE(state.is_suspended); + EXPECT_TRUE(state.is_memory_reporting_enabled); - state = ComputeIdlePlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::ENDED, state.delegate_state); + SetPaused(true); + state = ComputePlayState(); + EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); + EXPECT_TRUE(state.is_idle); + EXPECT_FALSE(state.is_suspended); EXPECT_FALSE(state.is_memory_reporting_enabled); +} + +TEST_F(WebMediaPlayerImplTest, ComputePlayState_StaysSuspended) { + InitializeWebMediaPlayerImpl(); + SetMetadata(true, true); + SetReadyState(blink::WebMediaPlayer::ReadyStateHaveFutureData); + + // Should stay suspended even though not stale or backgrounded. + WebMediaPlayerImpl::PlayState state = ComputePlayState_Suspended(); + EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PAUSED, state.delegate_state); + EXPECT_TRUE(state.is_idle); EXPECT_TRUE(state.is_suspended); + EXPECT_FALSE(state.is_memory_reporting_enabled); +} + +TEST_F(WebMediaPlayerImplTest, ComputePlayState_Remote) { + InitializeWebMediaPlayerImpl(); + SetMetadata(true, true); + SetReadyState(blink::WebMediaPlayer::ReadyStateHaveFutureData); + + // Remote media is always suspended. + // TODO(sandersd): Decide whether this should count as idle or not. + WebMediaPlayerImpl::PlayState state = ComputePlayState_Remote(); + EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); + EXPECT_TRUE(state.is_suspended); + EXPECT_FALSE(state.is_memory_reporting_enabled); +} + +TEST_F(WebMediaPlayerImplTest, ComputePlayState_Fullscreen) { + InitializeWebMediaPlayerImpl(); + SetMetadata(true, true); + SetReadyState(blink::WebMediaPlayer::ReadyStateHaveFutureData); + SetFullscreen(true); + SetPaused(true); + delegate_.SetStaleForTesting(true); + + // Fullscreen media is never suspended (Android only behavior). + WebMediaPlayerImpl::PlayState state = ComputePlayState(); + EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PAUSED, state.delegate_state); + EXPECT_TRUE(state.is_idle); + EXPECT_FALSE(state.is_suspended); + EXPECT_FALSE(state.is_memory_reporting_enabled); } TEST_F(WebMediaPlayerImplTest, ComputePlayState_Streaming) { InitializeWebMediaPlayerImpl(); - WebMediaPlayerImpl::PlayState state; SetMetadata(true, true); - SetReadyState(blink::WebMediaPlayer::ReadyStateHaveFutureData); SetPaused(true); + delegate_.SetStaleForTesting(true); - // Streaming media should not suspend, even if paused, idle, and backgrounded. - state = ComputeStreamingPlayState(false); + // Streaming media should not suspend, even if paused, stale, and + // backgrounded. + WebMediaPlayerImpl::PlayState state; + state = ComputePlayState_BackgroundedStreaming(); EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PAUSED, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); + EXPECT_TRUE(state.is_idle); EXPECT_FALSE(state.is_suspended); + EXPECT_FALSE(state.is_memory_reporting_enabled); // Streaming media should suspend when the tab is closed, regardless. - state = ComputeStreamingPlayState(true); + delegate_.SetFrameClosedForTesting(true); + state = ComputePlayState_BackgroundedStreaming(); EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); + EXPECT_TRUE(state.is_idle); EXPECT_TRUE(state.is_suspended); + EXPECT_FALSE(state.is_memory_reporting_enabled); } -TEST_F(WebMediaPlayerImplTest, ComputePlayState_Suspended) { +TEST_F(WebMediaPlayerImplTest, ComputePlayState_PlayingBackgroundedVideo) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(kResumeBackgroundVideo); + InitializeWebMediaPlayerImpl(); - WebMediaPlayerImpl::PlayState state; SetMetadata(true, true); - - // Suspended players should be resumed unless we have reached the appropriate - // ready state and are not seeking. - SetPaused(true); - state = ComputePlayStateSuspended(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_FALSE(state.is_suspended); - - // Paused players in the idle state are allowed to remain suspended. - state = ComputeIdleSuspendedPlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_TRUE(state.is_suspended); - - SetPaused(false); - state = ComputePlayStateSuspended(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_FALSE(state.is_suspended); - SetReadyState(blink::WebMediaPlayer::ReadyStateHaveFutureData); - - // Paused players should stay suspended. - SetPaused(true); - state = ComputePlayStateSuspended(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PAUSED, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_TRUE(state.is_suspended); - - // Playing players should resume into the playing state. SetPaused(false); - state = ComputePlayStateSuspended(); + EXPECT_CALL(delegate_, IsBackgroundVideoPlaybackUnlocked()) + .WillRepeatedly(Return(true)); + + WebMediaPlayerImpl::PlayState state = ComputePlayState_FrameHidden(); EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PLAYING, state.delegate_state); + EXPECT_FALSE(state.is_idle); + EXPECT_FALSE(state.is_suspended); EXPECT_TRUE(state.is_memory_reporting_enabled); - EXPECT_FALSE(state.is_suspended); +} - // If seeking, the previously suspended state does not matter; the player - // should always be resumed. - SetSeeking(true); - - SetPaused(true); - state = ComputePlayStateSuspended(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PAUSED, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_FALSE(state.is_suspended); - +TEST_F(WebMediaPlayerImplTest, ComputePlayState_AudioOnly) { + InitializeWebMediaPlayerImpl(); + SetMetadata(true, false); + SetReadyState(blink::WebMediaPlayer::ReadyStateHaveFutureData); SetPaused(false); - state = ComputePlayStateSuspended(); + + // Backgrounded audio-only playback stays playing. + WebMediaPlayerImpl::PlayState state = ComputePlayState_FrameHidden(); EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PLAYING, state.delegate_state); - EXPECT_TRUE(state.is_memory_reporting_enabled); + EXPECT_FALSE(state.is_idle); EXPECT_FALSE(state.is_suspended); + EXPECT_TRUE(state.is_memory_reporting_enabled); +} + +TEST_F(WebMediaPlayerImplTest, AutoplayMuted_StartsAndStops) { + InitializeWebMediaPlayerImpl(); + SetMetadata(true, true); + SetReadyState(blink::WebMediaPlayer::ReadyStateHaveFutureData); + SetPaused(false); + client_.set_is_autoplaying_muted(true); + + EXPECT_CALL(delegate_, DidPlay(_, true, false, _)); + SetDelegateState(WebMediaPlayerImpl::DelegateState::PLAYING); + + client_.set_is_autoplaying_muted(false); + EXPECT_CALL(delegate_, DidPlay(_, true, true, _)); + SetDelegateState(WebMediaPlayerImpl::DelegateState::PLAYING); +} + +TEST_F(WebMediaPlayerImplTest, AutoplayMuted_SetVolume) { + InitializeWebMediaPlayerImpl(); + SetMetadata(true, true); + SetReadyState(blink::WebMediaPlayer::ReadyStateHaveFutureData); + SetPaused(false); + client_.set_is_autoplaying_muted(true); + + EXPECT_CALL(delegate_, DidPlay(_, true, false, _)); + SetDelegateState(WebMediaPlayerImpl::DelegateState::PLAYING); + + client_.set_is_autoplaying_muted(false); + EXPECT_CALL(delegate_, DidPlay(_, true, true, _)); + wmpi_->setVolume(1.0); } TEST_F(WebMediaPlayerImplTest, NaturalSizeChange) { @@ -706,79 +668,12 @@ ASSERT_EQ(blink::WebSize(1080, 1920), wmpi_->naturalSize()); } -// Audible backgrounded videos are not suspended if delegate_ allows it. -TEST_F(WebMediaPlayerImplTest, ComputePlayState_BackgroundedVideoPlaying) { - InitializeWebMediaPlayerImpl(); - WebMediaPlayerImpl::PlayState state; - SetMetadata(true, true); - SetReadyState(blink::WebMediaPlayer::ReadyStateHaveFutureData); - - SetupForResumingBackgroundVideo(); - - EXPECT_CALL(delegate_, IsPlayingBackgroundVideo()) - .WillRepeatedly(Return(true)); - EXPECT_CALL(delegate_, IsHidden()).WillRepeatedly(Return(true)); - - SetPaused(false); - state = ComputeBackgroundedPlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PLAYING, state.delegate_state); - EXPECT_TRUE(state.is_memory_reporting_enabled); - EXPECT_FALSE(state.is_suspended); -} - -// Backgrounding audible videos should suspend them and report as paused, not -// gone. -TEST_F(WebMediaPlayerImplTest, ComputePlayState_BackgroundedVideoPaused) { - InitializeWebMediaPlayerImpl(); - WebMediaPlayerImpl::PlayState state; - SetMetadata(true, true); - SetReadyState(blink::WebMediaPlayer::ReadyStateHaveFutureData); - - SetupForResumingBackgroundVideo(); - - EXPECT_CALL(delegate_, IsPlayingBackgroundVideo()).WillOnce(Return(false)); - EXPECT_CALL(delegate_, IsHidden()).WillRepeatedly(Return(true)); - - state = ComputeBackgroundedPlayState(); - EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PAUSED, state.delegate_state); - EXPECT_FALSE(state.is_memory_reporting_enabled); - EXPECT_TRUE(state.is_suspended); -} - -TEST_F(WebMediaPlayerImplTest, AutoplayMuted_StartsAndStops) { - InitializeWebMediaPlayerImpl(); - SetMetadata(true, true); - SetReadyState(blink::WebMediaPlayer::ReadyStateHaveFutureData); - SetPaused(false); - - EXPECT_CALL(delegate_, DidPlay(_, true, false, false, _)); - client_.set_is_autoplaying_muted(true); - SetDelegateState(WebMediaPlayerImpl::DelegateState::PLAYING); - - EXPECT_CALL(delegate_, DidPlay(_, true, true, false, _)); - client_.set_is_autoplaying_muted(false); - SetDelegateState(WebMediaPlayerImpl::DelegateState::PLAYING); -} - -TEST_F(WebMediaPlayerImplTest, AutoplayMuted_SetVolume) { - InitializeWebMediaPlayerImpl(); - SetMetadata(true, true); - SetReadyState(blink::WebMediaPlayer::ReadyStateHaveFutureData); - SetPaused(false); - - EXPECT_CALL(delegate_, DidPlay(_, true, false, false, _)); - client_.set_is_autoplaying_muted(true); - SetDelegateState(WebMediaPlayerImpl::DelegateState::PLAYING); - - EXPECT_CALL(delegate_, DidPlay(_, true, true, false, _)); - client_.set_is_autoplaying_muted(false); - wmpi_->setVolume(1.0); -} - TEST_F(WebMediaPlayerImplTest, ShouldDisableVideoWhenHidden) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(kBackgroundVideoTrackOptimization); + InitializeWebMediaPlayerImpl(); - EXPECT_CALL(delegate_, IsHidden()).WillRepeatedly(Return(true)); - SetBackgroundVideoOptimization(true); + delegate_.SetFrameHiddenForTesting(true); SetMetadata(true, true); SetVideoKeyframeDistanceAverage(base::TimeDelta::FromSeconds(5)); @@ -796,9 +691,11 @@ } TEST_F(WebMediaPlayerImplTest, ShouldDisableVideoWhenHiddenFeatureDisabled) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndDisableFeature(kBackgroundVideoTrackOptimization); + InitializeWebMediaPlayerImpl(); - EXPECT_CALL(delegate_, IsHidden()).WillRepeatedly(Return(true)); - SetBackgroundVideoOptimization(false); + delegate_.SetFrameHiddenForTesting(true); SetMetadata(true, true); EXPECT_FALSE(ShouldDisableVideoWhenHidden());
diff --git a/media/ffmpeg/ffmpeg_regression_tests.cc b/media/ffmpeg/ffmpeg_regression_tests.cc index 1c0b0a5..36a16ba 100644 --- a/media/ffmpeg/ffmpeg_regression_tests.cc +++ b/media/ffmpeg/ffmpeg_regression_tests.cc
@@ -101,7 +101,10 @@ "security/112384.webm", DEMUXER_ERROR_COULD_NOT_PARSE, DEMUXER_ERROR_COULD_NOT_PARSE); -FFMPEG_TEST_CASE(Cr112976, "security/112976.ogg", PIPELINE_OK, PIPELINE_OK); +FFMPEG_TEST_CASE(Cr112976, + "security/112976.ogg", + PIPELINE_OK, + DEMUXER_ERROR_COULD_NOT_PARSE); FFMPEG_TEST_CASE(Cr116927, "security/116927.ogv", DEMUXER_ERROR_NO_SUPPORTED_STREAMS, @@ -110,17 +113,26 @@ "security/117912.webm", DEMUXER_ERROR_COULD_NOT_OPEN, DEMUXER_ERROR_COULD_NOT_OPEN); -FFMPEG_TEST_CASE(Cr123481, "security/123481.ogv", PIPELINE_OK, PIPELINE_OK); +FFMPEG_TEST_CASE(Cr123481, + "security/123481.ogv", + PIPELINE_OK, + DEMUXER_ERROR_COULD_NOT_PARSE); FFMPEG_TEST_CASE(Cr132779, "security/132779.webm", DEMUXER_ERROR_COULD_NOT_PARSE, DEMUXER_ERROR_COULD_NOT_PARSE); -FFMPEG_TEST_CASE(Cr140165, "security/140165.ogg", PIPELINE_OK, PIPELINE_OK); +FFMPEG_TEST_CASE(Cr140165, + "security/140165.ogg", + PIPELINE_OK, + DEMUXER_ERROR_COULD_NOT_PARSE); FFMPEG_TEST_CASE(Cr140647, "security/140647.ogv", DEMUXER_ERROR_COULD_NOT_OPEN, DEMUXER_ERROR_COULD_NOT_OPEN); -FFMPEG_TEST_CASE(Cr142738, "crbug142738.ogg", PIPELINE_OK, PIPELINE_OK); +FFMPEG_TEST_CASE(Cr142738, + "crbug142738.ogg", + PIPELINE_OK, + DEMUXER_ERROR_COULD_NOT_PARSE); FFMPEG_TEST_CASE(Cr152691, "security/152691.mp3", PIPELINE_OK,
diff --git a/media/filters/audio_decoder_unittest.cc b/media/filters/audio_decoder_unittest.cc index cfaf4b8a..12c86e35 100644 --- a/media/filters/audio_decoder_unittest.cc +++ b/media/filters/audio_decoder_unittest.cc
@@ -380,8 +380,6 @@ DISALLOW_COPY_AND_ASSIGN(AudioDecoderTest); }; -class FFmpegAudioDecoderBehavioralTest : public AudioDecoderTest {}; - TEST_P(AudioDecoderTest, Initialize) { SKIP_TEST_IF_NO_MEDIA_CODEC(); ASSERT_NO_FATAL_FAILURE(Initialize()); @@ -483,7 +481,7 @@ #endif }; -INSTANTIATE_TEST_CASE_P(MediaCodecAudioDecoderTest, +INSTANTIATE_TEST_CASE_P(MediaCodec, AudioDecoderTest, testing::ValuesIn(kMediaCodecTests)); #endif // defined(OS_ANDROID) @@ -571,16 +569,8 @@ CHANNEL_LAYOUT_STEREO}, }; -// Dummy data for behavioral tests. -const DecoderTestData kFFmpegBehavioralTest[] = { - {FFMPEG, kUnknownAudioCodec, "", NULL, 0, 0, CHANNEL_LAYOUT_NONE}, -}; - -INSTANTIATE_TEST_CASE_P(FFmpegAudioDecoderTest, +INSTANTIATE_TEST_CASE_P(FFmpeg, AudioDecoderTest, testing::ValuesIn(kFFmpegTests)); -INSTANTIATE_TEST_CASE_P(FFmpegAudioDecoderBehavioralTest, - FFmpegAudioDecoderBehavioralTest, - testing::ValuesIn(kFFmpegBehavioralTest)); } // namespace media
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc index 218989c..7d1fcea 100644 --- a/media/filters/ffmpeg_demuxer.cc +++ b/media/filters/ffmpeg_demuxer.cc
@@ -475,59 +475,59 @@ const base::TimeDelta stream_timestamp = ConvertStreamTimestamp(stream_->time_base, packet->pts); - if (stream_timestamp != kNoTimestamp) { - const bool is_audio = type() == AUDIO; + if (stream_timestamp == kNoTimestamp) { + demuxer_->NotifyDemuxerError(DEMUXER_ERROR_COULD_NOT_PARSE); + return; + } - // If this file has negative timestamps don't rebase any other stream types - // against the negative starting time. - base::TimeDelta start_time = demuxer_->start_time(); - if (fixup_negative_timestamps_ && !is_audio && - start_time < base::TimeDelta()) { - start_time = base::TimeDelta(); - } + const bool is_audio = type() == AUDIO; - // Don't rebase timestamps for positive start times, the HTML Media Spec - // details this in section "4.8.10.6 Offsets into the media resource." We - // will still need to rebase timestamps before seeking with FFmpeg though. - if (start_time > base::TimeDelta()) - start_time = base::TimeDelta(); + // If this file has negative timestamps don't rebase any other stream types + // against the negative starting time. + base::TimeDelta start_time = demuxer_->start_time(); + if (fixup_negative_timestamps_ && !is_audio && + start_time < base::TimeDelta()) { + start_time = base::TimeDelta(); + } - buffer->set_timestamp(stream_timestamp - start_time); + // Don't rebase timestamps for positive start times, the HTML Media Spec + // details this in section "4.8.10.6 Offsets into the media resource." We + // will still need to rebase timestamps before seeking with FFmpeg though. + if (start_time > base::TimeDelta()) + start_time = base::TimeDelta(); - // If enabled, and no codec delay is present, mark audio packets with - // negative timestamps for post-decode discard. - if (fixup_negative_timestamps_ && is_audio && - stream_timestamp < base::TimeDelta() && - buffer->duration() != kNoTimestamp) { - if (!audio_decoder_config().codec_delay()) { - DCHECK_EQ(buffer->discard_padding().first, base::TimeDelta()); + buffer->set_timestamp(stream_timestamp - start_time); - if (stream_timestamp + buffer->duration() < base::TimeDelta()) { - DCHECK_EQ(buffer->discard_padding().second, base::TimeDelta()); + // If enabled, and no codec delay is present, mark audio packets with + // negative timestamps for post-decode discard. + if (fixup_negative_timestamps_ && is_audio && + stream_timestamp < base::TimeDelta() && + buffer->duration() != kNoTimestamp) { + if (!audio_decoder_config().codec_delay()) { + DCHECK_EQ(buffer->discard_padding().first, base::TimeDelta()); - // Discard the entire packet if it's entirely before zero. - buffer->set_discard_padding( - std::make_pair(kInfiniteDuration, base::TimeDelta())); - } else { - // Only discard part of the frame if it overlaps zero. - buffer->set_discard_padding(std::make_pair( - -stream_timestamp, buffer->discard_padding().second)); - } + if (stream_timestamp + buffer->duration() < base::TimeDelta()) { + DCHECK_EQ(buffer->discard_padding().second, base::TimeDelta()); + + // Discard the entire packet if it's entirely before zero. + buffer->set_discard_padding( + std::make_pair(kInfiniteDuration, base::TimeDelta())); } else { - // Verify that codec delay would cover discard and that we don't need to - // mark the packet for post decode discard. Since timestamps may be in - // milliseconds and codec delay in nanosecond precision, round up to the - // nearest millisecond. See enable_negative_timestamp_fixups(). - DCHECK_LE(-std::ceil(FramesToTimeDelta( - audio_decoder_config().codec_delay(), - audio_decoder_config().samples_per_second()) - .InMillisecondsF()), - stream_timestamp.InMillisecondsF()); + // Only discard part of the frame if it overlaps zero. + buffer->set_discard_padding(std::make_pair( + -stream_timestamp, buffer->discard_padding().second)); } + } else { + // Verify that codec delay would cover discard and that we don't need to + // mark the packet for post decode discard. Since timestamps may be in + // milliseconds and codec delay in nanosecond precision, round up to the + // nearest millisecond. See enable_negative_timestamp_fixups(). + DCHECK_LE(-std::ceil(FramesToTimeDelta( + audio_decoder_config().codec_delay(), + audio_decoder_config().samples_per_second()) + .InMillisecondsF()), + stream_timestamp.InMillisecondsF()); } - } else { - // If this happens on the first packet, decoders will throw an error. - buffer->set_timestamp(kNoTimestamp); } if (last_packet_timestamp_ != kNoTimestamp) { @@ -538,27 +538,19 @@ // // If the new link starts with a negative timestamp or a timestamp less than // the original (positive) |start_time|, we will get a negative timestamp - // here. It's also possible FFmpeg returns kNoTimestamp here if it's not - // able to work out a timestamp using the previous link and the next. + // here. // // Fixing chained ogg is non-trivial, so for now just reuse the last good // timestamp. The decoder will rewrite the timestamps to be sample accurate // later. See http://crbug.com/396864. if (fixup_negative_timestamps_ && - (buffer->timestamp() == kNoTimestamp || - buffer->timestamp() < last_packet_timestamp_)) { + buffer->timestamp() < last_packet_timestamp_) { buffer->set_timestamp(last_packet_timestamp_ + (last_packet_duration_ != kNoTimestamp ? last_packet_duration_ : base::TimeDelta::FromMicroseconds(1))); } - if (buffer->timestamp() == kNoTimestamp) { - // If we didn't get a valid timestamp and didn't fix it up, then fail. - demuxer_->NotifyDemuxerError(DEMUXER_ERROR_COULD_NOT_PARSE); - return; - } - // The demuxer should always output positive timestamps. DCHECK(buffer->timestamp() >= base::TimeDelta());
diff --git a/media/filters/ffmpeg_demuxer_unittest.cc b/media/filters/ffmpeg_demuxer_unittest.cc index d6a2bffb..35bb7da 100644 --- a/media/filters/ffmpeg_demuxer_unittest.cc +++ b/media/filters/ffmpeg_demuxer_unittest.cc
@@ -17,6 +17,7 @@ #include "base/path_service.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" +#include "base/test/mock_callback.h" #include "base/threading/thread.h" #include "base/threading/thread_task_runner_handle.h" #include "media/base/decrypt_config.h" @@ -962,17 +963,6 @@ base::RunLoop().Run(); } -class MockReadCB { - public: - MockReadCB() {} - ~MockReadCB() {} - - MOCK_METHOD2(Run, void(DemuxerStream::Status status, - const scoped_refptr<DecoderBuffer>& buffer)); - private: - DISALLOW_COPY_AND_ASSIGN(MockReadCB); -}; - TEST_F(FFmpegDemuxerTest, Stop) { // Tests that calling Read() on a stopped demuxer stream immediately deletes // the callback. @@ -986,11 +976,11 @@ demuxer_->Stop(); // Reads after being stopped are all EOS buffers. - StrictMock<MockReadCB> callback; + StrictMock<base::MockCallback<DemuxerStream::ReadCB>> callback; EXPECT_CALL(callback, Run(DemuxerStream::kOk, IsEndOfStreamBuffer())); // Attempt the read... - audio->Read(base::Bind(&MockReadCB::Run, base::Unretained(&callback))); + audio->Read(callback.Get()); base::RunLoop().RunUntilIdle(); // Don't let the test call Stop() again.
diff --git a/media/muxers/webm_muxer.cc b/media/muxers/webm_muxer.cc index 616e7b9..02a4ca9 100644 --- a/media/muxers/webm_muxer.cc +++ b/media/muxers/webm_muxer.cc
@@ -106,7 +106,8 @@ has_video_(has_video), has_audio_(has_audio), write_data_callback_(write_data_callback), - position_(0) { + position_(0), + force_one_libwebm_error_(false) { DCHECK(has_video_ || has_audio_); DCHECK(!write_data_callback_.is_null()); DCHECK(codec == kCodecVP8 || codec == kCodecVP9 || codec == kCodecH264) @@ -131,7 +132,7 @@ segment_.Finalize(); } -void WebmMuxer::OnEncodedVideo(const VideoParameters& params, +bool WebmMuxer::OnEncodedVideo(const VideoParameters& params, std::unique_ptr<std::string> encoded_data, base::TimeTicks timestamp, bool is_key_frame) { @@ -154,23 +155,17 @@ encoded_frames_queue_.push_back(base::MakeUnique<EncodedVideoFrame>( std::move(encoded_data), timestamp, is_key_frame)); - return; + return true; } - // Dump all saved encoded video frames if any. - while (!encoded_frames_queue_.empty()) { - AddFrame( - std::move(encoded_frames_queue_.front()->data), video_track_index_, - encoded_frames_queue_.front()->timestamp - first_frame_timestamp_video_, - encoded_frames_queue_.front()->is_keyframe); - encoded_frames_queue_.pop_front(); - } + // Any saved encoded video frames must have been dumped in OnEncodedAudio(); + DCHECK(encoded_frames_queue_.empty()); - AddFrame(std::move(encoded_data), video_track_index_, - timestamp - first_frame_timestamp_video_, is_key_frame); + return AddFrame(std::move(encoded_data), video_track_index_, + timestamp - first_frame_timestamp_video_, is_key_frame); } -void WebmMuxer::OnEncodedAudio(const media::AudioParameters& params, +bool WebmMuxer::OnEncodedAudio(const media::AudioParameters& params, std::unique_ptr<std::string> encoded_data, base::TimeTicks timestamp) { DVLOG(2) << __func__ << " - " << encoded_data->size() << "B"; @@ -186,21 +181,24 @@ // TODO(ajose): Support multiple tracks: http://crbug.com/528523 if (has_video_ && !video_track_index_) { DVLOG(1) << __func__ << ": delaying until video track ready."; - return; + return true; } // Dump all saved encoded video frames if any. while (!encoded_frames_queue_.empty()) { - AddFrame( - std::move(encoded_frames_queue_.front()->data), video_track_index_, + const bool res = AddFrame( + base::MakeUnique<std::string>(*encoded_frames_queue_.front()->data), + video_track_index_, encoded_frames_queue_.front()->timestamp - first_frame_timestamp_video_, encoded_frames_queue_.front()->is_keyframe); + if (!res) + return false; encoded_frames_queue_.pop_front(); } - AddFrame(std::move(encoded_data), audio_track_index_, - timestamp - first_frame_timestamp_audio_, - true /* is_key_frame -- always true for audio */); + return AddFrame(std::move(encoded_data), audio_track_index_, + timestamp - first_frame_timestamp_audio_, + true /* is_key_frame -- always true for audio */); } void WebmMuxer::Pause() { @@ -309,7 +307,7 @@ << "Can't go back in a live WebM stream."; } -void WebmMuxer::AddFrame(std::unique_ptr<std::string> encoded_data, +bool WebmMuxer::AddFrame(std::unique_ptr<std::string> encoded_data, uint8_t track_index, base::TimeDelta timestamp, bool is_key_frame) { @@ -320,11 +318,19 @@ most_recent_timestamp_ = std::max(most_recent_timestamp_, timestamp - total_time_in_pause_); - segment_.AddFrame(reinterpret_cast<const uint8_t*>(encoded_data->data()), - encoded_data->size(), track_index, - most_recent_timestamp_.InMicroseconds() * - base::Time::kNanosecondsPerMicrosecond, - is_key_frame); + if (force_one_libwebm_error_) { + DVLOG(1) << "Forcing a libwebm error"; + force_one_libwebm_error_ = false; + return false; + } + + DCHECK(encoded_data->data()); + return segment_.AddFrame( + reinterpret_cast<const uint8_t*>(encoded_data->data()), + encoded_data->size(), track_index, + most_recent_timestamp_.InMicroseconds() * + base::Time::kNanosecondsPerMicrosecond, + is_key_frame); } WebmMuxer::EncodedVideoFrame::EncodedVideoFrame(
diff --git a/media/muxers/webm_muxer.h b/media/muxers/webm_muxer.h index e019983..e8ac3a4 100644 --- a/media/muxers/webm_muxer.h +++ b/media/muxers/webm_muxer.h
@@ -66,18 +66,20 @@ ~WebmMuxer() override; // Functions to add video and audio frames with |encoded_data.data()| - // to WebM Segment. - void OnEncodedVideo(const VideoParameters& params, + // to WebM Segment. Either one returns true on success. + bool OnEncodedVideo(const VideoParameters& params, std::unique_ptr<std::string> encoded_data, base::TimeTicks timestamp, bool is_key_frame); - void OnEncodedAudio(const media::AudioParameters& params, + bool OnEncodedAudio(const media::AudioParameters& params, std::unique_ptr<std::string> encoded_data, base::TimeTicks timestamp); void Pause(); void Resume(); + void ForceOneLibWebmErrorForTesting() { force_one_libwebm_error_ = true; } + private: friend class WebmMuxerTest; @@ -97,8 +99,8 @@ void ElementStartNotify(mkvmuxer::uint64 element_id, mkvmuxer::int64 position) override; - // Helper to simplify saving frames. - void AddFrame(std::unique_ptr<std::string> encoded_data, + // Helper to simplify saving frames. Returns true on success. + bool AddFrame(std::unique_ptr<std::string> encoded_data, uint8_t track_index, base::TimeDelta timestamp, bool is_key_frame); @@ -136,6 +138,8 @@ // The MkvMuxer active element. mkvmuxer::Segment segment_; + // Flag to force the next call to a |segment_| method to return false. + bool force_one_libwebm_error_; // Hold on to all encoded video frames to dump them with and when audio is // received, if expected, since WebM headers can only be written once.
diff --git a/media/muxers/webm_muxer_unittest.cc b/media/muxers/webm_muxer_unittest.cc index a65a885..8dcceb8 100644 --- a/media/muxers/webm_muxer_unittest.cc +++ b/media/muxers/webm_muxer_unittest.cc
@@ -33,13 +33,13 @@ namespace media { -struct kTestParams { +struct TestParams { VideoCodec codec; size_t num_video_tracks; size_t num_audio_tracks; }; -class WebmMuxerTest : public TestWithParam<kTestParams> { +class WebmMuxerTest : public TestWithParam<TestParams> { public: WebmMuxerTest() : webm_muxer_( @@ -109,9 +109,10 @@ .Times(AtLeast(1)) .WillRepeatedly( WithArgs<0>(Invoke(this, &WebmMuxerTest::SaveEncodedDataLen))); - webm_muxer_.OnEncodedVideo(WebmMuxer::VideoParameters(video_frame), - base::WrapUnique(new std::string(encoded_data)), - base::TimeTicks::Now(), false /* keyframe */); + EXPECT_TRUE(webm_muxer_.OnEncodedVideo( + WebmMuxer::VideoParameters(video_frame), + base::WrapUnique(new std::string(encoded_data)), base::TimeTicks::Now(), + false /* keyframe */)); // First time around WriteCallback() is pinged a number of times to write the // Matroska header, but at the end it dumps |encoded_data|. @@ -125,9 +126,9 @@ .Times(AtLeast(1)) .WillRepeatedly( WithArgs<0>(Invoke(this, &WebmMuxerTest::SaveEncodedDataLen))); - webm_muxer_.OnEncodedVideo(video_frame, - base::WrapUnique(new std::string(encoded_data)), - base::TimeTicks::Now(), false /* keyframe */); + EXPECT_TRUE(webm_muxer_.OnEncodedVideo( + video_frame, base::WrapUnique(new std::string(encoded_data)), + base::TimeTicks::Now(), false /* keyframe */)); // The second time around the callbacks should include a SimpleBlock header, // namely the track index, a timestamp and a flags byte, for a total of 6B. @@ -137,6 +138,13 @@ EXPECT_EQ(static_cast<int64_t>(begin_of_second_block + kSimpleBlockSize + encoded_data.size()), accumulated_position_); + + // Force an error in libwebm and expect OnEncodedVideo to fail. + webm_muxer_.ForceOneLibWebmErrorForTesting(); + EXPECT_FALSE( + webm_muxer_.OnEncodedVideo(WebmMuxer::VideoParameters(video_frame), + base::MakeUnique<std::string>(encoded_data), + base::TimeTicks::Now(), true /* keyframe */)); } TEST_P(WebmMuxerTest, OnEncodedAudioTwoFrames) { @@ -157,9 +165,9 @@ .Times(AtLeast(1)) .WillRepeatedly( WithArgs<0>(Invoke(this, &WebmMuxerTest::SaveEncodedDataLen))); - webm_muxer_.OnEncodedAudio(audio_params, - base::MakeUnique<std::string>(encoded_data), - base::TimeTicks::Now()); + EXPECT_TRUE(webm_muxer_.OnEncodedAudio( + audio_params, base::MakeUnique<std::string>(encoded_data), + base::TimeTicks::Now())); // First time around WriteCallback() is pinged a number of times to write the // Matroska header, but at the end it dumps |encoded_data|. @@ -173,9 +181,9 @@ .Times(AtLeast(1)) .WillRepeatedly( WithArgs<0>(Invoke(this, &WebmMuxerTest::SaveEncodedDataLen))); - webm_muxer_.OnEncodedAudio(audio_params, - base::MakeUnique<std::string>(encoded_data), - base::TimeTicks::Now()); + EXPECT_TRUE(webm_muxer_.OnEncodedAudio( + audio_params, base::MakeUnique<std::string>(encoded_data), + base::TimeTicks::Now())); // The second time around the callbacks should include a SimpleBlock header, // namely the track index, a timestamp and a flags byte, for a total of 6B. @@ -185,6 +193,12 @@ EXPECT_EQ(static_cast<int64_t>(begin_of_second_block + kSimpleBlockSize + encoded_data.size()), accumulated_position_); + + // Force an error in libwebm and expect OnEncodedAudio to fail. + webm_muxer_.ForceOneLibWebmErrorForTesting(); + EXPECT_FALSE(webm_muxer_.OnEncodedAudio( + audio_params, base::MakeUnique<std::string>(encoded_data), + base::TimeTicks::Now())); } // This test verifies that when video data comes before audio data, we save the @@ -194,24 +208,24 @@ if (GetParam().num_video_tracks == 0 || GetParam().num_audio_tracks == 0) return; - // First send a video keyframe + // First send a video keyframe. const gfx::Size frame_size(160, 80); const scoped_refptr<VideoFrame> video_frame = VideoFrame::CreateBlackFrame(frame_size); const std::string encoded_video("thisisanencodedvideopacket"); - webm_muxer_.OnEncodedVideo(WebmMuxer::VideoParameters(video_frame), - base::WrapUnique(new std::string(encoded_video)), - base::TimeTicks::Now(), true /* keyframe */); + EXPECT_TRUE(webm_muxer_.OnEncodedVideo( + WebmMuxer::VideoParameters(video_frame), + base::WrapUnique(new std::string(encoded_video)), base::TimeTicks::Now(), + true /* keyframe */)); // A few encoded non key frames. const int kNumNonKeyFrames = 2; for (int i = 0; i < kNumNonKeyFrames; ++i) { - webm_muxer_.OnEncodedVideo(WebmMuxer::VideoParameters(video_frame), - base::WrapUnique(new std::string(encoded_video)), - base::TimeTicks::Now(), false /* keyframe */); + EXPECT_TRUE(webm_muxer_.OnEncodedVideo( + WebmMuxer::VideoParameters(video_frame), + base::WrapUnique(new std::string(encoded_video)), + base::TimeTicks::Now(), false /* keyframe */)); } - // Send some audio. The header will be written and muxing will proceed - // normally. const int sample_rate = 48000; const int bits_per_sample = 16; const int frames_per_buffer = 480; @@ -221,7 +235,13 @@ frames_per_buffer); const std::string encoded_audio("thisisanencodedaudiopacket"); - // We should first get the encoded video frames, then the encoded audio frame. + // Force one libwebm error and verify OnEncodedAudio() fails. + webm_muxer_.ForceOneLibWebmErrorForTesting(); + EXPECT_FALSE(webm_muxer_.OnEncodedAudio( + audio_params, base::WrapUnique(new std::string(encoded_audio)), + base::TimeTicks::Now())); + + // We should get the queued encoded video frames, then an encoded audio frame. Sequence s; EXPECT_CALL(*this, WriteCallback(Eq(encoded_video))) .Times(1 + kNumNonKeyFrames) @@ -231,12 +251,12 @@ EXPECT_CALL(*this, WriteCallback( AllOf(Not(Eq(encoded_video)), Not(Eq(encoded_audio))))) .Times(AnyNumber()); - webm_muxer_.OnEncodedAudio(audio_params, - base::WrapUnique(new std::string(encoded_audio)), - base::TimeTicks::Now()); + EXPECT_TRUE(webm_muxer_.OnEncodedAudio( + audio_params, base::WrapUnique(new std::string(encoded_audio)), + base::TimeTicks::Now())); } -const kTestParams kTestCases[] = { +const TestParams kTestCases[] = { {kCodecVP8, 1 /* num_video_tracks */, 0 /*num_audio_tracks*/}, {kCodecVP8, 0, 1}, {kCodecVP8, 1, 1},
diff --git a/net/cert/ct_log_response_parser.cc b/net/cert/ct_log_response_parser.cc index 5baf1b3..b6067d1 100644 --- a/net/cert/ct_log_response_parser.cc +++ b/net/cert/ct_log_response_parser.cc
@@ -4,10 +4,11 @@ #include "net/cert/ct_log_response_parser.h" +#include <memory> + #include "base/base64.h" #include "base/json/json_value_converter.h" #include "base/logging.h" -#include "base/memory/scoped_vector.h" #include "base/strings/string_piece.h" #include "base/time/time.h" #include "base/values.h" @@ -105,7 +106,7 @@ // Structure for making JSON decoding easier. The string fields // are base64-encoded so will require further decoding. struct JsonConsistencyProof { - ScopedVector<std::string> proof_nodes; + std::vector<std::unique_ptr<std::string>> proof_nodes; static void RegisterJSONConverter( base::JSONValueConverter<JsonConsistencyProof>* converter); @@ -170,7 +171,7 @@ } consistency_proof->reserve(parsed_proof.proof_nodes.size()); - for (std::string* proof_node : parsed_proof.proof_nodes) { + for (const auto& proof_node : parsed_proof.proof_nodes) { consistency_proof->push_back(*proof_node); }
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 13e17b5..d26c1d3e 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -885,6 +885,18 @@ ] } ], + "InstantApps": [ + { + "platforms": [ + "android" + ], + "experiments": [ + { + "name": "InstantAppsEnabled" + } + ] + } + ], "IntelligentSessionRestore": [ { "platforms": [
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index c0985ae..da8d276d 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -2314,9 +2314,6 @@ crbug.com/676229 [ Linux ] plugins/mouse-click-plugin-clears-selection.html [ Failure Pass ] -crbug.com/677145 inspector/tracing/timeline-js/timeline-script-tag-1.html [ Pass Failure ] -crbug.com/677145 virtual/threaded/inspector/tracing/timeline-js/timeline-script-tag-1.html [ Pass Failure ] - crbug.com/678346 [ Win7 Debug ] fast/dom/shadow/selections-in-shadow.html [ Pass Timeout ] crbug.com/678346 [ Win7 Debug ] storage/indexeddb/index-cursor.html [ Pass Timeout ] crbug.com/678346 [ Win7 Debug ] storage/indexeddb/mozilla/test_objectStore_openKeyCursor.html [ Pass Timeout ]
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/timeline-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/timeline-test.js index c1ad4c83..0059174 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/timeline-test.js +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/timeline-test.js
@@ -268,57 +268,6 @@ formatter(record); }; -// Dump just the record name, indenting output on separate lines for subrecords -InspectorTest.dumpTimelineRecord = function(record, detailsCallback, level, filterTypes) -{ - if (typeof level !== "number") - level = 0; - var message = ""; - for (var i = 0; i < level ; ++i) - message = "----" + message; - if (level > 0) - message = message + "> "; - if (record.type() === TimelineModel.TimelineModel.RecordType.TimeStamp - || record.type() === TimelineModel.TimelineModel.RecordType.ConsoleTime) { - message += Timeline.TimelineUIUtils.eventTitle(record.traceEvent()); - } else { - message += record.type(); - } - if (detailsCallback) - message += " " + detailsCallback(record); - InspectorTest.addResult(message); - - var children = record.children(); - var numChildren = children.length; - for (var i = 0; i < numChildren; ++i) { - if (filterTypes && filterTypes.indexOf(children[i].type()) == -1) - continue; - InspectorTest.dumpTimelineRecord(children[i], detailsCallback, level + 1, filterTypes); - } -} - -InspectorTest.dumpTimelineModelRecord = function(record, level) -{ - if (typeof level !== "number") - level = 0; - var prefix = ""; - for (var i = 0; i < level ; ++i) - prefix = "----" + prefix; - if (level > 0) - prefix = prefix + "> "; - InspectorTest.addResult(prefix + record.type() + ": " + (Timeline.TimelineUIUtils.buildDetailsTextForTraceEvent(record.traceEvent(), null) || "")); - - var numChildren = record.children() ? record.children().length : 0; - for (var i = 0; i < numChildren; ++i) - InspectorTest.dumpTimelineModelRecord(record.children()[i], level + 1); -} - -InspectorTest.dumpTimelineRecords = function(timelineRecords) -{ - for (var i = 0; i < timelineRecords.length; ++i) - InspectorTest.dumpTimelineRecord(timelineRecords[i], 0); -}; - InspectorTest.printTimelineRecordProperties = function(record) { InspectorTest.printTraceEventProperties(record.traceEvent()); @@ -330,6 +279,18 @@ InspectorTest.printTraceEventProperties(traceEvent); } +InspectorTest.forAllEvents = function(events, callback) +{ + let eventStack = []; + for (let event of events) { + while (eventStack.length && eventStack.peekLast().endTime <= event.startTime) + eventStack.pop(); + callback(event, eventStack); + if (event.endTime) + eventStack.push(event); + } +} + InspectorTest.printTraceEventProperties = function(traceEvent) { InspectorTest.addResult(traceEvent.name + " Properties:");
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-correct-suggestions-expected.txt b/third_party/WebKit/LayoutTests/inspector/console/console-correct-suggestions-expected.txt index 9bdbd35e..86eade7 100644 --- a/third_party/WebKit/LayoutTests/inspector/console/console-correct-suggestions-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector/console/console-correct-suggestions-expected.txt
@@ -71,4 +71,36 @@ Checking 'shou' Not Found: should not find this +Checking 'document. bo' +Found: body + +Checking 'document. bo' +Found: body + +Checking 'document. +bo' +Found: body + +Checking 'document. +bo' +Found: body + +Checking 'document [ 'bo' +Not Found: 'body'] + +Checking 'function hey(should' +Not Found: shouldNotFindThisFunction + +Checking 'var should' +Not Found: shouldNotFindThisFunction + +Checking 'document[[win' +Found: window + +Checking 'document[ [win' +Found: window + +Checking 'document[ [ win' +Found: window +
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-correct-suggestions.html b/third_party/WebKit/LayoutTests/inspector/console/console-correct-suggestions.html index d2a9cec6..f01839c4 100644 --- a/third_party/WebKit/LayoutTests/inspector/console/console-correct-suggestions.html +++ b/third_party/WebKit/LayoutTests/inspector/console/console-correct-suggestions.html
@@ -68,7 +68,17 @@ () => testCompletions("`${do", ["document"], false), () => testCompletions("// do", ["document"], false), () => testCompletions('["should', ["shouldNotFindThisFunction"]), - () => testCompletions("shou", ["should not find this"]) + () => testCompletions("shou", ["should not find this"]), + () => testCompletions("document. bo", ["body"]), + () => testCompletions("document.\tbo", ["body"]), + () => testCompletions("document.\nbo", ["body"]), + () => testCompletions("document.\r\nbo", ["body"]), + () => testCompletions("document [ 'bo", ["'body']"]), + () => testCompletions("function hey(should", ["shouldNotFindThisFunction"]), + () => testCompletions("var should", ["shouldNotFindThisFunction"]), + () => testCompletions("document[[win", ["window"]), + () => testCompletions("document[ [win", ["window"]), + () => testCompletions("document[ [ win", ["window"]) ]).then(InspectorTest.completeTest); }
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-tag-1-expected.txt b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-tag-1-expected.txt index fa7747d..75665e6 100644 --- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-tag-1-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-tag-1-expected.txt
@@ -2,7 +2,6 @@ Tests the Timeline API instrumentation of an HTML script tag. -EvaluateScript EvaluateScript Properties: { data : { @@ -11,8 +10,6 @@ startTime : <number> type : "EvaluateScript" } -EvaluateScript -----> Timestamp: SCRIPT TAG EvaluateScript Properties: { data : { @@ -26,4 +23,5 @@ startTime : <number> type : "EvaluateScript" } +----> Timestamp: SCRIPT TAG
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-tag-1.html b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-tag-1.html index 5a0259f4..d77e264 100644 --- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-tag-1.html +++ b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-tag-1.html
@@ -31,14 +31,12 @@ function format(record) { if (record.type() === TimelineModel.TimelineModel.RecordType.EvaluateScript) { - InspectorTest.dumpTimelineRecord(record, undefined, undefined, [ - "TimeStamp", - ]); InspectorTest.printTimelineRecordProperties(record); + } else if (record.type() === TimelineModel.TimelineModel.RecordType.TimeStamp) { + InspectorTest.addResult(`----> ${Timeline.TimelineUIUtils.eventTitle(record.traceEvent())}`); } - } - - InspectorTest.printTimelineRecords(null, InspectorTest.safeWrap(format)); + }; + InspectorTest.printTimelineRecords(null, format); InspectorTest.completeTest(); } }
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-model-expected.txt b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-model-expected.txt index 3607f7c..0ca0edb 100644 --- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-model-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-model-expected.txt
@@ -1,5 +1,7 @@ Test trace-specific implementation of timeline model +TracingStartedInPage: +SetLayerTreeId: Program: ----> FunctionCall: --------> ResourceSendRequest: example.com
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-model.html b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-model.html index 3973c64..d72855c 100644 --- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-model.html +++ b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-model.html
@@ -52,12 +52,11 @@ ]; var tracingTimelineModel = InspectorTest.createTimelineModelWithEvents(commonMetadata.concat(traceEvents)); - var records = tracingTimelineModel.records(); - var topLevelRecordsCount = 2; - InspectorTest.assertEquals(topLevelRecordsCount, records.length); - for (var i = 0; i < records.length; ++i) { - InspectorTest.dumpTimelineModelRecord(records[i]); - } + InspectorTest.forAllEvents(tracingTimelineModel.mainThreadEvents(), (event, stack) => { + const prefix = Array(stack.length + 1).join("----") + (stack.length ? "> " : ""); + const details = Timeline.TimelineUIUtils.buildDetailsTextForTraceEvent(event, null) || ""; + InspectorTest.addResult(`${prefix}${event.name}: ${details}`); + }); InspectorTest.completeTest(); }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/border-radius-repaint-2-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/border-radius-repaint-2-expected.txt index 7e1f99d..04692bb 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/border-radius-repaint-2-expected.txt +++ b/third_party/WebKit/LayoutTests/paint/invalidation/border-radius-repaint-2-expected.txt
@@ -18,6 +18,11 @@ "reason": "border box change" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 780], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "rect": [8, 224, 784, 548], "reason": "incremental" @@ -36,6 +41,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "reason": "incremental" },
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-and-absolute-position-scrolled-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-and-absolute-position-scrolled-expected.txt index e1beaf2..8c7044e 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-and-absolute-position-scrolled-expected.txt +++ b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-and-absolute-position-scrolled-expected.txt
@@ -12,6 +12,11 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 2016], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow (positioned) DIV id='absoluteDiv' class='absolute green'", "rect": [108, 5708, 100, 100], "reason": "subtree" @@ -34,6 +39,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow (positioned) DIV id='absoluteDiv' class='absolute green'", "reason": "style change" }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/scrolled-iframe-scrollbar-change-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scrolled-iframe-scrollbar-change-expected.txt index b9a0b28..72fe8f3 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/scrolled-iframe-scrollbar-change-expected.txt +++ b/third_party/WebKit/LayoutTests/paint/invalidation/scrolled-iframe-scrollbar-change-expected.txt
@@ -13,6 +13,10 @@ "reason": "style change" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY class='noScroll'", "reason": "style change" },
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt index 16c08a5..5b2f5e69 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt +++ b/third_party/WebKit/LayoutTests/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
@@ -7,6 +7,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 785, 829], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [0, 735, 785, 94], "reason": "incremental" @@ -60,6 +65,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutIFrame IFRAME id='iframe'", "reason": "layoutObject insertion" },
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/shift-relative-positioned-container-with-image-removal-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/shift-relative-positioned-container-with-image-removal-expected.txt index 1b942e91..65d3d3e 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/shift-relative-positioned-container-with-image-removal-expected.txt +++ b/third_party/WebKit/LayoutTests/paint/invalidation/shift-relative-positioned-container-with-image-removal-expected.txt
@@ -7,6 +7,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 785, 833], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [0, 735, 785, 98], "reason": "incremental" @@ -62,6 +67,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow (relative positioned) DIV class='relative paddingTop'", "reason": "bounds change" },
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-background-image-fixed-centered-composited-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-background-image-fixed-centered-composited-expected.txt index d8a230a..90bf90d7 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-background-image-fixed-centered-composited-expected.txt +++ b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-background-image-fixed-centered-composited-expected.txt
@@ -9,6 +9,11 @@ "object": "LayoutView #document", "rect": [0, 250, 600, 250], "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 600, 8], + "reason": "forced by layout" } ] } @@ -17,6 +22,10 @@ { "object": "LayoutView #document", "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] } @@ -28,6 +37,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 600, 8], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [400, 0, 200, 250], "reason": "incremental" @@ -39,6 +53,10 @@ { "object": "LayoutView #document", "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] } @@ -53,6 +71,11 @@ "object": "LayoutView #document", "rect": [0, 250, 400, 350], "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 400, 8], + "reason": "forced by layout" } ] } @@ -61,6 +84,10 @@ { "object": "LayoutView #document", "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] } @@ -72,6 +99,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 8], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [400, 0, 400, 600], "reason": "incremental" @@ -83,6 +115,10 @@ { "object": "LayoutView #document", "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-background-image-fixed-centered-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-background-image-fixed-centered-expected.txt index cdd87ce..128cff1e 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-background-image-fixed-centered-expected.txt +++ b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-background-image-fixed-centered-expected.txt
@@ -10,6 +10,11 @@ "object": "LayoutView #document", "rect": [0, 0, 600, 500], "reason": "bounds change" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 600, 8], + "reason": "forced by layout" } ] } @@ -18,6 +23,10 @@ { "object": "LayoutView #document", "reason": "bounds change" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] } @@ -33,6 +42,11 @@ "object": "LayoutView #document", "rect": [0, 0, 600, 250], "reason": "bounds change" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 600, 8], + "reason": "forced by layout" } ] } @@ -41,6 +55,10 @@ { "object": "LayoutView #document", "reason": "bounds change" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] } @@ -56,6 +74,11 @@ "object": "LayoutView #document", "rect": [0, 0, 400, 600], "reason": "bounds change" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 400, 8], + "reason": "forced by layout" } ] } @@ -64,6 +87,10 @@ { "object": "LayoutView #document", "reason": "bounds change" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] } @@ -79,6 +106,11 @@ "object": "LayoutView #document", "rect": [0, 0, 800, 600], "reason": "bounds change" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 8], + "reason": "forced by layout" } ] } @@ -87,6 +119,10 @@ { "object": "LayoutView #document", "reason": "bounds change" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-background-image-generated-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-background-image-generated-expected.txt index cdd87ce..128cff1e 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-background-image-generated-expected.txt +++ b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-background-image-generated-expected.txt
@@ -10,6 +10,11 @@ "object": "LayoutView #document", "rect": [0, 0, 600, 500], "reason": "bounds change" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 600, 8], + "reason": "forced by layout" } ] } @@ -18,6 +23,10 @@ { "object": "LayoutView #document", "reason": "bounds change" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] } @@ -33,6 +42,11 @@ "object": "LayoutView #document", "rect": [0, 0, 600, 250], "reason": "bounds change" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 600, 8], + "reason": "forced by layout" } ] } @@ -41,6 +55,10 @@ { "object": "LayoutView #document", "reason": "bounds change" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] } @@ -56,6 +74,11 @@ "object": "LayoutView #document", "rect": [0, 0, 400, 600], "reason": "bounds change" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 400, 8], + "reason": "forced by layout" } ] } @@ -64,6 +87,10 @@ { "object": "LayoutView #document", "reason": "bounds change" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] } @@ -79,6 +106,11 @@ "object": "LayoutView #document", "rect": [0, 0, 800, 600], "reason": "bounds change" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 8], + "reason": "forced by layout" } ] } @@ -87,6 +119,10 @@ { "object": "LayoutView #document", "reason": "bounds change" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-background-image-non-fixed-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-background-image-non-fixed-expected.txt index 5e3ebd4..302f48d4 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-background-image-non-fixed-expected.txt +++ b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-background-image-non-fixed-expected.txt
@@ -10,6 +10,11 @@ "object": "LayoutView #document", "rect": [0, 250, 600, 250], "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 600, 8], + "reason": "forced by layout" } ] } @@ -18,6 +23,10 @@ { "object": "LayoutView #document", "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] } @@ -30,6 +39,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 600, 8], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [400, 0, 200, 250], "reason": "incremental" @@ -41,6 +55,10 @@ { "object": "LayoutView #document", "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] } @@ -56,6 +74,11 @@ "object": "LayoutView #document", "rect": [0, 250, 400, 350], "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 400, 8], + "reason": "forced by layout" } ] } @@ -64,6 +87,10 @@ { "object": "LayoutView #document", "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] } @@ -76,6 +103,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 8], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [400, 0, 400, 600], "reason": "incremental" @@ -87,6 +119,10 @@ { "object": "LayoutView #document", "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-centered-inline-under-fixed-pos-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-centered-inline-under-fixed-pos-expected.txt index 73762ea..499f797 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-centered-inline-under-fixed-pos-expected.txt +++ b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-centered-inline-under-fixed-pos-expected.txt
@@ -17,6 +17,11 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 600, 8], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow DIV class='parent'", "rect": [0, 0, 6, 500], "reason": "forced by layout" @@ -40,6 +45,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow (positioned) DIV class='container'", "reason": "forced by layout" }, @@ -71,6 +80,11 @@ "reason": "forced by layout" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 600, 8], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [400, 0, 200, 250], "reason": "incremental" @@ -94,6 +108,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow (positioned) DIV class='container'", "reason": "forced by layout" }, @@ -130,6 +148,11 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 400, 8], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow DIV class='parent'", "rect": [0, 0, 6, 600], "reason": "forced by layout" @@ -153,6 +176,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow (positioned) DIV class='container'", "reason": "full" }, @@ -184,6 +211,11 @@ "reason": "full" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 8], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [400, 0, 400, 600], "reason": "incremental" @@ -207,6 +239,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow (positioned) DIV class='container'", "reason": "full" },
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-frameset-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-frameset-expected.txt index 4b7110b..a29a0fb 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-frameset-expected.txt +++ b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-frameset-expected.txt
@@ -7,6 +7,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 600, 500], + "reason": "forced by layout" + }, + { "object": "LayoutFrameSet FRAMESET", "rect": [0, 0, 600, 500], "reason": "border box change" @@ -17,17 +22,32 @@ "reason": "incremental" }, { - "object": "LayoutFrame FRAME", + "object": "LayoutBlockFlow HTML", "rect": [153, 0, 294, 500], "reason": "forced by layout" }, { "object": "LayoutFrame FRAME", + "rect": [153, 0, 294, 500], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", "rect": [453, 0, 147, 500], "reason": "forced by layout" }, { "object": "LayoutFrame FRAME", + "rect": [453, 0, 147, 500], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 147, 500], + "reason": "forced by layout" + }, + { + "object": "LayoutFrame FRAME", "rect": [0, 0, 147, 500], "reason": "forced by layout" } @@ -40,6 +60,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutFrameSet FRAMESET", "reason": "border box change" }, @@ -60,12 +84,24 @@ "reason": "scroll" }, { - "object": "VerticalScrollbar", - "reason": "scroll" + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" }, { "object": "VerticalScrollbar", "reason": "scroll" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { + "object": "VerticalScrollbar", + "reason": "scroll" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] } @@ -78,11 +114,21 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 600, 250], + "reason": "forced by layout" + }, + { "object": "LayoutFrameSet FRAMESET", "rect": [0, 0, 600, 250], "reason": "border box change" }, { + "object": "LayoutBlockFlow HTML", + "rect": [153, 0, 294, 250], + "reason": "forced by layout" + }, + { "object": "LayoutFrame FRAME", "rect": [153, 0, 294, 250], "reason": "forced by layout" @@ -93,21 +139,41 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "rect": [103, 0, 194, 250], + "reason": "forced by layout" + }, + { "object": "LayoutFrame FRAME", "rect": [103, 0, 194, 250], "reason": "forced by layout" }, { + "object": "LayoutBlockFlow HTML", + "rect": [453, 0, 147, 250], + "reason": "forced by layout" + }, + { "object": "LayoutFrame FRAME", "rect": [453, 0, 147, 250], "reason": "forced by layout" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 147, 250], + "reason": "forced by layout" + }, + { "object": "LayoutFrame FRAME", "rect": [0, 0, 147, 250], "reason": "forced by layout" }, { + "object": "LayoutBlockFlow HTML", + "rect": [303, 0, 97, 250], + "reason": "forced by layout" + }, + { "object": "LayoutFrame FRAME", "rect": [303, 0, 97, 250], "reason": "forced by layout" @@ -121,6 +187,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutFrameSet FRAMESET", "reason": "border box change" }, @@ -141,6 +211,10 @@ "reason": "scroll" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "HorizontalScrollbar", "reason": "scroll" }, @@ -150,7 +224,7 @@ }, { "object": "LayoutBlockFlow HTML", - "reason": "location change" + "reason": "forced by layout" }, { "object": "LayoutBlockFlow BODY", @@ -166,7 +240,7 @@ }, { "object": "LayoutBlockFlow HTML", - "reason": "location change" + "reason": "forced by layout" }, { "object": "LayoutBlockFlow BODY", @@ -183,6 +257,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 400, 600], + "reason": "forced by layout" + }, + { "object": "LayoutFrameSet FRAMESET", "rect": [0, 0, 400, 600], "reason": "border box change" @@ -193,17 +272,32 @@ "reason": "incremental" }, { - "object": "LayoutFrame FRAME", + "object": "LayoutBlockFlow HTML", "rect": [103, 0, 194, 600], "reason": "forced by layout" }, { "object": "LayoutFrame FRAME", + "rect": [103, 0, 194, 600], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", "rect": [303, 0, 97, 600], "reason": "forced by layout" }, { "object": "LayoutFrame FRAME", + "rect": [303, 0, 97, 600], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 97, 600], + "reason": "forced by layout" + }, + { + "object": "LayoutFrame FRAME", "rect": [0, 0, 97, 600], "reason": "forced by layout" } @@ -216,6 +310,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutFrameSet FRAMESET", "reason": "border box change" }, @@ -230,6 +328,18 @@ { "object": "LayoutFrame FRAME", "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] } @@ -242,6 +352,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 600], + "reason": "forced by layout" + }, + { "object": "LayoutFrameSet FRAMESET", "rect": [0, 0, 800, 600], "reason": "border box change" @@ -252,27 +367,52 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "rect": [203, 0, 394, 600], + "reason": "forced by layout" + }, + { "object": "LayoutFrame FRAME", "rect": [203, 0, 394, 600], "reason": "forced by layout" }, { + "object": "LayoutBlockFlow HTML", + "rect": [603, 0, 197, 600], + "reason": "forced by layout" + }, + { "object": "LayoutFrame FRAME", "rect": [603, 0, 197, 600], "reason": "forced by layout" }, { - "object": "LayoutFrame FRAME", + "object": "LayoutBlockFlow HTML", "rect": [0, 0, 197, 600], "reason": "forced by layout" }, { "object": "LayoutFrame FRAME", + "rect": [0, 0, 197, 600], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", "rect": [103, 0, 194, 600], "reason": "forced by layout" }, { "object": "LayoutFrame FRAME", + "rect": [103, 0, 194, 600], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [303, 0, 97, 600], + "reason": "forced by layout" + }, + { + "object": "LayoutFrame FRAME", "rect": [303, 0, 97, 600], "reason": "forced by layout" } @@ -285,6 +425,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutFrameSet FRAMESET", "reason": "border box change" }, @@ -301,12 +445,16 @@ "reason": "forced by layout" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "reason": "location change" }, { "object": "LayoutBlockFlow HTML", - "reason": "location change" + "reason": "forced by layout" }, { "object": "LayoutBlockFlow BODY", @@ -318,7 +466,7 @@ }, { "object": "LayoutBlockFlow HTML", - "reason": "location change" + "reason": "forced by layout" }, { "object": "LayoutBlockFlow BODY",
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-media-query-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-media-query-expected.txt index 3d6a9e3..833a115 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-media-query-expected.txt +++ b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-media-query-expected.txt
@@ -11,6 +11,11 @@ "object": "LayoutView #document", "rect": [0, 250, 600, 250], "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 600, 8], + "reason": "forced by layout" } ] } @@ -19,6 +24,10 @@ { "object": "LayoutView #document", "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] } @@ -32,6 +41,11 @@ "backgroundColor": "#0000FF", "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 600, 8], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [400, 0, 200, 250], "reason": "incremental" @@ -43,6 +57,10 @@ { "object": "LayoutView #document", "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] } @@ -59,6 +77,11 @@ "object": "LayoutView #document", "rect": [0, 250, 400, 350], "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 400, 8], + "reason": "forced by layout" } ] } @@ -67,6 +90,10 @@ { "object": "LayoutView #document", "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] } @@ -80,6 +107,11 @@ "backgroundColor": "#0000FF", "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 8], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [400, 0, 400, 600], "reason": "incremental" @@ -91,6 +123,10 @@ { "object": "LayoutView #document", "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-percent-html-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-percent-html-expected.txt index b12c233..2a0f7d8 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-percent-html-expected.txt +++ b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-percent-html-expected.txt
@@ -12,6 +12,11 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 600, 250], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow DIV", "rect": [0, 0, 300, 125], "reason": "border box change" @@ -25,6 +30,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow DIV", "reason": "border box change" } @@ -39,6 +48,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 600, 125], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow DIV", "rect": [0, 0, 300, 63], "reason": "border box change" @@ -57,6 +71,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow DIV", "reason": "border box change" } @@ -76,6 +94,11 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 400, 300], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow DIV", "rect": [0, 0, 200, 150], "reason": "border box change" @@ -89,6 +112,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow DIV", "reason": "border box change" } @@ -103,6 +130,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 300], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [400, 0, 400, 600], "reason": "incremental" @@ -121,6 +153,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow DIV", "reason": "incremental" }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-percent-width-height-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-percent-width-height-expected.txt index 8cd53c0..9b89be8 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-percent-width-height-expected.txt +++ b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-percent-width-height-expected.txt
@@ -25,6 +25,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow (positioned) DIV", "reason": "incremental" } @@ -57,6 +61,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow (positioned) DIV", "reason": "incremental" } @@ -89,6 +97,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow (positioned) DIV", "reason": "incremental" } @@ -121,6 +133,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow (positioned) DIV", "reason": "incremental" }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-positioned-bottom-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-positioned-bottom-expected.txt index 08674f06..667e9d0 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-positioned-bottom-expected.txt +++ b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-positioned-bottom-expected.txt
@@ -30,6 +30,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow (positioned) DIV", "reason": "bounds change" } @@ -55,6 +59,10 @@ { "object": "LayoutView #document", "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] } @@ -90,6 +98,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow (positioned) DIV", "reason": "bounds change" } @@ -115,6 +127,10 @@ { "object": "LayoutView #document", "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-positioned-percent-top-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-positioned-percent-top-expected.txt index a6abe419..5635bd5 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-positioned-percent-top-expected.txt +++ b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-positioned-percent-top-expected.txt
@@ -30,6 +30,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow (positioned) DIV", "reason": "bounds change" } @@ -55,6 +59,10 @@ { "object": "LayoutView #document", "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] } @@ -90,6 +98,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow (positioned) DIV", "reason": "bounds change" } @@ -115,6 +127,10 @@ { "object": "LayoutView #document", "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-viewport-percent-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-viewport-percent-expected.txt index 9ba1963..b0b4159b 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-viewport-percent-expected.txt +++ b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-viewport-percent-expected.txt
@@ -30,6 +30,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow DIV", "reason": "incremental" } @@ -55,6 +59,10 @@ { "object": "LayoutView #document", "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] } @@ -90,6 +98,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow DIV", "reason": "incremental" } @@ -115,6 +127,10 @@ { "object": "LayoutView #document", "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/abspos-shift-image-incorrect-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/abspos-shift-image-incorrect-repaint-expected.txt index 8501e34..3bc3c4a8 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/abspos-shift-image-incorrect-repaint-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/abspos-shift-image-incorrect-repaint-expected.txt
@@ -17,6 +17,11 @@ "reason": "bounds change" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 56], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow (relative positioned) DIV class='imageWrapper'", "rect": [704, 0, 700, 237], "reason": "bounds change" @@ -80,6 +85,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow (positioned) DIV id='shiftMe'", "reason": "bounds change" },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt index 727e8d9..8303ca25 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
@@ -30,6 +30,16 @@ "reason": "style change" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 500, 300, 36], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 500, 285, 150], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "rect": [8, 508, 284, 20], "reason": "forced by layout" @@ -66,6 +76,10 @@ "reason": "style change" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "reason": "forced by layout" },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-2-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-2-expected.txt index 46a24049..d85a716 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-2-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-2-expected.txt
@@ -7,6 +7,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 485, 600], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow P", "rect": [8, 74, 418, 526], "reason": "border box change" @@ -135,6 +140,10 @@ "reason": "scroll" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow P", "reason": "border box change" },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-8-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-8-expected.txt index 151c399..1954ee2 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-8-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-8-expected.txt
@@ -7,6 +7,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 485, 600], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow P", "rect": [8, 74, 418, 526], "reason": "forced by layout" @@ -114,6 +119,10 @@ "reason": "scroll" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow P", "reason": "forced by layout" },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/resize-iframe-text-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/resize-iframe-text-expected.txt index aeb175d..40a3c663 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/resize-iframe-text-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/resize-iframe-text-expected.txt
@@ -12,11 +12,21 @@ "reason": "forced by layout" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 759], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [0, 600, 800, 200], "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 36], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "rect": [8, 8, 784, 20], "reason": "forced by layout" @@ -45,6 +55,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "reason": "forced by layout" }, @@ -77,6 +91,10 @@ "reason": "scroll" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow H1", "reason": "became visible" },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt index 9919ab9..e8e68ae2 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
@@ -7,6 +7,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 785, 836], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [0, 742, 785, 94], "reason": "incremental" @@ -60,6 +65,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutIFrame IFRAME id='iframe'", "reason": "layoutObject insertion" },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/shift-relative-positioned-container-with-image-removal-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/shift-relative-positioned-container-with-image-removal-expected.txt index 1c8dfb15..08729c6 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/shift-relative-positioned-container-with-image-removal-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/shift-relative-positioned-container-with-image-removal-expected.txt
@@ -7,6 +7,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 785, 841], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [0, 742, 785, 99], "reason": "incremental" @@ -62,6 +67,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow (relative positioned) DIV class='relative paddingTop'", "reason": "bounds change" },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table-shrink-row-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table-shrink-row-repaint-expected.txt index 2bbd089..d86f50e 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table-shrink-row-repaint-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table-shrink-row-repaint-expected.txt
@@ -7,6 +7,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 785, 1050], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [0, 850, 785, 200], "reason": "incremental" @@ -265,6 +270,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutTableCell TD id='resizeMe'", "reason": "incremental" },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/text-match-document-change-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/text-match-document-change-expected.txt index fba9d1c2..7d685a1 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/text-match-document-change-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/text-match-document-change-expected.txt
@@ -7,6 +7,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [10, 102, 285, 400], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow DIV id='to-be-changed'", "rect": [18, 130, 269, 40], "reason": "full" @@ -39,6 +44,10 @@ "reason": "scroll" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow DIV id='to-be-changed'", "reason": "full" },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/window-resize-vertical-writing-mode-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/window-resize-vertical-writing-mode-expected.txt index 609d5f1..574f683 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/window-resize-vertical-writing-mode-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
@@ -7,6 +7,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 939, 235], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [0, 0, 939, 235], "reason": "bounds change" @@ -37,6 +42,11 @@ "reason": "scroll" }, { + "object": "LayoutBlockFlow HTML", + "rect": [497, 0, 442, 500], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "rect": [505, 8, 426, 484], "reason": "forced by layout" @@ -59,6 +69,10 @@ "reason": "bounds change" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "reason": "forced by layout" }, @@ -269,6 +283,11 @@ "reason": "full" }, { + "object": "LayoutBlockFlow HTML", + "rect": [-539, 0, 939, 235], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [-539, 0, 939, 235], "reason": "bounds change" @@ -294,6 +313,11 @@ "reason": "scroll" }, { + "object": "LayoutBlockFlow HTML", + "rect": [29, 0, 371, 600], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "rect": [37, 8, 355, 584], "reason": "forced by layout" @@ -316,6 +340,10 @@ "reason": "bounds change" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "reason": "forced by layout" }, @@ -363,6 +391,16 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "rect": [429, 0, 371, 600], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [29, 0, 371, 600], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "rect": [437, 8, 355, 584], "reason": "forced by layout" @@ -391,6 +429,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "reason": "forced by layout" },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/stable/paint/invalidation/resize-iframe-text-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/stable/paint/invalidation/resize-iframe-text-expected.txt new file mode 100644 index 0000000..40a3c663 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/stable/paint/invalidation/resize-iframe-text-expected.txt
@@ -0,0 +1,107 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 800], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutIFrame (positioned) IFRAME", + "rect": [0, 0, 800, 800], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 759], + "reason": "forced by layout" + }, + { + "object": "LayoutView #document", + "rect": [0, 600, 800, 200], + "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 36], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow BODY", + "rect": [8, 8, 784, 20], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow H1", + "rect": [8, 700, 600, 37], + "reason": "became visible" + }, + { + "object": "LayoutText #text", + "rect": [8, 8, 324, 19], + "reason": "forced by layout" + }, + { + "object": "LayoutView #document", + "rect": [785, 0, 15, 600], + "reason": "scroll" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutView #document", + "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow BODY", + "reason": "forced by layout" + }, + { + "object": "RootInlineBox", + "reason": "forced by layout" + }, + { + "object": "LayoutText #text", + "reason": "forced by layout" + }, + { + "object": "InlineTextBox 'Test passes if you see \"Success\" after window resizes.'", + "reason": "forced by layout" + }, + { + "object": "LayoutIFrame (positioned) IFRAME", + "reason": "forced by layout" + }, + { + "object": "VerticalScrollbar", + "reason": "scroll" + }, + { + "object": "HorizontalScrollbar", + "reason": "scroll" + }, + { + "object": "LayoutView #document", + "reason": "scroll" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow H1", + "reason": "became visible" + }, + { + "object": "RootInlineBox", + "reason": "became visible" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/stable/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/stable/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt index 024270b..95b54eb 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/stable/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/stable/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
@@ -7,6 +7,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 785, 836], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [0, 742, 785, 94], "reason": "incremental" @@ -27,6 +32,11 @@ "reason": "layoutObject insertion" }, { + "object": "LayoutBlockFlow HTML", + "rect": [10, 94, 728, 90], + "reason": "forced by layout" + }, + { "object": "LayoutImage IMG", "rect": [58, 236, 489, 537], "reason": "bounds change" @@ -45,6 +55,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutIFrame IFRAME id='iframe'", "reason": "layoutObject insertion" }, @@ -78,7 +92,7 @@ }, { "object": "LayoutBlockFlow HTML", - "reason": "location change" + "reason": "forced by layout" }, { "object": "LayoutBlockFlow BODY",
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/paint/invalidation/resize-iframe-text-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/paint/invalidation/resize-iframe-text-expected.txt new file mode 100644 index 0000000..f2b69df4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/paint/invalidation/resize-iframe-text-expected.txt
@@ -0,0 +1,90 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 681], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutIFrame (positioned) IFRAME", + "rect": [0, 0, 800, 681], + "reason": "forced by layout" + }, + { + "object": "LayoutView #document", + "rect": [0, 600, 800, 81], + "reason": "incremental" + }, + { + "object": "LayoutView #document", + "rect": [0, 600, 785, 81], + "reason": "incremental" + }, + { + "object": "LayoutBlockFlow BODY", + "rect": [8, 8, 784, 18], + "reason": "forced by layout" + }, + { + "object": "LayoutText #text", + "rect": [8, 8, 346, 18], + "reason": "forced by layout" + }, + { + "object": "LayoutView #document", + "rect": [785, 0, 15, 681], + "reason": "scroll" + }, + { + "object": "LayoutView #document", + "rect": [785, 0, 15, 600], + "reason": "scroll" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutView #document", + "reason": "incremental" + }, + { + "object": "LayoutBlockFlow BODY", + "reason": "forced by layout" + }, + { + "object": "RootInlineBox", + "reason": "forced by layout" + }, + { + "object": "LayoutText #text", + "reason": "forced by layout" + }, + { + "object": "InlineTextBox 'Test passes if you see \"Success\" after window resizes.'", + "reason": "forced by layout" + }, + { + "object": "LayoutIFrame (positioned) IFRAME", + "reason": "forced by layout" + }, + { + "object": "HorizontalScrollbar", + "reason": "scroll" + }, + { + "object": "LayoutView #document", + "reason": "scroll" + }, + { + "object": "VerticalScrollbar", + "reason": "scroll" + }, + { + "object": "LayoutView #document", + "reason": "incremental" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/stable/paint/invalidation/resize-iframe-text-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/stable/paint/invalidation/resize-iframe-text-expected.txt new file mode 100644 index 0000000..f2b69df4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/stable/paint/invalidation/resize-iframe-text-expected.txt
@@ -0,0 +1,90 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 681], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutIFrame (positioned) IFRAME", + "rect": [0, 0, 800, 681], + "reason": "forced by layout" + }, + { + "object": "LayoutView #document", + "rect": [0, 600, 800, 81], + "reason": "incremental" + }, + { + "object": "LayoutView #document", + "rect": [0, 600, 785, 81], + "reason": "incremental" + }, + { + "object": "LayoutBlockFlow BODY", + "rect": [8, 8, 784, 18], + "reason": "forced by layout" + }, + { + "object": "LayoutText #text", + "rect": [8, 8, 346, 18], + "reason": "forced by layout" + }, + { + "object": "LayoutView #document", + "rect": [785, 0, 15, 681], + "reason": "scroll" + }, + { + "object": "LayoutView #document", + "rect": [785, 0, 15, 600], + "reason": "scroll" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutView #document", + "reason": "incremental" + }, + { + "object": "LayoutBlockFlow BODY", + "reason": "forced by layout" + }, + { + "object": "RootInlineBox", + "reason": "forced by layout" + }, + { + "object": "LayoutText #text", + "reason": "forced by layout" + }, + { + "object": "InlineTextBox 'Test passes if you see \"Success\" after window resizes.'", + "reason": "forced by layout" + }, + { + "object": "LayoutIFrame (positioned) IFRAME", + "reason": "forced by layout" + }, + { + "object": "HorizontalScrollbar", + "reason": "scroll" + }, + { + "object": "LayoutView #document", + "reason": "scroll" + }, + { + "object": "VerticalScrollbar", + "reason": "scroll" + }, + { + "object": "LayoutView #document", + "reason": "incremental" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/resize-iframe-text-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/resize-iframe-text-expected.txt index b35b467f..9039a5b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/resize-iframe-text-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/resize-iframe-text-expected.txt
@@ -17,6 +17,16 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 34], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 785, 677], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [0, 600, 785, 77], "reason": "incremental" @@ -50,6 +60,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "reason": "forced by layout" }, @@ -84,6 +98,10 @@ { "object": "LayoutView #document", "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/paint/invalidation/resize-iframe-text-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/paint/invalidation/resize-iframe-text-expected.txt index 366ac00f6..a96960b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/paint/invalidation/resize-iframe-text-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac-retina/paint/invalidation/resize-iframe-text-expected.txt
@@ -12,11 +12,21 @@ "reason": "forced by layout" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 759], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [0, 600, 800, 200], "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 34], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "rect": [8, 8, 784, 18], "reason": "forced by layout" @@ -45,6 +55,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "reason": "forced by layout" }, @@ -77,6 +91,10 @@ "reason": "scroll" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow H1", "reason": "became visible" },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/abspos-shift-image-incorrect-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/abspos-shift-image-incorrect-repaint-expected.txt index a4956893..1b5d71a 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/abspos-shift-image-incorrect-repaint-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/abspos-shift-image-incorrect-repaint-expected.txt
@@ -17,6 +17,11 @@ "reason": "bounds change" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 52], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow (relative positioned) DIV class='imageWrapper'", "rect": [704, 0, 700, 236], "reason": "bounds change" @@ -80,6 +85,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow (positioned) DIV id='shiftMe'", "reason": "bounds change" },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt index 53fdc643..55cf8f2 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
@@ -30,6 +30,16 @@ "reason": "style change" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 500, 300, 34], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 500, 285, 150], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "rect": [8, 508, 284, 18], "reason": "forced by layout" @@ -66,6 +76,10 @@ "reason": "style change" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "reason": "forced by layout" },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/line-flow-with-floats-9-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/line-flow-with-floats-9-expected.txt index f5e66e64..578a9781 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/line-flow-with-floats-9-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/line-flow-with-floats-9-expected.txt
@@ -7,6 +7,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 500, 600], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow P", "rect": [8, 569, 418, 21], "reason": "incremental" @@ -118,6 +123,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow P", "reason": "incremental" },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/resize-iframe-text-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/resize-iframe-text-expected.txt index f2b69df4..0feedc7a 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/resize-iframe-text-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/resize-iframe-text-expected.txt
@@ -17,6 +17,16 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 34], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 785, 681], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [0, 600, 785, 81], "reason": "incremental" @@ -50,6 +60,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "reason": "forced by layout" }, @@ -84,6 +98,10 @@ { "object": "LayoutView #document", "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table-shrink-row-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table-shrink-row-repaint-expected.txt index d380b3e3..b34869d 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table-shrink-row-repaint-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table-shrink-row-repaint-expected.txt
@@ -7,6 +7,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 785, 1048], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [0, 848, 785, 200], "reason": "incremental" @@ -265,6 +270,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutTableCell TD id='resizeMe'", "reason": "incremental" },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/text-match-document-change-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/text-match-document-change-expected.txt index cb161c6..8104edb 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/text-match-document-change-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/text-match-document-change-expected.txt
@@ -7,6 +7,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [10, 102, 285, 400], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow DIV id='to-be-changed'", "rect": [18, 128, 269, 36], "reason": "full" @@ -39,6 +44,10 @@ "reason": "scroll" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow DIV id='to-be-changed'", "reason": "full" },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/window-resize-vertical-writing-mode-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/window-resize-vertical-writing-mode-expected.txt index 244c8ab..6b212b3 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/window-resize-vertical-writing-mode-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
@@ -7,6 +7,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 913, 235], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [0, 0, 913, 235], "reason": "bounds change" @@ -37,6 +42,11 @@ "reason": "scroll" }, { + "object": "LayoutBlockFlow HTML", + "rect": [483, 0, 430, 500], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "rect": [491, 8, 414, 484], "reason": "forced by layout" @@ -59,6 +69,10 @@ "reason": "bounds change" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "reason": "forced by layout" }, @@ -269,6 +283,11 @@ "reason": "full" }, { + "object": "LayoutBlockFlow HTML", + "rect": [-513, 0, 913, 235], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [-513, 0, 913, 235], "reason": "bounds change" @@ -294,6 +313,11 @@ "reason": "scroll" }, { + "object": "LayoutBlockFlow HTML", + "rect": [39, 0, 361, 600], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "rect": [47, 8, 345, 584], "reason": "forced by layout" @@ -316,6 +340,10 @@ "reason": "bounds change" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "reason": "forced by layout" }, @@ -363,6 +391,16 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "rect": [439, 0, 361, 600], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [39, 0, 361, 600], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "rect": [447, 8, 345, 584], "reason": "forced by layout" @@ -391,6 +429,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "reason": "forced by layout" },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/paint/invalidation/resize-iframe-text-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/paint/invalidation/resize-iframe-text-expected.txt new file mode 100644 index 0000000..0feedc7a --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/paint/invalidation/resize-iframe-text-expected.txt
@@ -0,0 +1,108 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 681], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutIFrame (positioned) IFRAME", + "rect": [0, 0, 800, 681], + "reason": "forced by layout" + }, + { + "object": "LayoutView #document", + "rect": [0, 600, 800, 81], + "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 34], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 785, 681], + "reason": "forced by layout" + }, + { + "object": "LayoutView #document", + "rect": [0, 600, 785, 81], + "reason": "incremental" + }, + { + "object": "LayoutBlockFlow BODY", + "rect": [8, 8, 784, 18], + "reason": "forced by layout" + }, + { + "object": "LayoutText #text", + "rect": [8, 8, 346, 18], + "reason": "forced by layout" + }, + { + "object": "LayoutView #document", + "rect": [785, 0, 15, 681], + "reason": "scroll" + }, + { + "object": "LayoutView #document", + "rect": [785, 0, 15, 600], + "reason": "scroll" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutView #document", + "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow BODY", + "reason": "forced by layout" + }, + { + "object": "RootInlineBox", + "reason": "forced by layout" + }, + { + "object": "LayoutText #text", + "reason": "forced by layout" + }, + { + "object": "InlineTextBox 'Test passes if you see \"Success\" after window resizes.'", + "reason": "forced by layout" + }, + { + "object": "LayoutIFrame (positioned) IFRAME", + "reason": "forced by layout" + }, + { + "object": "HorizontalScrollbar", + "reason": "scroll" + }, + { + "object": "LayoutView #document", + "reason": "scroll" + }, + { + "object": "VerticalScrollbar", + "reason": "scroll" + }, + { + "object": "LayoutView #document", + "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/abspos-shift-image-incorrect-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/abspos-shift-image-incorrect-repaint-expected.txt index 0666d0f..044c8161 100644 --- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/abspos-shift-image-incorrect-repaint-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/abspos-shift-image-incorrect-repaint-expected.txt
@@ -17,6 +17,11 @@ "reason": "bounds change" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 52], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow (relative positioned) DIV class='imageWrapper'", "rect": [704, 0, 700, 236], "reason": "bounds change" @@ -80,6 +85,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow (positioned) DIV id='shiftMe'", "reason": "bounds change" },
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt index c38994e..66790ed 100644 --- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
@@ -30,6 +30,16 @@ "reason": "style change" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 500, 300, 34], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 500, 285, 150], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "rect": [8, 508, 284, 18], "reason": "forced by layout" @@ -66,6 +76,10 @@ "reason": "style change" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "reason": "forced by layout" },
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/line-flow-with-floats-9-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/line-flow-with-floats-9-expected.txt index 8a56550..23255e98 100644 --- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/line-flow-with-floats-9-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/line-flow-with-floats-9-expected.txt
@@ -7,6 +7,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 500, 600], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow P", "rect": [8, 569, 418, 21], "reason": "incremental" @@ -118,6 +123,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow P", "reason": "incremental" },
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/resize-iframe-text-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/resize-iframe-text-expected.txt index 542eb4c..f3fbb352 100644 --- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/resize-iframe-text-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/resize-iframe-text-expected.txt
@@ -17,6 +17,16 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 34], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 785, 728], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [0, 600, 785, 128], "reason": "incremental" @@ -55,6 +65,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "reason": "forced by layout" }, @@ -91,6 +105,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow H1", "reason": "became visible" },
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table-shrink-row-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table-shrink-row-repaint-expected.txt index a3198cc8..ee597de 100644 --- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table-shrink-row-repaint-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table-shrink-row-repaint-expected.txt
@@ -7,6 +7,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 785, 1048], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [0, 848, 785, 200], "reason": "incremental" @@ -265,6 +270,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutTableCell TD id='resizeMe'", "reason": "incremental" },
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/text-match-document-change-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/text-match-document-change-expected.txt index ff00f33..21bba70 100644 --- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/text-match-document-change-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/text-match-document-change-expected.txt
@@ -7,6 +7,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [10, 102, 285, 400], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow DIV id='to-be-changed'", "rect": [18, 128, 269, 36], "reason": "full" @@ -39,6 +44,10 @@ "reason": "scroll" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow DIV id='to-be-changed'", "reason": "full" },
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/window-resize-vertical-writing-mode-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/window-resize-vertical-writing-mode-expected.txt index 3be2d60..24b1d65 100644 --- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/window-resize-vertical-writing-mode-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
@@ -7,6 +7,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 913, 235], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [0, 0, 913, 235], "reason": "bounds change" @@ -37,6 +42,11 @@ "reason": "scroll" }, { + "object": "LayoutBlockFlow HTML", + "rect": [483, 0, 430, 500], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "rect": [491, 8, 414, 484], "reason": "forced by layout" @@ -59,6 +69,10 @@ "reason": "bounds change" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "reason": "forced by layout" }, @@ -269,6 +283,11 @@ "reason": "full" }, { + "object": "LayoutBlockFlow HTML", + "rect": [-513, 0, 913, 235], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [-513, 0, 913, 235], "reason": "bounds change" @@ -294,6 +313,11 @@ "reason": "scroll" }, { + "object": "LayoutBlockFlow HTML", + "rect": [39, 0, 361, 600], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "rect": [47, 8, 345, 584], "reason": "forced by layout" @@ -316,6 +340,10 @@ "reason": "bounds change" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "reason": "forced by layout" }, @@ -363,6 +391,16 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "rect": [439, 0, 361, 600], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [39, 0, 361, 600], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "rect": [447, 8, 345, 584], "reason": "forced by layout" @@ -391,6 +429,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "reason": "forced by layout" },
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/paint/invalidation/resize-iframe-text-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/paint/invalidation/resize-iframe-text-expected.txt new file mode 100644 index 0000000..f3fbb352 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/paint/invalidation/resize-iframe-text-expected.txt
@@ -0,0 +1,121 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 728], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutIFrame (positioned) IFRAME", + "rect": [0, 0, 800, 728], + "reason": "forced by layout" + }, + { + "object": "LayoutView #document", + "rect": [0, 600, 800, 128], + "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 34], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 785, 728], + "reason": "forced by layout" + }, + { + "object": "LayoutView #document", + "rect": [0, 600, 785, 128], + "reason": "incremental" + }, + { + "object": "LayoutBlockFlow BODY", + "rect": [8, 8, 784, 18], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow H1", + "rect": [8, 700, 600, 28], + "reason": "became visible" + }, + { + "object": "LayoutText #text", + "rect": [8, 8, 346, 17], + "reason": "forced by layout" + }, + { + "object": "LayoutView #document", + "rect": [785, 0, 15, 728], + "reason": "scroll" + }, + { + "object": "LayoutView #document", + "rect": [785, 0, 15, 600], + "reason": "scroll" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutView #document", + "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow BODY", + "reason": "forced by layout" + }, + { + "object": "RootInlineBox", + "reason": "forced by layout" + }, + { + "object": "LayoutText #text", + "reason": "forced by layout" + }, + { + "object": "InlineTextBox 'Test passes if you see \"Success\" after window resizes.'", + "reason": "forced by layout" + }, + { + "object": "LayoutIFrame (positioned) IFRAME", + "reason": "forced by layout" + }, + { + "object": "HorizontalScrollbar", + "reason": "scroll" + }, + { + "object": "LayoutView #document", + "reason": "scroll" + }, + { + "object": "VerticalScrollbar", + "reason": "scroll" + }, + { + "object": "LayoutView #document", + "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow H1", + "reason": "became visible" + }, + { + "object": "RootInlineBox", + "reason": "became visible" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt index a88792e..504d969f 100644 --- a/third_party/WebKit/LayoutTests/virtual/stable/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/stable/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
@@ -7,6 +7,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 785, 829], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [0, 735, 785, 94], "reason": "incremental" @@ -27,6 +32,11 @@ "reason": "layoutObject insertion" }, { + "object": "LayoutBlockFlow HTML", + "rect": [10, 88, 728, 90], + "reason": "forced by layout" + }, + { "object": "LayoutImage IMG", "rect": [58, 230, 489, 537], "reason": "bounds change" @@ -45,6 +55,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutIFrame IFRAME id='iframe'", "reason": "layoutObject insertion" }, @@ -78,7 +92,7 @@ }, { "object": "LayoutBlockFlow HTML", - "reason": "location change" + "reason": "forced by layout" }, { "object": "LayoutBlockFlow BODY",
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/paint/invalidation/window-resize-percent-html-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/paint/invalidation/window-resize-percent-html-expected.txt index 5513527..141cf54 100644 --- a/third_party/WebKit/LayoutTests/virtual/stable/paint/invalidation/window-resize-percent-html-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/stable/paint/invalidation/window-resize-percent-html-expected.txt
@@ -12,6 +12,11 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 600, 250], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow DIV", "rect": [0, 62, 300, 63], "reason": "incremental" @@ -25,6 +30,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow DIV", "reason": "incremental" } @@ -39,6 +48,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 600, 125], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [400, 0, 200, 250], "reason": "incremental" @@ -57,6 +71,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow DIV", "reason": "incremental" } @@ -76,6 +94,11 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 400, 300], + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow DIV", "rect": [0, 62, 200, 88], "reason": "incremental" @@ -89,6 +112,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow DIV", "reason": "incremental" } @@ -103,6 +130,11 @@ "drawsContent": true, "paintInvalidations": [ { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 300], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", "rect": [400, 0, 400, 600], "reason": "incremental" @@ -121,6 +153,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow DIV", "reason": "incremental" }
diff --git a/third_party/WebKit/Source/bindings/templates/interface_base.cpp.tmpl b/third_party/WebKit/Source/bindings/templates/interface_base.cpp.tmpl index bbea073..d32da99 100644 --- a/third_party/WebKit/Source/bindings/templates/interface_base.cpp.tmpl +++ b/third_party/WebKit/Source/bindings/templates/interface_base.cpp.tmpl
@@ -283,7 +283,7 @@ void crossOriginNamedEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) { Vector<String> names; for (const auto& attribute : kCrossOriginAttributeTable) - names.append(attribute.name); + names.push_back(attribute.name); v8SetReturnValue( info,
diff --git a/third_party/WebKit/Source/bindings/templates/methods.cpp.tmpl b/third_party/WebKit/Source/bindings/templates/methods.cpp.tmpl index d7009da8..a0a4779 100644 --- a/third_party/WebKit/Source/bindings/templates/methods.cpp.tmpl +++ b/third_party/WebKit/Source/bindings/templates/methods.cpp.tmpl
@@ -188,7 +188,7 @@ {{throw_argument_error(method, argument, "parameter %(index)d is not of type '%(type)s'.")}} return; } - {{argument.name}}.append(V8{{argument.idl_type}}::toImpl(v8::Local<v8::Object>::Cast(info[i]))); + {{argument.name}}.push_back(V8{{argument.idl_type}}::toImpl(v8::Local<v8::Object>::Cast(info[i]))); } {% elif argument.is_dictionary %} {% if not argument.use_permissive_dictionary_conversion %}
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceCheckSecurity.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceCheckSecurity.cpp index a17fe42c2..da7325d 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceCheckSecurity.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceCheckSecurity.cpp
@@ -437,7 +437,7 @@ void crossOriginNamedEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) { Vector<String> names; for (const auto& attribute : kCrossOriginAttributeTable) - names.append(attribute.name); + names.push_back(attribute.name); v8SetReturnValue( info,
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp index d482b46..af019af 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp
@@ -7869,7 +7869,7 @@ return; } - variadicTestInterfaceEmptyArgs.append(V8TestInterfaceEmpty::toImpl(v8::Local<v8::Object>::Cast(info[i]))); + variadicTestInterfaceEmptyArgs.push_back(V8TestInterfaceEmpty::toImpl(v8::Local<v8::Object>::Cast(info[i]))); } impl->voidMethodVariadicTestInterfaceEmptyArg(variadicTestInterfaceEmptyArgs); @@ -7904,7 +7904,7 @@ return; } - variadicTestInterfaceEmptyArgs.append(V8TestInterfaceEmpty::toImpl(v8::Local<v8::Object>::Cast(info[i]))); + variadicTestInterfaceEmptyArgs.push_back(V8TestInterfaceEmpty::toImpl(v8::Local<v8::Object>::Cast(info[i]))); } impl->voidMethodTestInterfaceEmptyArgVariadicTestInterfaceEmptyArg(testInterfaceEmptyArg, variadicTestInterfaceEmptyArgs); @@ -7926,7 +7926,7 @@ return; } - variadicTestInterfaceGarbageCollectedArg.append(V8TestInterfaceGarbageCollected::toImpl(v8::Local<v8::Object>::Cast(info[i]))); + variadicTestInterfaceGarbageCollectedArg.push_back(V8TestInterfaceGarbageCollected::toImpl(v8::Local<v8::Object>::Cast(info[i]))); } impl->voidMethodVariadicTestInterfaceGarbageCollectedArg(variadicTestInterfaceGarbageCollectedArg); @@ -10575,7 +10575,7 @@ return; } - testInterfaceEmptyArg.append(V8TestInterfaceEmpty::toImpl(v8::Local<v8::Object>::Cast(info[i]))); + testInterfaceEmptyArg.push_back(V8TestInterfaceEmpty::toImpl(v8::Local<v8::Object>::Cast(info[i]))); } impl->legacyInterfaceTypeCheckingVoidMethodTestInterfaceEmptyVariadicArg(testInterfaceEmptyArg);
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp index caf5618..600af2f1 100644 --- a/third_party/WebKit/Source/core/dom/Node.cpp +++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -109,6 +109,24 @@ namespace blink { +namespace { + +// TODO(crbug.com/545926): Unsafe hack to avoid triggering the +// ThreadRestrictionVerifier on StringImpl. This should be fixed completely, and +// we should always avoid accessing these strings from the impl thread. +// Currently code that calls into this method from the impl thread tries to make +// sure that the main thread is not running at this time. +void appendUnsafe(StringBuilder& builder, const String& offThreadString) { + StringImpl* impl = offThreadString.impl(); + if (impl) { + builder.append(impl->is8Bit() + ? StringView(impl->characters8(), impl->length()) + : StringView(impl->characters16(), impl->length())); + } +} + +} // namespace + using namespace HTMLNames; struct SameSizeAsNode : EventTarget { @@ -1488,12 +1506,12 @@ String Node::debugName() const { StringBuilder name; - name.append(debugNodeName()); + appendUnsafe(name, debugNodeName()); if (isElementNode()) { const Element& thisElement = toElement(*this); if (thisElement.hasID()) { name.append(" id=\'"); - name.append(thisElement.getIdAttribute()); + appendUnsafe(name, thisElement.getIdAttribute()); name.append('\''); } @@ -1502,7 +1520,7 @@ for (size_t i = 0; i < thisElement.classNames().size(); ++i) { if (i > 0) name.append(' '); - name.append(thisElement.classNames()[i]); + appendUnsafe(name, thisElement.classNames()[i]); } name.append('\''); }
diff --git a/third_party/WebKit/Source/core/layout/LayoutView.cpp b/third_party/WebKit/Source/core/layout/LayoutView.cpp index 58d135e..a5f630b1 100644 --- a/third_party/WebKit/Source/core/layout/LayoutView.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutView.cpp
@@ -247,6 +247,8 @@ SubtreeLayoutScope layoutScope(*this); + LayoutRect oldLayoutOverflowRect = layoutOverflowRect(); + // Use calcWidth/Height to get the new width/height, since this will take the // full page zoom factor into account. bool relayoutChildren = @@ -281,6 +283,17 @@ layoutContent(); + if (layoutOverflowRect() != oldLayoutOverflowRect) { + // The document element paints the viewport background, so we need to + // invalidate it when layout overflow changes. + // FIXME: Improve viewport background styling/invalidation/painting. + // crbug.com/475115 + if (Element* documentElement = document().documentElement()) { + if (LayoutObject* rootObject = documentElement->layoutObject()) + rootObject->setShouldDoFullPaintInvalidation(); + } + } + #if ENABLE(ASSERT) checkLayoutState(); #endif
diff --git a/third_party/WebKit/Source/core/paint/BoxPaintInvalidatorTest.cpp b/third_party/WebKit/Source/core/paint/BoxPaintInvalidatorTest.cpp index 975a31a4..d4f4992 100644 --- a/third_party/WebKit/Source/core/paint/BoxPaintInvalidatorTest.cpp +++ b/third_party/WebKit/Source/core/paint/BoxPaintInvalidatorTest.cpp
@@ -238,14 +238,22 @@ // is clipped. // TODO(skobes): Treat LayoutView in the same way as normal objects having // background-attachment: local. crbug.com/568847. - EXPECT_FALSE(layoutView() - .layer() - ->graphicsLayerBacking() - ->getRasterInvalidationTracking()); + // TODO(wangxianzhu): Temporary for crbug.com/680745. + // EXPECT_FALSE(layoutView() + // .layer() + // ->graphicsLayerBacking() + // ->getRasterInvalidationTracking()); + EXPECT_EQ(1u, layoutView() + .layer() + ->graphicsLayerBacking() + ->getRasterInvalidationTracking() + ->trackedRasterInvalidations.size()); } else { const auto& rasterInvalidations = getRasterInvalidationTracking()->trackedRasterInvalidations; - ASSERT_EQ(1u, rasterInvalidations.size()); + // TODO(wangxianzhu): Temporary for crbug.com/680745. + // ASSERT_EQ(1u, rasterInvalidations.size()); + ASSERT_EQ(2u, rasterInvalidations.size()); EXPECT_EQ(IntRect(0, 2000, 800, 1000), rasterInvalidations[0].rect); EXPECT_EQ(static_cast<const DisplayItemClient*>(&layoutView()), rasterInvalidations[0].client); @@ -292,7 +300,9 @@ } else { const auto& rasterInvalidations = getRasterInvalidationTracking()->trackedRasterInvalidations; - ASSERT_EQ(1u, rasterInvalidations.size()); + // TODO(wangxianzhu): Temporary for crbug.com/680745. + // ASSERT_EQ(1u, rasterInvalidations.size()); + ASSERT_EQ(2u, rasterInvalidations.size()); EXPECT_EQ(IntRect(0, 0, 800, 3000), rasterInvalidations[0].rect); EXPECT_EQ(static_cast<const DisplayItemClient*>(&layoutView()), rasterInvalidations[0].client); @@ -333,7 +343,10 @@ content->setAttribute(HTMLNames::styleAttr, "height: 500px"); document().view()->updateAllLifecyclePhases(); // No invalidation because the changed part of layout overflow is clipped. - EXPECT_FALSE(getRasterInvalidationTracking()); + // TODO(wangxianzhu): Temporary for crbug.com/680745. + // EXPECT_FALSE(getRasterInvalidationTracking()); + EXPECT_EQ(1u, + getRasterInvalidationTracking()->trackedRasterInvalidations.size()); document().view()->setTracksPaintInvalidations(false); // Resize the iframe. @@ -392,7 +405,9 @@ document().view()->updateAllLifecyclePhases(); const auto* rasterInvalidations = &getRasterInvalidationTracking()->trackedRasterInvalidations; - ASSERT_EQ(1u, rasterInvalidations->size()); + // TODO(wangxianzhu): Temporary for crbug.com/680745. + // ASSERT_EQ(1u, rasterInvalidations->size()); + ASSERT_EQ(2u, rasterInvalidations->size()); EXPECT_EQ(IntRect(0, 0, 100, 100), (*rasterInvalidations)[0].rect); EXPECT_EQ(static_cast<const DisplayItemClient*>(frameLayoutView), (*rasterInvalidations)[0].client);
diff --git a/third_party/WebKit/Source/devtools/front_end/components/JavaScriptAutocomplete.js b/third_party/WebKit/Source/devtools/front_end/components/JavaScriptAutocomplete.js index 0314ec0..b9aad4f 100644 --- a/third_party/WebKit/Source/devtools/front_end/components/JavaScriptAutocomplete.js +++ b/third_party/WebKit/Source/devtools/front_end/components/JavaScriptAutocomplete.js
@@ -15,13 +15,18 @@ */ Components.JavaScriptAutocomplete.completionsForTextInCurrentContext = function(text, query, force) { var index; - var stopChars = new Set(' =:({;,!+-*/&|^<>`'.split('')); + var stopChars = new Set('=:({;,!+-*/&|^<>`'.split('')); + var whiteSpaceChars = new Set(' \r\n\t'.split('')); + var continueChars = new Set('[. \r\n\t'.split('')); + for (index = text.length - 1; index >= 0; index--) { // Pass less stop characters to rangeOfWord so the range will be a more complete expression. if (stopChars.has(text.charAt(index))) break; + if (whiteSpaceChars.has(text.charAt(index)) && !continueChars.has(text.charAt(index - 1))) + break; } - var clippedExpression = text.substring(index + 1); + var clippedExpression = text.substring(index + 1).trim(); var bracketCount = 0; index = clippedExpression.length - 1; @@ -37,7 +42,7 @@ } index--; } - clippedExpression = clippedExpression.substring(index + 1); + clippedExpression = clippedExpression.substring(index + 1).trim(); return Components.JavaScriptAutocomplete.completionsForExpression(clippedExpression, query, force); }; @@ -56,7 +61,7 @@ var lastIndex = expressionString.length - 1; var dotNotation = (expressionString[lastIndex] === '.'); - var bracketNotation = (expressionString[lastIndex] === '['); + var bracketNotation = (expressionString.length > 1 && expressionString[lastIndex] === '['); if (dotNotation || bracketNotation) expressionString = expressionString.substr(0, lastIndex); @@ -67,9 +72,6 @@ if ((expressionString && !isNaN(expressionString)) || (!expressionString && query && !isNaN(query))) return Promise.resolve([]); - // User is creating an array, do not suggest anything. - if (bracketNotation && !expressionString) - return Promise.resolve([]); if (!query && !expressionString && !force) return Promise.resolve([]);
diff --git a/third_party/WebKit/Source/devtools/front_end/console/ConsolePrompt.js b/third_party/WebKit/Source/devtools/front_end/console/ConsolePrompt.js index 6fab893..c1f8a5ee 100644 --- a/third_party/WebKit/Source/devtools/front_end/console/ConsolePrompt.js +++ b/third_party/WebKit/Source/devtools/front_end/console/ConsolePrompt.js
@@ -244,7 +244,7 @@ var lineText = this._editor.line(lineNumber); var index; for (index = lineText.length - 1; index >= 0; index--) { - if (' =:[({;,!+-*/&|^<>.'.indexOf(lineText.charAt(index)) !== -1) + if (' =:[({;,!+-*/&|^<>.\t\r\n'.indexOf(lineText.charAt(index)) !== -1) break; } return new Common.TextRange(lineNumber, index + 1, lineNumber, columnNumber); @@ -262,9 +262,12 @@ var before = this._editor.text(new Common.TextRange(0, 0, queryRange.startLine, queryRange.startColumn)); var historyWords = this._historyCompletions(query, force); - var excludedTokens = new Set(['js-comment', 'js-string-2']); - if (!before.endsWith('[')) + var excludedTokens = new Set(['js-comment', 'js-string-2', 'js-def']); + var trimmedBefore = before.trim(); + if (!trimmedBefore.endsWith('[')) excludedTokens.add('js-string'); + if (!trimmedBefore.endsWith('.')) + excludedTokens.add('js-property'); if (excludedTokens.has(currentTokenType)) return Promise.resolve(historyWords);
diff --git a/third_party/WebKit/Source/devtools/front_end/quick_open/FilteredListWidget.js b/third_party/WebKit/Source/devtools/front_end/quick_open/FilteredListWidget.js index 5912967..7b9266ec6 100644 --- a/third_party/WebKit/Source/devtools/front_end/quick_open/FilteredListWidget.js +++ b/third_party/WebKit/Source/devtools/front_end/quick_open/FilteredListWidget.js
@@ -271,6 +271,7 @@ this._progressBarElement.style.transform = 'scaleX(0)'; this._progressBarElement.classList.remove('filtered-widget-progress-fade'); + this._progressBarElement.classList.remove('hidden'); var query = this._delegate.rewriteQuery(this._value()); this._query = query; @@ -284,6 +285,7 @@ var bestItemsToCollect = 100; var minBestScore = 0; var overflowItems = []; + var scoreStartTime = window.performance.now(); var maxWorkItems = Number.constrain(10, 500, (this._delegate.itemCount() / 10) | 0); @@ -338,11 +340,16 @@ // Process everything in chunks. if (i < this._delegate.itemCount()) { this._scoringTimer = setTimeout(scoreItems.bind(this, i), 0); - this._progressBarElement.style.transform = 'scaleX(' + i / this._delegate.itemCount() + ')'; + if (window.performance.now() - scoreStartTime > 50) + this._progressBarElement.style.transform = 'scaleX(' + i / this._delegate.itemCount() + ')'; return; } - this._progressBarElement.style.transform = 'scaleX(1)'; - this._progressBarElement.classList.add('filtered-widget-progress-fade'); + if (window.performance.now() - scoreStartTime > 100) { + this._progressBarElement.style.transform = 'scaleX(1)'; + this._progressBarElement.classList.add('filtered-widget-progress-fade'); + } else { + this._progressBarElement.classList.add('hidden'); + } this._refreshListWithCurrentResult(); } }
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/FilteredUISourceCodeListDelegate.js b/third_party/WebKit/Source/devtools/front_end/sources/FilteredUISourceCodeListDelegate.js index 86f9371..8286ee1 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/FilteredUISourceCodeListDelegate.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/FilteredUISourceCodeListDelegate.js
@@ -183,9 +183,9 @@ * @return {string} */ rewriteQuery(query) { - if (!query) - return query; - query = query.trim(); + query = query ? query.trim() : ''; + if (!query || query === ':') + return ''; var lineNumberMatch = query.match(/^([^:]+)((?::[^:]*){0,2})$/); this._queryLineNumberAndColumnNumber = lineNumberMatch ? lineNumberMatch[2] : ''; return lineNumberMatch ? lineNumberMatch[1] : query;
diff --git a/third_party/WebKit/Source/devtools/scripts/chrome_debug_launcher/launch_chrome.js b/third_party/WebKit/Source/devtools/scripts/chrome_debug_launcher/launch_chrome.js index 545c949..426e8906e 100644 --- a/third_party/WebKit/Source/devtools/scripts/chrome_debug_launcher/launch_chrome.js +++ b/third_party/WebKit/Source/devtools/scripts/chrome_debug_launcher/launch_chrome.js
@@ -100,7 +100,7 @@ var child; try { child = childProcess.spawn(filePath, chromeArgs, { - stdio: "ignore", + stdio: "inherit", }); } catch (error) { onLaunchChromeError();
diff --git a/third_party/WebKit/Source/devtools/scripts/compile_frontend.py b/third_party/WebKit/Source/devtools/scripts/compile_frontend.py index be2c35e..5be7930d 100755 --- a/third_party/WebKit/Source/devtools/scripts/compile_frontend.py +++ b/third_party/WebKit/Source/devtools/scripts/compile_frontend.py
@@ -75,6 +75,10 @@ protocol_externs_file = path.join(devtools_frontend_path, 'protocol_externs.js') runtime_file = to_platform_path(path.join(devtools_frontend_path, 'Runtime.js')) +closure_compiler_jar = to_platform_path(path.join(scripts_path, 'closure', 'compiler.jar')) +closure_runner_jar = to_platform_path(path.join(scripts_path, 'closure', 'closure_runner', 'closure_runner.jar')) +jsdoc_validator_jar = to_platform_path(path.join(scripts_path, 'jsdoc_validator', 'jsdoc_validator.jar')) + type_checked_jsdoc_tags_list = ['param', 'return', 'type', 'enum'] type_checked_jsdoc_tags_or = '|'.join(type_checked_jsdoc_tags_list) @@ -116,66 +120,70 @@ return re.search(error_warning_regex, output) != None -def verify_jsdoc_extra(): - files = [to_platform_path(compiled_file) for compiled_file in descriptors.all_compiled_files()] - file_list = tempfile.NamedTemporaryFile(mode='wt', delete=False) - try: - file_list.write('\n'.join(files)) - finally: - file_list.close() - return popen(java_exec + ['-jar', jsdoc_validator_jar, '--files-list-name', to_platform_path_exact(file_list.name)]), file_list +class JSDocChecker: + def __init__(self): + self._error_found = False + self._all_files = descriptors.all_compiled_files() + def check(self): + print 'Verifying JSDoc comments...' + self._verify_jsdoc() + self._run_jsdoc_validator() + return self._error_found -def verify_jsdoc(): - def file_list(): - return descriptors.all_compiled_files() + def _run_jsdoc_validator(self): + files = [to_platform_path(f) for f in self._all_files] + file_list = tempfile.NamedTemporaryFile(mode='wt', delete=False) + try: + file_list.write('\n'.join(files)) + finally: + file_list.close() + proc = popen(java_exec + ['-jar', jsdoc_validator_jar, '--files-list-name', to_platform_path_exact(file_list.name)]) + (out, _) = proc.communicate() + if out: + print ('JSDoc validator output:%s%s' % (os.linesep, out)) + self._error_found = True + os.remove(file_list.name) - errors_found = False - for full_file_name in file_list(): - line_index = 0 - with open(full_file_name, 'r') as sourceFile: - for line in sourceFile: - line = line.rstrip() - line_index += 1 - if not line: - continue - if verify_jsdoc_line(full_file_name, line_index, line): - errors_found = True - return errors_found + def _verify_jsdoc(self): + for full_file_name in self._all_files: + line_index = 0 + with open(full_file_name, 'r') as sourceFile: + for line in sourceFile: + line_index += 1 + if line.rstrip(): + self._verify_jsdoc_line(full_file_name, line_index, line) + def _verify_jsdoc_line(self, file_name, line_index, line): + def print_error(message, error_position): + print '%s:%s: ERROR - %s%s%s%s%s%s' % (file_name, line_index, message, os.linesep, line, os.linesep, ' ' * error_position + '^', os.linesep) -def verify_jsdoc_line(file_name, line_index, line): - def print_error(message, error_position): - print '%s:%s: ERROR - %s%s%s%s%s%s' % (file_name, line_index, message, os.linesep, line, os.linesep, ' ' * error_position + '^', os.linesep) + known_css = {} + match = re.search(invalid_type_regex, line) + if match: + print_error('Type "%s" nullability not marked explicitly with "?" (nullable) or "!" (non-nullable)' % match.group(1), match.start(1)) + self._error_found = True - known_css = {} - errors_found = False - match = re.search(invalid_type_regex, line) - if match: - print_error('Type "%s" nullability not marked explicitly with "?" (nullable) or "!" (non-nullable)' % match.group(1), match.start(1)) - errors_found = True + match = re.search(invalid_non_object_type_regex, line) + if match: + print_error('Non-object type explicitly marked with "!" (non-nullable), which is the default and should be omitted', match.start(1)) + self._error_found = True - match = re.search(invalid_non_object_type_regex, line) - if match: - print_error('Non-object type explicitly marked with "!" (non-nullable), which is the default and should be omitted', match.start(1)) - errors_found = True + match = re.search(invalid_type_designator_regex, line) + if match: + print_error('Type nullability indicator misplaced, should precede type', match.start(1)) + self._error_found = True - match = re.search(invalid_type_designator_regex, line) - if match: - print_error('Type nullability indicator misplaced, should precede type', match.start(1)) - errors_found = True - - match = re.search(loaded_css_regex, line) - if match: - file = path.join(devtools_frontend_path, match.group(1)) - exists = known_css.get(file) - if exists is None: - exists = path.isfile(file) - known_css[file] = exists - if not exists: - print_error('Dynamically loaded CSS stylesheet is missing in the source tree', match.start(1)) - errors_found = True - return errors_found + match = re.search(loaded_css_regex, line) + if match: + file = path.join(devtools_frontend_path, match.group(1)) + exists = known_css.get(file) + if exists is None: + exists = path.isfile(file) + known_css[file] = exists + if not exists: + print_error('Dynamically loaded CSS stylesheet is missing in the source tree', match.start(1)) + self._error_found = True def find_java(): @@ -214,10 +222,6 @@ java_exec = find_java() -closure_compiler_jar = to_platform_path(path.join(scripts_path, 'closure', 'compiler.jar')) -closure_runner_jar = to_platform_path(path.join(scripts_path, 'closure', 'closure_runner', 'closure_runner.jar')) -jsdoc_validator_jar = to_platform_path(path.join(scripts_path, 'jsdoc_validator', 'jsdoc_validator.jar')) - common_closure_args = [ '--summary_detail_level', '3', '--jscomp_error', 'visibility', @@ -231,20 +235,6 @@ '--checks-only', ] -worker_modules_by_name = {} -dependents_by_module_name = {} - -for module_name in descriptors.application: - module = descriptors.modules[module_name] - if descriptors.application[module_name].get('type', None) == 'worker': - worker_modules_by_name[module_name] = module - for dep in module.get('dependencies', []): - list = dependents_by_module_name.get(dep) - if not list: - list = [] - dependents_by_module_name[dep] = list - list.append(module_name) - def check_conditional_dependencies(): errors_found = False @@ -258,39 +248,6 @@ errors_found |= check_conditional_dependencies() - -def verify_worker_modules(): - errors_found = False - for name in modules_by_name: - for dependency in modules_by_name[name].get('dependencies', []): - if dependency in worker_modules_by_name: - log_error('Module "%s" may not depend on the worker module "%s"' % (name, dependency)) - errors_found = True - return errors_found - -errors_found |= verify_worker_modules() - - -def check_duplicate_files(): - - def check_module(module, seen_files, seen_modules): - name = module['name'] - seen_modules[name] = True - for dep_name in module.get('dependencies', []): - if not dep_name in seen_modules: - check_module(modules_by_name[dep_name], seen_files, seen_modules) - for source in module.get('scripts', []): - referencing_module = seen_files.get(source) - if referencing_module: - log_error('Duplicate use of %s in "%s" (previously seen in "%s")' % (source, name, referencing_module)) - seen_files[source] = name - - for module_name in worker_modules_by_name: - check_module(worker_modules_by_name[module_name], {}, {}) - -print 'Checking duplicate files across modules...' -check_duplicate_files() - print 'Compiling frontend...' temp_devtools_path = tempfile.mkdtemp() @@ -339,18 +296,7 @@ ] devtools_js_compile_proc = popen(devtools_js_compile_command) -print 'Verifying JSDoc comments...' -errors_found |= verify_jsdoc() -(jsdoc_validator_proc, jsdoc_validator_file_list) = verify_jsdoc_extra() - -print - -(jsdoc_validator_out, _) = jsdoc_validator_proc.communicate() -if jsdoc_validator_out: - print ('JSDoc validator output:%s%s' % (os.linesep, jsdoc_validator_out)) - errors_found = True - -os.remove(jsdoc_validator_file_list.name) +errors_found |= JSDocChecker().check() (devtools_js_compile_out, _) = devtools_js_compile_proc.communicate() print 'devtools_compatibility.js compilation output:%s' % os.linesep, devtools_js_compile_out
diff --git a/third_party/WebKit/Source/devtools/scripts/npm_test.js b/third_party/WebKit/Source/devtools/scripts/npm_test.js index b493f0c7a..37a93ac 100644 --- a/third_party/WebKit/Source/devtools/scripts/npm_test.js +++ b/third_party/WebKit/Source/devtools/scripts/npm_test.js
@@ -35,8 +35,7 @@ if (!IS_FETCH_CONTENT_SHELL && hasUserCompiledContentShell) { var outDir = path.resolve(RELEASE_PATH, ".."); if (!IS_DEBUG_ENABLED) { - console.log("Compiling devtools frontend"); - shell(`ninja -C ${RELEASE_PATH} devtools_frontend_resources`); + compileFrontend(); } runTests(outDir, IS_DEBUG_ENABLED); return; @@ -55,6 +54,18 @@ } main(); +function compileFrontend() +{ + console.log("Compiling devtools frontend"); + try { + shell(`ninja -C ${RELEASE_PATH} devtools_frontend_resources`); + } catch (err) { + console.log(err.stdout.toString()); + console.log('ERROR: Cannot compile frontend\n' + err); + process.exit(1); + } +} + function onUploadedCommitPosition(commitPosition) { var contentShellDirPath = path.resolve(CACHE_PATH, commitPosition, "out", "Release");
diff --git a/third_party/WebKit/Source/modules/webdatabase/SQLTransactionClient.cpp b/third_party/WebKit/Source/modules/webdatabase/SQLTransactionClient.cpp index 47dbb0ee..3cbac44 100644 --- a/third_party/WebKit/Source/modules/webdatabase/SQLTransactionClient.cpp +++ b/third_party/WebKit/Source/modules/webdatabase/SQLTransactionClient.cpp
@@ -65,16 +65,14 @@ String databaseName = database->stringIdentifier(); ExecutionContext* executionContext = database->getDatabaseContext()->getExecutionContext(); + SecurityOrigin* origin = database->getSecurityOrigin(); if (!executionContext->isContextThread()) { executionContext->postTask( TaskType::DatabaseAccess, BLINK_FROM_HERE, - createCrossThreadTask( - &databaseModifiedCrossThread, - executionContext->getSecurityOrigin()->toRawString(), - databaseName)); + createCrossThreadTask(&databaseModifiedCrossThread, + origin->toRawString(), databaseName)); } else { - databaseModified(WebSecurityOrigin(executionContext->getSecurityOrigin()), - databaseName); + databaseModified(WebSecurityOrigin(origin), databaseName); } }
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp index 7930eae..7ec6b2e 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp +++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -599,7 +599,7 @@ ContextProviderCreationInfo creationInfo; creationInfo.contextAttributes = contextAttributes; creationInfo.glInfo = glInfo; - creationInfo.url = url; + creationInfo.url = url.copy(); RefPtr<WebTaskRunner> taskRunner = Platform::current()->mainThread()->getWebTaskRunner(); taskRunner->postTask(BLINK_FROM_HERE,
diff --git a/third_party/WebKit/Source/wtf/RefCounted.h b/third_party/WebKit/Source/wtf/RefCounted.h index 398db7b..a4847ef 100644 --- a/third_party/WebKit/Source/wtf/RefCounted.h +++ b/third_party/WebKit/Source/wtf/RefCounted.h
@@ -43,7 +43,7 @@ public: void ref() const { #if CHECK_REF_COUNTED_LIFECYCLE - m_verifier.onRef(m_refCount); + SECURITY_DCHECK(m_verifier.onRef(m_refCount)); DCHECK(!m_adoptionIsRequired); #endif SECURITY_DCHECK(!m_deletionHasBegun); @@ -53,14 +53,14 @@ bool hasOneRef() const { SECURITY_DCHECK(!m_deletionHasBegun); #if CHECK_REF_COUNTED_LIFECYCLE - m_verifier.checkSafeToUse(); + SECURITY_DCHECK(m_verifier.isSafeToUse()); #endif return m_refCount == 1; } int refCount() const { #if CHECK_REF_COUNTED_LIFECYCLE - m_verifier.checkSafeToUse(); + SECURITY_DCHECK(m_verifier.isSafeToUse()); #endif return m_refCount; } @@ -90,7 +90,7 @@ bool derefBase() const { SECURITY_DCHECK(!m_deletionHasBegun); #if CHECK_REF_COUNTED_LIFECYCLE - m_verifier.onDeref(m_refCount); + SECURITY_DCHECK(m_verifier.onDeref(m_refCount)); DCHECK(!m_adoptionIsRequired); #endif
diff --git a/third_party/WebKit/Source/wtf/ThreadRestrictionVerifier.h b/third_party/WebKit/Source/wtf/ThreadRestrictionVerifier.h index 15ea5fa..5af787c 100644 --- a/third_party/WebKit/Source/wtf/ThreadRestrictionVerifier.h +++ b/third_party/WebKit/Source/wtf/ThreadRestrictionVerifier.h
@@ -48,14 +48,10 @@ public: ThreadRestrictionVerifier() : m_shared(false), m_owningThread(0) {} - void checkSafeToUse() const { - // If this assert fires, it either indicates a thread safety issue or - // that the verification needs to change. - SECURITY_DCHECK(isSafeToUse()); - } - - // Call onRef() before refCount is incremented in ref(). - void onRef(int refCount) { + // Call onRef() before refCount is incremented in ref(). Returns whether the + // ref() is safe. + template <typename COUNTERTYPE> + bool onRef(COUNTERTYPE refCount) { // Start thread verification as soon as the ref count gets to 2. This // heuristic reflects the fact that items are often created on one // thread and then given to another thread to be used. @@ -66,17 +62,24 @@ // explicit. if (refCount == 1) setShared(true); - checkSafeToUse(); + return isSafeToUse(); } - // Call onDeref() before refCount is decremented in deref(). - void onDeref(int refCount) { - checkSafeToUse(); - + // Call onDeref() before refCount is decremented in deref(). Returns whether + // the deref() is safe. + template <typename COUNTERTYPE> + bool onDeref(COUNTERTYPE refCount) { + bool safe = isSafeToUse(); // Stop thread verification when the ref goes to 1 because it // is safe to be passed to another thread at this point. if (refCount == 2) setShared(false); + return safe; + } + + // Is it OK to use the object at this moment on the current thread? + bool isSafeToUse() const { + return !m_shared || m_owningThread == currentThread(); } private: @@ -94,14 +97,6 @@ m_owningThread = currentThread(); } - // Is it OK to use the object at this moment on the current thread? - bool isSafeToUse() const { - if (!m_shared) - return true; - - return m_owningThread == currentThread(); - } - bool m_shared; ThreadIdentifier m_owningThread;
diff --git a/third_party/WebKit/Source/wtf/text/StringImpl.cpp b/third_party/WebKit/Source/wtf/text/StringImpl.cpp index 641fbc9..f8b6b7b 100644 --- a/third_party/WebKit/Source/wtf/text/StringImpl.cpp +++ b/third_party/WebKit/Source/wtf/text/StringImpl.cpp
@@ -32,6 +32,7 @@ #include "wtf/allocator/Partitions.h" #include "wtf/text/AtomicString.h" #include "wtf/text/AtomicStringTable.h" +#include "wtf/text/CString.h" #include "wtf/text/CharacterNames.h" #include "wtf/text/StringBuffer.h" #include "wtf/text/StringHash.h" @@ -54,8 +55,16 @@ using namespace Unicode; -static_assert(sizeof(StringImpl) == 3 * sizeof(int), +// As of Jan 2017, StringImpl needs 2 * sizeof(int) + 29 bits of data, and +// sizeof(ThreadRestrictionVerifier) is 16 bytes. Thus, in DCHECK mode the +// class may be padded to 32 bytes. +#if DCHECK_IS_ON() +static_assert(sizeof(StringImpl) <= 8 * sizeof(int), "StringImpl should stay small"); +#else +static_assert(sizeof(StringImpl) <= 3 * sizeof(int), + "StringImpl should stay small"); +#endif #ifdef STRING_STATS @@ -300,7 +309,7 @@ AtomicStringTable::instance().remove(this); } -void StringImpl::destroyIfNotStatic() { +void StringImpl::destroyIfNotStatic() const { if (!isStatic()) delete this; } @@ -324,6 +333,13 @@ return false; } +#if DCHECK_IS_ON() +std::string StringImpl::asciiForDebugging() const { + CString ascii = String(substring(0, 128)).ascii(); + return std::string(ascii.data(), ascii.length()); +} +#endif + PassRefPtr<StringImpl> StringImpl::createUninitialized(unsigned length, LChar*& data) { if (!length) { @@ -501,13 +517,16 @@ return true; } -PassRefPtr<StringImpl> StringImpl::substring(unsigned start, unsigned length) { +PassRefPtr<StringImpl> StringImpl::substring(unsigned start, + unsigned length) const { if (start >= m_length) return empty(); unsigned maxLength = m_length - start; if (length >= maxLength) { + // PassRefPtr has trouble dealing with const arguments. It should be updated + // so this const_cast is not necessary. if (!start) - return this; + return const_cast<StringImpl*>(this); length = maxLength; } if (is8Bit())
diff --git a/third_party/WebKit/Source/wtf/text/StringImpl.h b/third_party/WebKit/Source/wtf/text/StringImpl.h index 6288b56..77dfcc3 100644 --- a/third_party/WebKit/Source/wtf/text/StringImpl.h +++ b/third_party/WebKit/Source/wtf/text/StringImpl.h
@@ -35,6 +35,10 @@ #include <limits.h> #include <string.h> +#if DCHECK_IS_ON() +#include "wtf/ThreadRestrictionVerifier.h" +#endif + #if OS(MACOSX) typedef const struct __CFString* CFStringRef; #endif @@ -297,11 +301,25 @@ return hashSlowCase(); } - ALWAYS_INLINE bool hasOneRef() const { return m_refCount == 1; } + ALWAYS_INLINE bool hasOneRef() const { +#if DCHECK_IS_ON() + DCHECK(isStatic() || m_verifier.isSafeToUse()) << asciiForDebugging(); +#endif + return m_refCount == 1; + } - ALWAYS_INLINE void ref() { ++m_refCount; } + ALWAYS_INLINE void ref() const { +#if DCHECK_IS_ON() + DCHECK(isStatic() || m_verifier.onRef(m_refCount)) << asciiForDebugging(); +#endif + ++m_refCount; + } - ALWAYS_INLINE void deref() { + ALWAYS_INLINE void deref() const { +#if DCHECK_IS_ON() + DCHECK(isStatic() || m_verifier.onDeref(m_refCount)) + << asciiForDebugging() << " " << currentThread(); +#endif if (!--m_refCount) destroyIfNotStatic(); } @@ -329,7 +347,7 @@ // its own copy of the string. PassRefPtr<StringImpl> isolatedCopy() const; - PassRefPtr<StringImpl> substring(unsigned pos, unsigned len = UINT_MAX); + PassRefPtr<StringImpl> substring(unsigned pos, unsigned len = UINT_MAX) const; UChar operator[](unsigned i) const { SECURITY_DCHECK(i < m_length); @@ -487,9 +505,13 @@ StripBehavior); NEVER_INLINE unsigned hashSlowCase() const; - void destroyIfNotStatic(); + void destroyIfNotStatic() const; void updateContainsOnlyASCII() const; +#if DCHECK_IS_ON() + std::string asciiForDebugging() const; +#endif + #ifdef STRING_STATS static StringStats m_stringStats; #endif @@ -505,7 +527,10 @@ #endif private: - unsigned m_refCount; +#if DCHECK_IS_ON() + mutable ThreadRestrictionVerifier m_verifier; +#endif + mutable unsigned m_refCount; const unsigned m_length; mutable unsigned m_hash : 24; mutable unsigned m_containsOnlyASCII : 1;
diff --git a/third_party/WebKit/Source/wtf/text/StringImplTest.cpp b/third_party/WebKit/Source/wtf/text/StringImplTest.cpp index 7dab3d9..9843a07 100644 --- a/third_party/WebKit/Source/wtf/text/StringImplTest.cpp +++ b/third_party/WebKit/Source/wtf/text/StringImplTest.cpp
@@ -89,6 +89,9 @@ static const UChar testWithNonASCIICapitalized[3] = {0x0041, 0x00e1, 0}; // A\xE1 + // Make sure we support RefPtr<const StringImpl>. + RefPtr<const StringImpl> constRef = testStringImpl->isolatedCopy(); + DCHECK(constRef->hasOneRef()); EXPECT_TRUE(equal( StringImpl::create(testWithNonASCII, 2).get(), StringImpl::create(testWithNonASCIICapitalized, 2)->lowerASCII().get()));
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py index 298125a7..34998b1 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py
@@ -506,14 +506,8 @@ @staticmethod def _android_server_process_constructor(port, server_name, cmd_line, env=None, more_logging=False): - # We need universal_newlines=True, because 'adb shell' for some unknown reason - # does newline conversion of unix-style LF into win-style CRLF (and we need - # to convert that back). This can cause headaches elsewhere because - # server_process' stdout and stderr are now unicode file-like objects, - # not binary file-like objects like all of the other ports are. - # FIXME: crbug.com/496983. return server_process.ServerProcess(port, server_name, cmd_line, env, - universal_newlines=True, treat_no_data_as_crash=True, more_logging=more_logging) + treat_no_data_as_crash=True, more_logging=more_logging) class AndroidPerf(SingleFileOutputProfiler): @@ -881,14 +875,8 @@ self._device.serial, stack) - # The parent method expects stdout and stderr to be byte streams, but - # since adb shell does newline conversion, we used universal_newlines - # when launching the processes, and hence our stdout and stderr are - # text objects that need to be encoded back into bytes. return super(ChromiumAndroidDriver, self)._get_crash_log( - stdout.encode('utf8', 'replace'), - stderr.encode('utf8', 'replace'), - newer_than) + stdout, stderr, newer_than) def cmd_line(self, pixel_tests, per_test_args): # The returned command line is used to start _server_process. In our case, it's an interactive 'adb shell'.
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py index 7f0bed8..52d4064 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
@@ -1465,12 +1465,12 @@ # We require stdout and stderr to be bytestrings, not character strings. if stdout: - assert isinstance(stdout, str) + assert isinstance(stdout, basestring) stdout_lines = stdout.decode('utf8', 'replace').splitlines() else: stdout_lines = [u'<empty>'] if stderr: - assert isinstance(stderr, str) + assert isinstance(stderr, basestring) stderr_lines = stderr.decode('utf8', 'replace').splitlines() else: stderr_lines = [u'<empty>']
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/server_process.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/server_process.py index a582ebe..6795b35d 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/server_process.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/server_process.py
@@ -79,15 +79,12 @@ as necessary to keep issuing commands. """ - def __init__(self, port_obj, name, cmd, env=None, universal_newlines=False, treat_no_data_as_crash=False, + def __init__(self, port_obj, name, cmd, env=None, treat_no_data_as_crash=False, more_logging=False): self._port = port_obj self._name = name # Should be the command name (e.g. content_shell, image_diff) self._cmd = cmd self._env = env - # Set if the process outputs non-standard newlines like '\r\n' or '\r'. - # Don't set if there will be binary data or the data must be ASCII encoded. - self._universal_newlines = universal_newlines self._treat_no_data_as_crash = treat_no_data_as_crash self._logging = more_logging self._host = self._port.host @@ -140,8 +137,7 @@ stdout=self._host.executive.PIPE, stderr=self._host.executive.PIPE, close_fds=close_fds, - env=self._env, - universal_newlines=self._universal_newlines) + env=self._env) self._pid = self._proc.pid fd = self._proc.stdout.fileno() if not self._use_win32_apis:
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/server_process_mock.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/server_process_mock.py index 5a1633a..70ac65c 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/server_process_mock.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/server_process_mock.py
@@ -29,8 +29,12 @@ class MockServerProcess(object): - def __init__(self, port_obj=None, name=None, cmd=None, env=None, universal_newlines=False, - treat_no_data_as_crash=False, more_logging=False, lines=None, crashed=False): + def __init__(self, port_obj=None, name=None, cmd=None, env=None, + treat_no_data_as_crash=False, more_logging=False, lines=None, + crashed=False): + # port_obj and name are unused, but are maintained for compatibility + # with server_process.ServerProcess. + # pylint: disable=unused-argument self.timed_out = False self.lines = lines or ['#READY'] self.crashed = crashed
diff --git a/third_party/node/LICENSE b/third_party/node/LICENSE new file mode 100644 index 0000000..3a7260e --- /dev/null +++ b/third_party/node/LICENSE
@@ -0,0 +1,1192 @@ +Node.js is licensed for use as follows: + +""" +Copyright Node.js contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + +This license applies to parts of Node.js originating from the +https://github.com/joyent/node repository: + +""" +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + +The Node.js license applies to all parts of Node.js that are not externally +maintained libraries. + +The externally maintained libraries used by Node.js are: + +- c-ares, located at deps/cares, is licensed as follows: + """ + Copyright 1998 by the Massachusetts Institute of Technology. + Copyright (C) 2007-2013 by Daniel Stenberg + + Permission to use, copy, modify, and distribute this + software and its documentation for any purpose and without + fee is hereby granted, provided that the above copyright + notice appear in all copies and that both that copyright + notice and this permission notice appear in supporting + documentation, and that the name of M.I.T. not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + M.I.T. makes no representations about the suitability of + this software for any purpose. It is provided "as is" + without express or implied warranty. + """ + +- HTTP Parser, located at deps/http_parser, is licensed as follows: + """ + http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright + Igor Sysoev. + + Additional changes are licensed under the same terms as NGINX and + copyright Joyent, Inc. and other Node contributors. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to + deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. + """ + +- ICU, located at deps/icu-small, is licensed as follows: + """ + COPYRIGHT AND PERMISSION NOTICE (ICU 58 and later) + + Copyright © 1991-2016 Unicode, Inc. All rights reserved. + Distributed under the Terms of Use in http://www.unicode.org/copyright.html + + Permission is hereby granted, free of charge, to any person obtaining + a copy of the Unicode data files and any associated documentation + (the "Data Files") or Unicode software and any associated documentation + (the "Software") to deal in the Data Files or Software + without restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, and/or sell copies of + the Data Files or Software, and to permit persons to whom the Data Files + or Software are furnished to do so, provided that either + (a) this copyright and permission notice appear with all copies + of the Data Files or Software, or + (b) this copyright and permission notice appear in associated + Documentation. + + THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF + ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS + NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL + DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + PERFORMANCE OF THE DATA FILES OR SOFTWARE. + + Except as contained in this notice, the name of a copyright holder + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in these Data Files or Software without prior + written authorization of the copyright holder. + + --------------------- + + Third-Party Software Licenses + + This section contains third-party software notices and/or additional + terms for licensed third-party software components included within ICU + libraries. + + 1. ICU License - ICU 1.8.1 to ICU 57.1 + + COPYRIGHT AND PERMISSION NOTICE + + Copyright (c) 1995-2016 International Business Machines Corporation and others + All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, and/or sell copies of the Software, and to permit persons + to whom the Software is furnished to do so, provided that the above + copyright notice(s) and this permission notice appear in all copies of + the Software and that both the above copyright notice(s) and this + permission notice appear in supporting documentation. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT + OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY + SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER + RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + Except as contained in this notice, the name of a copyright holder + shall not be used in advertising or otherwise to promote the sale, use + or other dealings in this Software without prior written authorization + of the copyright holder. + + All trademarks and registered trademarks mentioned herein are the + property of their respective owners. + + 2. Chinese/Japanese Word Break Dictionary Data (cjdict.txt) + + # The Google Chrome software developed by Google is licensed under + # the BSD license. Other software included in this distribution is + # provided under other licenses, as set forth below. + # + # The BSD License + # http://opensource.org/licenses/bsd-license.php + # Copyright (C) 2006-2008, Google Inc. + # + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions are met: + # + # Redistributions of source code must retain the above copyright notice, + # this list of conditions and the following disclaimer. + # Redistributions in binary form must reproduce the above + # copyright notice, this list of conditions and the following + # disclaimer in the documentation and/or other materials provided with + # the distribution. + # Neither the name of Google Inc. nor the names of its + # contributors may be used to endorse or promote products derived from + # this software without specific prior written permission. + # + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + # + # + # The word list in cjdict.txt are generated by combining three word lists + # listed below with further processing for compound word breaking. The + # frequency is generated with an iterative training against Google web + # corpora. + # + # * Libtabe (Chinese) + # - https://sourceforge.net/project/?group_id=1519 + # - Its license terms and conditions are shown below. + # + # * IPADIC (Japanese) + # - http://chasen.aist-nara.ac.jp/chasen/distribution.html + # - Its license terms and conditions are shown below. + # + # ---------COPYING.libtabe ---- BEGIN-------------------- + # + # /* + # * Copyrighy (c) 1999 TaBE Project. + # * Copyright (c) 1999 Pai-Hsiang Hsiao. + # * All rights reserved. + # * + # * Redistribution and use in source and binary forms, with or without + # * modification, are permitted provided that the following conditions + # * are met: + # * + # * . Redistributions of source code must retain the above copyright + # * notice, this list of conditions and the following disclaimer. + # * . Redistributions in binary form must reproduce the above copyright + # * notice, this list of conditions and the following disclaimer in + # * the documentation and/or other materials provided with the + # * distribution. + # * . Neither the name of the TaBE Project nor the names of its + # * contributors may be used to endorse or promote products derived + # * from this software without specific prior written permission. + # * + # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + # * OF THE POSSIBILITY OF SUCH DAMAGE. + # */ + # + # /* + # * Copyright (c) 1999 Computer Systems and Communication Lab, + # * Institute of Information Science, Academia + # * Sinica. All rights reserved. + # * + # * Redistribution and use in source and binary forms, with or without + # * modification, are permitted provided that the following conditions + # * are met: + # * + # * . Redistributions of source code must retain the above copyright + # * notice, this list of conditions and the following disclaimer. + # * . Redistributions in binary form must reproduce the above copyright + # * notice, this list of conditions and the following disclaimer in + # * the documentation and/or other materials provided with the + # * distribution. + # * . Neither the name of the Computer Systems and Communication Lab + # * nor the names of its contributors may be used to endorse or + # * promote products derived from this software without specific + # * prior written permission. + # * + # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + # * OF THE POSSIBILITY OF SUCH DAMAGE. + # */ + # + # Copyright 1996 Chih-Hao Tsai @ Beckman Institute, + # University of Illinois + # c-tsai4@uiuc.edu http://casper.beckman.uiuc.edu/~c-tsai4 + # + # ---------------COPYING.libtabe-----END-------------------------------- + # + # + # ---------------COPYING.ipadic-----BEGIN------------------------------- + # + # Copyright 2000, 2001, 2002, 2003 Nara Institute of Science + # and Technology. All Rights Reserved. + # + # Use, reproduction, and distribution of this software is permitted. + # Any copy of this software, whether in its original form or modified, + # must include both the above copyright notice and the following + # paragraphs. + # + # Nara Institute of Science and Technology (NAIST), + # the copyright holders, disclaims all warranties with regard to this + # software, including all implied warranties of merchantability and + # fitness, in no event shall NAIST be liable for + # any special, indirect or consequential damages or any damages + # whatsoever resulting from loss of use, data or profits, whether in an + # action of contract, negligence or other tortuous action, arising out + # of or in connection with the use or performance of this software. + # + # A large portion of the dictionary entries + # originate from ICOT Free Software. The following conditions for ICOT + # Free Software applies to the current dictionary as well. + # + # Each User may also freely distribute the Program, whether in its + # original form or modified, to any third party or parties, PROVIDED + # that the provisions of Section 3 ("NO WARRANTY") will ALWAYS appear + # on, or be attached to, the Program, which is distributed substantially + # in the same form as set out herein and that such intended + # distribution, if actually made, will neither violate or otherwise + # contravene any of the laws and regulations of the countries having + # jurisdiction over the User or the intended distribution itself. + # + # NO WARRANTY + # + # The program was produced on an experimental basis in the course of the + # research and development conducted during the project and is provided + # to users as so produced on an experimental basis. Accordingly, the + # program is provided without any warranty whatsoever, whether express, + # implied, statutory or otherwise. The term "warranty" used herein + # includes, but is not limited to, any warranty of the quality, + # performance, merchantability and fitness for a particular purpose of + # the program and the nonexistence of any infringement or violation of + # any right of any third party. + # + # Each user of the program will agree and understand, and be deemed to + # have agreed and understood, that there is no warranty whatsoever for + # the program and, accordingly, the entire risk arising from or + # otherwise connected with the program is assumed by the user. + # + # Therefore, neither ICOT, the copyright holder, or any other + # organization that participated in or was otherwise related to the + # development of the program and their respective officials, directors, + # officers and other employees shall be held liable for any and all + # damages, including, without limitation, general, special, incidental + # and consequential damages, arising out of or otherwise in connection + # with the use or inability to use the program or any product, material + # or result produced or otherwise obtained by using the program, + # regardless of whether they have been advised of, or otherwise had + # knowledge of, the possibility of such damages at any time during the + # project or thereafter. Each user will be deemed to have agreed to the + # foregoing by his or her commencement of use of the program. The term + # "use" as used herein includes, but is not limited to, the use, + # modification, copying and distribution of the program and the + # production of secondary products from the program. + # + # In the case where the program, whether in its original form or + # modified, was distributed or delivered to or received by a user from + # any person, organization or entity other than ICOT, unless it makes or + # grants independently of ICOT any specific warranty to the user in + # writing, such person, organization or entity, will also be exempted + # from and not be held liable to the user for any such damages as noted + # above as far as the program is concerned. + # + # ---------------COPYING.ipadic-----END---------------------------------- + + 3. Lao Word Break Dictionary Data (laodict.txt) + + # Copyright (c) 2013 International Business Machines Corporation + # and others. All Rights Reserved. + # + # Project: http://code.google.com/p/lao-dictionary/ + # Dictionary: http://lao-dictionary.googlecode.com/git/Lao-Dictionary.txt + # License: http://lao-dictionary.googlecode.com/git/Lao-Dictionary-LICENSE.txt + # (copied below) + # + # This file is derived from the above dictionary, with slight + # modifications. + # ---------------------------------------------------------------------- + # Copyright (C) 2013 Brian Eugene Wilson, Robert Martin Campbell. + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, + # are permitted provided that the following conditions are met: + # + # + # Redistributions of source code must retain the above copyright notice, this + # list of conditions and the following disclaimer. Redistributions in + # binary form must reproduce the above copyright notice, this list of + # conditions and the following disclaimer in the documentation and/or + # other materials provided with the distribution. + # + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + # OF THE POSSIBILITY OF SUCH DAMAGE. + # -------------------------------------------------------------------------- + + 4. Burmese Word Break Dictionary Data (burmesedict.txt) + + # Copyright (c) 2014 International Business Machines Corporation + # and others. All Rights Reserved. + # + # This list is part of a project hosted at: + # github.com/kanyawtech/myanmar-karen-word-lists + # + # -------------------------------------------------------------------------- + # Copyright (c) 2013, LeRoy Benjamin Sharon + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions + # are met: Redistributions of source code must retain the above + # copyright notice, this list of conditions and the following + # disclaimer. Redistributions in binary form must reproduce the + # above copyright notice, this list of conditions and the following + # disclaimer in the documentation and/or other materials provided + # with the distribution. + # + # Neither the name Myanmar Karen Word Lists, nor the names of its + # contributors may be used to endorse or promote products derived + # from this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + # SUCH DAMAGE. + # -------------------------------------------------------------------------- + + 5. Time Zone Database + + ICU uses the public domain data and code derived from Time Zone + Database for its time zone support. The ownership of the TZ database + is explained in BCP 175: Procedure for Maintaining the Time Zone + Database section 7. + + # 7. Database Ownership + # + # The TZ database itself is not an IETF Contribution or an IETF + # document. Rather it is a pre-existing and regularly updated work + # that is in the public domain, and is intended to remain in the + # public domain. Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do + # not apply to the TZ Database or contributions that individuals make + # to it. Should any claims be made and substantiated against the TZ + # Database, the organization that is providing the IANA + # Considerations defined in this RFC, under the memorandum of + # understanding with the IETF, currently ICANN, may act in accordance + # with all competent court orders. No ownership claims will be made + # by ICANN or the IETF Trust on the database or the code. Any person + # making a contribution to the database or code waives all rights to + # future claims in that contribution or in the TZ Database. + """ + +- libuv, located at deps/uv, is licensed as follows: + """ + libuv is part of the Node project: http://nodejs.org/ + libuv may be distributed alone under Node's license: + + ==== + + Copyright Joyent, Inc. and other Node contributors. All rights reserved. + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to + deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. + + ==== + + This license applies to all parts of libuv that are not externally + maintained libraries. + + The externally maintained libraries used by libuv are: + + - tree.h (from FreeBSD), copyright Niels Provos. Two clause BSD license. + + - inet_pton and inet_ntop implementations, contained in src/inet.c, are + copyright the Internet Systems Consortium, Inc., and licensed under the ISC + license. + + - stdint-msvc2008.h (from msinttypes), copyright Alexander Chemeris. Three + clause BSD license. + + - pthread-fixes.h, pthread-fixes.c, copyright Google Inc. and Sony Mobile + Communications AB. Three clause BSD license. + + - android-ifaddrs.h, android-ifaddrs.c, copyright Berkeley Software Design + Inc, Kenneth MacKay and Emergya (Cloud4all, FP7/2007-2013, grant agreement + n° 289016). Three clause BSD license. + """ + +- OpenSSL, located at deps/openssl, is licensed as follows: + """ + Copyright (c) 1998-2016 The OpenSSL Project. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + 3. All advertising materials mentioning features or use of this + software must display the following acknowledgment: + "This product includes software developed by the OpenSSL Project + for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + + 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + endorse or promote products derived from this software without + prior written permission. For written permission, please contact + openssl-core@openssl.org. + + 5. Products derived from this software may not be called "OpenSSL" + nor may "OpenSSL" appear in their names without prior written + permission of the OpenSSL Project. + + 6. Redistributions of any form whatsoever must retain the following + acknowledgment: + "This product includes software developed by the OpenSSL Project + for use in the OpenSSL Toolkit (http://www.openssl.org/)" + + THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. + ==================================================================== + + This product includes cryptographic software written by Eric Young + (eay@cryptsoft.com). This product includes software written by Tim + Hudson (tjh@cryptsoft.com). + """ + +- Punycode.js, located at lib/punycode.js, is licensed as follows: + """ + Copyright Mathias Bynens <https://mathiasbynens.be/> + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + """ + +- V8, located at deps/v8, is licensed as follows: + """ + This license applies to all parts of V8 that are not externally + maintained libraries. The externally maintained libraries used by V8 + are: + + - PCRE test suite, located in + test/mjsunit/third_party/regexp-pcre/regexp-pcre.js. This is based on the + test suite from PCRE-7.3, which is copyrighted by the University + of Cambridge and Google, Inc. The copyright notice and license + are embedded in regexp-pcre.js. + + - Layout tests, located in test/mjsunit/third_party/object-keys. These are + based on layout tests from webkit.org which are copyrighted by + Apple Computer, Inc. and released under a 3-clause BSD license. + + - Strongtalk assembler, the basis of the files assembler-arm-inl.h, + assembler-arm.cc, assembler-arm.h, assembler-ia32-inl.h, + assembler-ia32.cc, assembler-ia32.h, assembler-x64-inl.h, + assembler-x64.cc, assembler-x64.h, assembler-mips-inl.h, + assembler-mips.cc, assembler-mips.h, assembler.cc and assembler.h. + This code is copyrighted by Sun Microsystems Inc. and released + under a 3-clause BSD license. + + - Valgrind client API header, located at third_party/valgrind/valgrind.h + This is release under the BSD license. + + These libraries have their own licenses; we recommend you read them, + as their terms may differ from the terms below. + + Further license information can be found in LICENSE files located in + sub-directories. + + Copyright 2014, the V8 project authors. All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + """ + +- zlib, located at deps/zlib, is licensed as follows: + """ + zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.8, April 28th, 2013 + + Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + """ + +- npm, located at deps/npm, is licensed as follows: + """ + The npm application + Copyright (c) npm, Inc. and Contributors + Licensed on the terms of The Artistic License 2.0 + + Node package dependencies of the npm application + Copyright (c) their respective copyright owners + Licensed on their respective license terms + + The npm public registry at https://registry.npmjs.org + and the npm website at https://www.npmjs.com + Operated by npm, Inc. + Use governed by terms published on https://www.npmjs.com + + "Node.js" + Trademark Joyent, Inc., https://joyent.com + Neither npm nor npm, Inc. are affiliated with Joyent, Inc. + + The Node.js application + Project of Node Foundation, https://nodejs.org + + The npm Logo + Copyright (c) Mathias Pettersson and Brian Hammond + + "Gubblebum Blocky" typeface + Copyright (c) Tjarda Koster, https://jelloween.deviantart.com + Used with permission + + -------- + + The Artistic License 2.0 + + Copyright (c) 2000-2006, The Perl Foundation. + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + This license establishes the terms under which a given free software + Package may be copied, modified, distributed, and/or redistributed. + The intent is that the Copyright Holder maintains some artistic + control over the development of that Package while still keeping the + Package available as open source and free software. + + You are always permitted to make arrangements wholly outside of this + license directly with the Copyright Holder of a given Package. If the + terms of this license do not permit the full use that you propose to + make of the Package, you should contact the Copyright Holder and seek + a different licensing arrangement. + + Definitions + + "Copyright Holder" means the individual(s) or organization(s) + named in the copyright notice for the entire Package. + + "Contributor" means any party that has contributed code or other + material to the Package, in accordance with the Copyright Holder's + procedures. + + "You" and "your" means any person who would like to copy, + distribute, or modify the Package. + + "Package" means the collection of files distributed by the + Copyright Holder, and derivatives of that collection and/or of + those files. A given Package may consist of either the Standard + Version, or a Modified Version. + + "Distribute" means providing a copy of the Package or making it + accessible to anyone else, or in the case of a company or + organization, to others outside of your company or organization. + + "Distributor Fee" means any fee that you charge for Distributing + this Package or providing support for this Package to another + party. It does not mean licensing fees. + + "Standard Version" refers to the Package if it has not been + modified, or has been modified only in ways explicitly requested + by the Copyright Holder. + + "Modified Version" means the Package, if it has been changed, and + such changes were not explicitly requested by the Copyright + Holder. + + "Original License" means this Artistic License as Distributed with + the Standard Version of the Package, in its current version or as + it may be modified by The Perl Foundation in the future. + + "Source" form means the source code, documentation source, and + configuration files for the Package. + + "Compiled" form means the compiled bytecode, object code, binary, + or any other form resulting from mechanical transformation or + translation of the Source form. + + Permission for Use and Modification Without Distribution + + (1) You are permitted to use the Standard Version and create and use + Modified Versions for any purpose without restriction, provided that + you do not Distribute the Modified Version. + + Permissions for Redistribution of the Standard Version + + (2) You may Distribute verbatim copies of the Source form of the + Standard Version of this Package in any medium without restriction, + either gratis or for a Distributor Fee, provided that you duplicate + all of the original copyright notices and associated disclaimers. At + your discretion, such verbatim copies may or may not include a + Compiled form of the Package. + + (3) You may apply any bug fixes, portability changes, and other + modifications made available from the Copyright Holder. The resulting + Package will still be considered the Standard Version, and as such + will be subject to the Original License. + + Distribution of Modified Versions of the Package as Source + + (4) You may Distribute your Modified Version as Source (either gratis + or for a Distributor Fee, and with or without a Compiled form of the + Modified Version) provided that you clearly document how it differs + from the Standard Version, including, but not limited to, documenting + any non-standard features, executables, or modules, and provided that + you do at least ONE of the following: + + (a) make the Modified Version available to the Copyright Holder + of the Standard Version, under the Original License, so that the + Copyright Holder may include your modifications in the Standard + Version. + + (b) ensure that installation of your Modified Version does not + prevent the user installing or running the Standard Version. In + addition, the Modified Version must bear a name that is different + from the name of the Standard Version. + + (c) allow anyone who receives a copy of the Modified Version to + make the Source form of the Modified Version available to others + under + + (i) the Original License or + + (ii) a license that permits the licensee to freely copy, + modify and redistribute the Modified Version using the same + licensing terms that apply to the copy that the licensee + received, and requires that the Source form of the Modified + Version, and of any works derived from it, be made freely + available in that license fees are prohibited but Distributor + Fees are allowed. + + Distribution of Compiled Forms of the Standard Version + or Modified Versions without the Source + + (5) You may Distribute Compiled forms of the Standard Version without + the Source, provided that you include complete instructions on how to + get the Source of the Standard Version. Such instructions must be + valid at the time of your distribution. If these instructions, at any + time while you are carrying out such distribution, become invalid, you + must provide new instructions on demand or cease further distribution. + If you provide valid instructions or cease distribution within thirty + days after you become aware that the instructions are invalid, then + you do not forfeit any of your rights under this license. + + (6) You may Distribute a Modified Version in Compiled form without + the Source, provided that you comply with Section 4 with respect to + the Source of the Modified Version. + + Aggregating or Linking the Package + + (7) You may aggregate the Package (either the Standard Version or + Modified Version) with other packages and Distribute the resulting + aggregation provided that you do not charge a licensing fee for the + Package. Distributor Fees are permitted, and licensing fees for other + components in the aggregation are permitted. The terms of this license + apply to the use and Distribution of the Standard or Modified Versions + as included in the aggregation. + + (8) You are permitted to link Modified and Standard Versions with + other works, to embed the Package in a larger work of your own, or to + build stand-alone binary or bytecode versions of applications that + include the Package, and Distribute the result without restriction, + provided the result does not expose a direct interface to the Package. + + Items That are Not Considered Part of a Modified Version + + (9) Works (including, but not limited to, modules and scripts) that + merely extend or make use of the Package, do not, by themselves, cause + the Package to be a Modified Version. In addition, such works are not + considered parts of the Package itself, and are not subject to the + terms of this license. + + General Provisions + + (10) Any use, modification, and distribution of the Standard or + Modified Versions is governed by this Artistic License. By using, + modifying or distributing the Package, you accept this license. Do not + use, modify, or distribute the Package, if you do not accept this + license. + + (11) If your Modified Version has been derived from a Modified + Version made by someone other than you, you are nevertheless required + to ensure that your Modified Version complies with the requirements of + this license. + + (12) This license does not grant you the right to use any trademark, + service mark, tradename, or logo of the Copyright Holder. + + (13) This license includes the non-exclusive, worldwide, + free-of-charge patent license to make, have made, use, offer to sell, + sell, import and otherwise transfer the Package with respect to any + patent claims licensable by the Copyright Holder that are necessarily + infringed by the Package. If you institute patent litigation + (including a cross-claim or counterclaim) against any party alleging + that the Package constitutes direct or contributory patent + infringement, then this Artistic License to you shall terminate on the + date that such litigation is filed. + + (14) Disclaimer of Warranty: + THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS + IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR + NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL + LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL + DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + -------- + """ + +- GYP, located at tools/gyp, is licensed as follows: + """ + Copyright (c) 2009 Google Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + """ + +- marked, located at tools/doc/node_modules/marked, is licensed as follows: + """ + Copyright (c) 2011-2014, Christopher Jeffrey (https://github.com/chjj/) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + """ + +- cpplint.py, located at tools/cpplint.py, is licensed as follows: + """ + Copyright (c) 2009 Google Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + """ + +- ESLint, located at tools/eslint, is licensed as follows: + """ + ESLint + Copyright jQuery Foundation and other contributors, https://jquery.org/ + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + """ + +- gtest, located at deps/gtest, is licensed as follows: + """ + Copyright 2008, Google Inc. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + """ + +- node-weak, located at test/gc/node_modules/weak, is licensed as follows: + """ + Copyright (c) 2011, Ben Noordhuis <info@bnoordhuis.nl> + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + """ + +- v8_inspector, located at deps/v8_inspector/third_party/v8_inspector, is licensed as follows: + """ + // Copyright 2015 The Chromium Authors. All rights reserved. + // + // Redistribution and use in source and binary forms, with or without + // modification, are permitted provided that the following conditions are + // met: + // + // * Redistributions of source code must retain the above copyright + // notice, this list of conditions and the following disclaimer. + // * Redistributions in binary form must reproduce the above + // copyright notice, this list of conditions and the following disclaimer + // in the documentation and/or other materials provided with the + // distribution. + // * Neither the name of Google Inc. nor the names of its + // contributors may be used to endorse or promote products derived from + // this software without specific prior written permission. + // + // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + """ + +- jinja2, located at deps/v8_inspector/third_party/jinja2, is licensed as follows: + """ + Copyright (c) 2009 by the Jinja Team, see AUTHORS for more details. + + Some rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + """ + +- markupsafe, located at deps/v8_inspector/third_party/markupsafe, is licensed as follows: + """ + Copyright (c) 2010 by Armin Ronacher and contributors. See AUTHORS + for more details. + + Some rights reserved. + + Redistribution and use in source and binary forms of the software as well + as documentation, with or without modification, are permitted provided + that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. + """
diff --git a/third_party/node/OWNERS b/third_party/node/OWNERS new file mode 100644 index 0000000..ca467ff7f --- /dev/null +++ b/third_party/node/OWNERS
@@ -0,0 +1,2 @@ +dbeam@chromium.org +dpapad@chromium.org
diff --git a/third_party/node/README.chromium b/third_party/node/README.chromium new file mode 100644 index 0000000..7f68e9e --- /dev/null +++ b/third_party/node/README.chromium
@@ -0,0 +1,17 @@ +Name: Node JS +Short Name: node +URL: https://github.com/nodejs/node +Version: 6.9.4 +Revision: f098f8295c407e5a5126b501ed5f1aa80bd86106 +Date: Tue Dec 06 2016 18:07:35 GMT-0800 (PST) +License: NodeJS +License File: NOT_SHIPPED +Security Critical: no + +Description: +Node binaries and NPM modules necessary for buliding Chrome's WebUI. +Use update_node_binaries to update Node binaries and update_npm_deps to +update NPM dependencies. + +Local Modifications: +No modifications.
diff --git a/third_party/node/linux/node-linux-x64.tar.gz.sha1 b/third_party/node/linux/node-linux-x64.tar.gz.sha1 new file mode 100644 index 0000000..68c1c85 --- /dev/null +++ b/third_party/node/linux/node-linux-x64.tar.gz.sha1
@@ -0,0 +1 @@ +eb63c12c3b19b96b9142e572c3c2cfaa27e13191
diff --git a/third_party/node/mac/node-darwin-x64.tar.gz.sha1 b/third_party/node/mac/node-darwin-x64.tar.gz.sha1 new file mode 100644 index 0000000..e98a8045 --- /dev/null +++ b/third_party/node/mac/node-darwin-x64.tar.gz.sha1
@@ -0,0 +1 @@ +b5ac19fd2f8afaa20f698972d2b0bb1056dc258a
diff --git a/third_party/node/node_modules.tar.gz.sha1 b/third_party/node/node_modules.tar.gz.sha1 new file mode 100644 index 0000000..d1b5761b --- /dev/null +++ b/third_party/node/node_modules.tar.gz.sha1
@@ -0,0 +1 @@ +ce62710ad9f651016248574ecd7b07e86dd01f2b
diff --git a/third_party/node/npm_exclude.txt b/third_party/node/npm_exclude.txt new file mode 100644 index 0000000..3a8e6fc --- /dev/null +++ b/third_party/node/npm_exclude.txt
@@ -0,0 +1,15 @@ +*/.* +*/example/ +*/examples/ +*.html +hydrolysis/hydrolysis.js +*/jsdoc2md/ +*.md +*.png +*.sh +*.svg +*/test/ +*.ts +*/@types/ +*.woff +*.yml
diff --git a/third_party/node/package.json b/third_party/node/package.json new file mode 100644 index 0000000..3558ae7 --- /dev/null +++ b/third_party/node/package.json
@@ -0,0 +1,11 @@ +{ + "name": "webui-node-modules", + "version": "1.0.0", + "author": "dpapad@chromium.org", + "dependencies": { + "crisper": "2.0.2", + "polymer-css-build": "0.0.7", + "uglifyjs": "2.4.10", + "vulcanize": "1.15.2" + } +}
diff --git a/third_party/node/update_node_binaries b/third_party/node/update_node_binaries new file mode 100755 index 0000000..d6d6512 --- /dev/null +++ b/third_party/node/update_node_binaries
@@ -0,0 +1,93 @@ +#!/bin/bash + +# Copyright 2017 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. + +# Script for updating Node binaries. +# 1) Update NODE_VERSION variable below to the desired version. +# 2) Run this script. +# 3) Upload the binaries to the Google Storage bucket (commands to upload +# binaries are printed at step 2, look for "gsutil.py"). +# 4) Land a CL with the changes generated by this script. + +set -eu +cd "$(dirname "$0")" + +BASE_URL="https://nodejs.org/dist" +NODE_VERSION="v6.9.4" + +update_unix() { + local SUFFIX="$1" + local FOLDER="$2" + local FILENAME="node-${NODE_VERSION}-${SUFFIX}.tar.gz" + local URL="${BASE_URL}/${NODE_VERSION}/${FILENAME}" + + rm -f "${FOLDER}/${FILENAME}" + wget -P "${FOLDER}/" "${URL}" + + # Check SHASUMS256 of downloaded binary. + local sha256_expected + sha256_expected="$(grep "$FILENAME" SHASUMS256.txt | cut -d ' ' -f1)" + local sha256_actual + sha256_actual="$(sha256sum "${FOLDER}/${FILENAME}" | cut -d ' ' -f1)" + + if [ "${sha256_expected}" != "${sha256_actual}" ]; then + echo "SHA256 mismatch. Exiting..." + exit 1 + fi + + # Unpack temporarily, delete NPM symlink and re-pack. + tar xfz "${FOLDER}/${FILENAME}" -C "${FOLDER}/" + rm "${FOLDER}/${FILENAME}" + rm "${FOLDER}/node-${NODE_VERSION}-${SUFFIX}/bin/npm" + + # Drop the version info from the name, since it is redundant and would make + # rolling new versions more involved. + rm -rf "${FOLDER}/node-${SUFFIX}/" + mv "${FOLDER}/node-${NODE_VERSION}-${SUFFIX}/" "${FOLDER}/node-${SUFFIX}/" + tar cfz "${FOLDER}/node-${SUFFIX}.tar.gz" -C "${FOLDER}" "node-${SUFFIX}/" + local sha1 + sha1="$(sha1sum ${FOLDER}/node-${SUFFIX}.tar.gz | cut -d ' ' -f1)" + echo "${sha1}" > "${FOLDER}/node-${SUFFIX}.tar.gz.sha1" + echo "Please execute manually the following:" + echo "> gsutil.py cp ${FOLDER}/node-${SUFFIX}.tar.gz gs://chromium-nodejs/${NODE_VERSION:1}/${sha1}" + echo "DONE updating for ${SUFFIX}." +} + +update_win() { + local FILENAME="node.exe" + local FOLDER="win" + local WINDOWS_URL="${BASE_URL}/${NODE_VERSION}/win-x64/${FILENAME}" + rm -f "${FOLDER}/${FILENAME}" + wget -P "${FOLDER}/" "${WINDOWS_URL}" + + # Check SHASUMS256 of downloaded binary. + local sha256_expected + sha256_expected="$(grep "win-x64/$FILENAME" SHASUMS256.txt | cut -d ' ' -f1)" + local sha256_actual + sha256_actual="$(sha256sum "${FOLDER}/${FILENAME}" | cut -d ' ' -f1)" + + if [ "${sha256_expected}" != "${sha256_actual}" ]; then + echo "SHA256 mismatch. Exiting..." + exit 1 + fi + + local sha1 + sha1="$(sha1sum ${FOLDER}/node.exe | cut -d ' ' -f1)" + echo "${sha1}" > "${FOLDER}/node.exe.sha1" + echo "Please execute manually the following:" + echo "> gsutil.py cp ${FOLDER}/node.exe gs://chromium-nodejs/${NODE_VERSION:1}/${sha1}" + echo "DONE updating Windows." +} + +# First download checksum file. +rm "SHASUMS256.txt" +wget "https://nodejs.org/dist/latest-v6.x/SHASUMS256.txt" + +update_unix "darwin-x64" "mac" +update_unix "linux-x64" "linux" +update_win + +# Update DEPS to point to the new Google Storage bucket subfolder. +sed -i "s@\(chromium-nodejs/\)\([0-9\.]\)\+@\1${NODE_VERSION:1}@" ../../DEPS
diff --git a/third_party/node/update_npm_deps b/third_party/node/update_npm_deps new file mode 100755 index 0000000..187d05d --- /dev/null +++ b/third_party/node/update_npm_deps
@@ -0,0 +1,38 @@ +#!/bin/bash + +# Copyright 2017 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. + +# Script for updating WebUI's NPM deps. +# 1) Update package.json file to point to the desired version. +# 2) Run this script. +# 3) Upload the compressed node_modules.tar.gz file to the Google Storage +# bucket (commands to upload binaries are printed at step 2). +# 4) Land a CL with the changes generated by this script. + +set -eu +cd "$(dirname "$0")" + +rm -rf node_modules + +npm install --no-bin-links --only=prod +rsync -c --delete -r -q --exclude-from="npm_exclude.txt" \ + --prune-empty-dirs "node_modules/" "node_modules_filtered/" + +echo -e "\n---------------------------------------------------------" +echo "Before filtering:" size: $(du -h node_modules/ | tail -n1 | cut -f1) ", files: " $(find node_modules/ -type f | wc -l) +rm -r node_modules +mv node_modules_filtered node_modules + +echo "After filtering:" size: $(du -h node_modules/ | tail -n1 | cut -f1) ", files: " $(find node_modules/ -type f | wc -l) + +tar cfz node_modules.tar.gz node_modules +echo "After compressing:" size: $(du -h node_modules.tar.gz | tail -n1 | cut -f1) + +sha1="$(sha1sum node_modules.tar.gz | cut -d ' ' -f1)" +echo "${sha1}" > node_modules.tar.gz.sha1 +echo "Please run the following manually to update Google Storage bucket:" +echo "> gsutil.py cp node_modules.tar.gz gs://chromium-nodejs/${sha1}" +echo "DONE" +echo -e "---------------------------------------------------------"
diff --git a/third_party/node/win/node.exe.sha1 b/third_party/node/win/node.exe.sha1 new file mode 100644 index 0000000..a30212e7 --- /dev/null +++ b/third_party/node/win/node.exe.sha1
@@ -0,0 +1 @@ +a5217c3b78a04dd8da80d4ee145577ea536a6cfc
diff --git a/ui/ozone/platform/drm/common/drm_util.cc b/ui/ozone/platform/drm/common/drm_util.cc index 0baf95e..fff21503 100644 --- a/ui/ozone/platform/drm/common/drm_util.cc +++ b/ui/ozone/platform/drm/common/drm_util.cc
@@ -52,7 +52,7 @@ DCHECK_GE(32, resources->count_crtcs); uint32_t best_crtc = 0; - int best_crtc_planes = 0; + int best_crtc_planes = -1; // Try to find an encoder for the connector. for (int i = 0; i < connector->count_encoders; ++i) {
diff --git a/ui/strings/ui_strings.grd b/ui/strings/ui_strings.grd index 643b007..3160c1c 100644 --- a/ui/strings/ui_strings.grd +++ b/ui/strings/ui_strings.grd
@@ -667,6 +667,9 @@ <message name="IDS_DISPLAY_TOUCH_CALIBRATION_HINT_SUBLABEL_TEXT" desc="Message to inform the user what the next step is in touch calibration is"> Tap the touch targets on your screen. </message> + <message name="IDS_DISPLAY_TOUCH_CALIBRATION_TAP_HERE_LABEL" desc="A message to notify the user about the significance of a circle on the screen during the touchscreen calibration."> + Tap here + </message> <!-- Display names --> <message name="IDS_DISPLAY_NAME_UNKNOWN" desc="The name used for a display whose name is unknown, which is shown in the display settings and ash tray.">